import { useMemo } from "react"; import { OverlayTrigger, Tooltip } from "react-bootstrap"; import SelectSearch, { SelectedOptionValue, SelectSearchOption } from "react-select-search"; import { StoreMenuDish } from "../../../types"; import { countNoteItems, matchNoteToMenu, noteItemQuantity, splitNoteItems } from "../utils/menuMatch"; import { useGroupLimits } from "../hooks/useGroupLimits"; import "./MenuHintCell.scss"; type Props = { /** Celá nabídka podniku (stažená z Bolt Food/Wolt), undefined = načítá se / není */ menu?: StoreMenuDish[], note?: string, /** Zadaná částka člena v haléřích */ amount?: number, canEdit: boolean, onPick: (dish: StoreMenuDish) => void, onUsePrice: (priceKc: number) => void, /** Odebere jeden kus položky poznámky na daném indexu (a odečte její cenu) */ onRemoveItem: (index: number) => void, }; const formatDish = (d: StoreMenuDish) => d.price != null ? `${d.name} (${d.price} Kč)` : d.name; /** * Buňka „Z nabídky" ve skupinové objednávce: výběr položky ze stažené nabídky podniku * (doplní poznámku i částku) a kontrola ceny rozpoznané z poznámky proti zadané částce. */ export default function MenuHintCell({ menu, note, amount, canEdit, onPick, onUsePrice, onRemoveItem }: Readonly) { const { maxItemQuantity, maxItems } = useGroupLimits(); const options = useMemo(() => { if (!menu?.length) return []; const groups = new Map(); menu.forEach((d, index) => { const category = d.category || 'Ostatní'; if (!groups.has(category)) groups.set(category, []); // Jídlo, kterého už je v objednávce maximum kusů, nejde přidat znovu const atLimit = noteItemQuantity(note, d.name, menu) >= maxItemQuantity; groups.get(category)!.push({ name: atLimit ? `${formatDish(d)} — max ${maxItemQuantity} ks` : formatDish(d), value: String(index), disabled: atLimit }); }); return [...groups.entries()].map(([name, items]) => ({ name, type: 'group', items })); }, [menu, note, maxItemQuantity]); const itemLimitReached = useMemo(() => countNoteItems(note, menu ?? []) >= maxItems, [note, menu, maxItems]); const match = useMemo(() => menu ? matchNoteToMenu(note, menu) : undefined, [menu, note]); const items = useMemo(() => splitNoteItems(note, menu), [note, menu]); if (!menu?.length) { return —; } const menuPrice = match?.total; const differs = menuPrice != null && amount != null && Math.round(menuPrice * 100) !== amount; const unmatched = match?.parts.filter(p => !p.dish).map(p => p.text) ?? []; return (
{canEdit && itemLimitReached && ( Dosažen limit {maxItems} položek — nejdřív něco odeber (×). )} {canEdit && !itemLimitReached && ( { }} onFocus={() => { }} onChange={(value: SelectedOptionValue | SelectedOptionValue[]) => { const dish = menu[Number(value)]; if (dish) onPick(dish); }} /> )} {canEdit && items.length > 0 && (
{items.map((text, i) => { // Rozpoznaná položka ze stejného rozdělení poznámky — kvůli ceně na čipu const part = match && match.parts.length === items.length ? match.parts[i] : undefined; const price = part?.dish?.price; const quantity = part?.quantity ?? 1; return ( {text}{price != null && {quantity > 1 ? `${quantity}× ${price} = ${quantity * price}` : price} Kč} ); })}
)} {match && ( {match.parts.map((p, i) => (
{p.dish ? `${p.quantity > 1 ? `${p.quantity}× ` : ''}${formatDish(p.dish)}` : `„${p.text}" — v nabídce nenalezeno`}
))} } > {menuPrice != null ? <>Dle nabídky: {menuPrice} Kč : <>Nalezeno {match.parts.length - unmatched.length}/{match.parts.length} položek} {differs && canEdit && ( )}
)}
); }