import { useRef, useState } from 'react' function fmtPrice(v) { return Number(v).toFixed(2) + ' €' } // ── Icons ───────────────────────────────────────────────────────────────────── function SectionIcon({ type }) { const icons = { prefs: , quick: , extras: , removed: , note: , } return {icons[type] ?? null} } // ── Parse selected_options into grouped sections (same logic as cart) ──────── function buildSections(item) { const sections = [] const opts = (() => { try { return item.selected_options ? JSON.parse(item.selected_options) : [] } catch { return [] } })() const removed = (() => { try { return item.removed_ingredients ? JSON.parse(item.removed_ingredients) : [] } catch { return [] } })() // We don't have product metadata here, so we classify by heuristics: // - id != null → could be a pref choice or extra; we use the _type hint if present, else we group them // - id == null → sub-choice (follows its parent) // Strategy: walk through opts in order, attaching sub-choices to their parent, // then classify parent items: items with a real id that appear multiple times → extra (stacked), // but without product metadata we can't fully distinguish prefs from extras. // We use a simple rule: if an option with id appears only once in the stream → treat as pref // (since extras can be added multiple times). This matches how handleAdd() emits them. const prefGroups = [] // { setName: null (unknown), values: [...] } const extraGroups = [] // { id, name, subName, qty } const quickLines = [] // { name, _qty } // Count how many times each id appears (extras can be stacked → appear multiple times) const idCount = {} opts.forEach(o => { if (o.id != null) idCount[o.id] = (idCount[o.id] || 0) + 1 }) // Single pass: consume each item and its optional following sub (id=null) const consumedAsSubAtIndex = new Set() let i = 0 while (i < opts.length) { const o = opts[i] if (consumedAsSubAtIndex.has(i)) { i++; continue } if (o.id == null) { // Standalone id=null → quick option const existing = quickLines.find(x => x.name === o.name) if (existing) existing._qty = (existing._qty || 1) + 1 else quickLines.push({ name: o.name, _qty: 1 }) i++ continue } // id != null — look ahead for immediate sub let subName = null if (i + 1 < opts.length && opts[i + 1].id == null) { subName = opts[i + 1].name consumedAsSubAtIndex.add(i + 1) } if (idCount[o.id] > 1) { // Extra — appears multiple times in the list const existing = extraGroups.find(g => g.id === o.id && g.subName === subName) if (existing) existing.qty++ else extraGroups.push({ id: o.id, name: o.name, subName, qty: 1 }) } else { // Single occurrence → preference choice const value = subName ? `${o.name} · ${subName}` : o.name prefGroups.push({ setName: null, values: [value] }) } i++ } if (prefGroups.length > 0) sections.push({ type: 'prefs', lines: prefGroups }) if (quickLines.length > 0) sections.push({ type: 'quick', lines: quickLines }) if (extraGroups.length > 0) sections.push({ type: 'extras', lines: extraGroups }) if (removed.length > 0) sections.push({ type: 'removed', lines: removed.map(n => ({ name: n })) }) if (item.notes) sections.push({ type: 'note', lines: [{ name: item.notes }] }) return sections } // ── ItemRow ─────────────────────────────────────────────────────────────────── function ItemRow({ item, selectable, selected, onToggle, onLongPress, isLast }) { const isPaid = item.status === 'paid' const isCancelled = item.status === 'cancelled' const sections = buildSections(item) const hasDetails = sections.length > 0 const [expanded, setExpanded] = useState(false) // Long-press detection const pressTimer = useRef(null) const didLongPress = useRef(false) const touchStartPos = useRef({ x: 0, y: 0 }) function handleTouchStart(e) { if (!selectable || isPaid || isCancelled || !onLongPress) return didLongPress.current = false touchStartPos.current = { x: e.touches[0].clientX, y: e.touches[0].clientY } pressTimer.current = setTimeout(() => { didLongPress.current = true onLongPress(item) }, 500) } function handleTouchMove(e) { const dx = Math.abs(e.touches[0].clientX - touchStartPos.current.x) const dy = Math.abs(e.touches[0].clientY - touchStartPos.current.y) if (dx > 8 || dy > 8) clearTimeout(pressTimer.current) } function handleTouchEnd() { clearTimeout(pressTimer.current) } function handleBodyClick() { if (didLongPress.current) { didLongPress.current = false; return } if (selectable && !isPaid && !isCancelled) onToggle(item.id) } return (
{/* Main row — click to select */}
{/* Selection checkbox */} {selectable && !isPaid && !isCancelled && ( {selected ? '☑' : '☐'} )} {/* Name + badges */}
{item.product?.name || `#${item.product_id}`} {isPaid && Paid} {isCancelled && Cancelled} {!isPaid && !isCancelled && !item.printed && ( )}
{/* Qty + price */} ×{item.quantity} {fmtPrice(item.unit_price * item.quantity)} {/* Expand arrow — only if there are details; stops propagation so it doesn't trigger select */} {hasDetails && ( )}
{/* Expanded details */} {expanded && hasDetails && (
{sections.map((sec, si) => (
{sec.type === 'prefs' && sec.lines.map((line, li) => (
{line.setName && ( {line.setName} )} {line.values.join(' · ')}
))} {sec.type === 'quick' && sec.lines.map((line, li) => (
{line.name} {line._qty > 1 && ×{line._qty}}
))} {sec.type === 'extras' && sec.lines.map((line, li) => (
{line.name} {line.subName && · {line.subName}} {line.qty > 1 && ×{line.qty}}
))} {sec.type === 'removed' && sec.lines.map((line, li) => (
Χωρίς {line.name}
))} {sec.type === 'note' && sec.lines.map((line, li) => (
{line.name}
))}
))}
)}
) } export default function OrderSummary({ order, selectable = false, selectedIds = [], onToggle, onLongPressItem }) { const activeItems = order.items?.filter(i => i.status !== 'cancelled') || [] const total = activeItems .filter(i => i.status !== 'cancelled') .reduce((s, i) => s + i.unit_price * i.quantity, 0) const paidTotal = activeItems .filter(i => i.status === 'paid') .reduce((s, i) => s + i.unit_price * i.quantity, 0) return (
{activeItems.length === 0 &&

Δεν υπάρχουν αντικείμενα

} {activeItems.map((item, idx) => ( ))}
Σύνολο {fmtPrice(total)}
{paidTotal > 0 && paidTotal < total && (
Πληρωμένο {fmtPrice(paidTotal)}
)} {paidTotal > 0 && paidTotal < total && (
Εκκρεμεί {fmtPrice(total - paidTotal)}
)}
) }