supersam/src/components/client/OrderCompositionPanel.jsx

143 lines
5.4 KiB
JavaScript

import React from "react";
import { Badge } from "../UI/Badge";
import { Button } from "../UI/Button";
import { Panel } from "../UI/Panel";
import { getInvitationReferenceLabel } from "./invitationReference";
import { supabase } from "../../supabaseClient";
import { matchesStopWord } from "../../hooks/useStopWords";
const flattenOrderProducts = (rawItems) => {
if (!Array.isArray(rawItems) || rawItems.length === 0) return [];
const products = [];
for (const item of rawItems) {
if (!item || typeof item !== "object") continue;
const subItems = Array.isArray(item.items) ? item.items : [];
if (subItems.length > 0) {
const hasSubOrders = subItems.some(
(s) => typeof s === "object" && ("nom" in s || ("items" in s && Array.isArray(s.items))),
);
if (hasSubOrders) {
for (const sub of subItems) {
if (!sub || typeof sub !== "object") continue;
const productsList = Array.isArray(sub.items) ? sub.items : [];
for (const p of productsList) {
if (!p || typeof p !== "object") continue;
const pName = String(p.product_name || p.name || "").trim();
if (!pName) continue;
products.push({
name: pName,
quantity: String(p.product_quantity || p.quantity || p.count || p.amount || "").trim(),
unit: String(p.product_ed || p.unit || "").trim(),
_sourceOrder: sub,
});
}
}
} else {
for (const p of subItems) {
if (!p || typeof p !== "object") continue;
const pName = String(p.product_name || p.name || "").trim();
if (!pName) continue;
products.push({
name: pName,
quantity: String(p.product_quantity || p.quantity || p.count || p.amount || "").trim(),
unit: String(p.product_ed || p.unit || "").trim(),
_sourceOrder: item,
});
}
}
continue;
}
const name = String(item.product_name || item.name || item.nom || "").trim();
if (!name) continue;
products.push({
name,
quantity: String(item.product_quantity || item.quantity || item.count || item.amount || "").trim(),
unit: String(item.product_ed || item.unit || "").trim(),
_sourceOrder: item,
});
}
return products;
};
export const OrderCompositionPanel = ({ invitation = {} }) => {
const [stopWords, setStopWords] = React.useState([]);
const [stopWordsLoaded, setStopWordsLoaded] = React.useState(false);
const [scopeActive, setScopeActive] = React.useState(true);
React.useEffect(() => {
if (!supabase) { setStopWordsLoaded(true); return; }
Promise.all([
supabase.from("stop_words").select("word"),
supabase.from("stop_words_scope").select("scope").eq("id", 1).single(),
]).then(([{ data: wordsData }, { data: scopeData }]) => {
if (wordsData) setStopWords(wordsData.map((d) => d.word));
setScopeActive(scopeData?.scope === "everywhere" || scopeData?.scope === "client_only");
setStopWordsLoaded(true);
})
.catch(() => setStopWordsLoaded(true));
}, []);
const rawItems = invitation.orderItems || invitation.items || [];
const allProducts = flattenOrderProducts(rawItems);
const products = (stopWords.length && scopeActive)
? allProducts.filter((p) => !matchesStopWord(p.name, stopWords))
: allProducts;
const filteredCount = allProducts.length - products.length;
const reference = getInvitationReferenceLabel(invitation);
const [isExpanded, setIsExpanded] = React.useState(false);
// Hide the entire panel if there are no products to show and some were filtered
if (products.length === 0 && filteredCount > 0) return null;
if (products.length === 0 && filteredCount === 0) return null;
return (
<Panel className="space-y-3 border shadow-soft p-5 sm:p-6">
<Button
variant="ghost"
className="flex w-full items-center justify-between text-left"
onClick={() => setIsExpanded(!isExpanded)}
>
<p className="text-sm uppercase tracking-[0.18em] text-[var(--color-text-muted)]">
Состав заказа{reference && reference !== "Счет —" ? ` ${reference}` : ""}
</p>
<span className="flex items-center gap-2 text-sm text-[var(--color-text-muted)]">
{products.length} поз.
<svg
className="h-4 w-4 transition-transform"
style={{ transform: isExpanded ? "rotate(180deg)" : "rotate(0deg)" }}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
</svg>
</span>
</Button>
{isExpanded && (
<div className="space-y-2">
{products.map((product, idx) => (
<div
key={`${product.name}-${idx}`}
className="flex items-center justify-between gap-3 rounded-[18px] border border-[var(--color-border)] bg-[var(--color-surface-strong)] px-4 py-3 text-sm"
>
<span className="leading-6">{product.name}</span>
{(product.quantity || product.unit) ? (
<Badge tone="neutral">{[product.quantity, product.unit].filter(Boolean).join(" ")}</Badge>
) : null}
</div>
))}
</div>
)}
</Panel>
);
};