// Order drawer — add/customize a product before sending to the kitchen. // Mobile-portrait, ~90% height bottom sheet with horizontal tabs. const { DIAVOLA } = window; // --- utils ----------------------------------------------------------------- const fmt = (n) => { const sign = n < 0 ? '−' : ''; return sign + '€' + Math.abs(n).toFixed(2); }; const fmtSigned = (n) => (n >= 0 ? '+' : '−') + '€' + Math.abs(n).toFixed(2); // --- stepper (big touch) --------------------------------------------------- function Stepper({ value, onChange, min = 0, max = 99, size = 'md' }) { const sizes = { md: { btn: 40, font: 18, w: 108 }, lg: { btn: 48, font: 22, w: 132 }, }; const s = sizes[size]; return (
e.stopPropagation()}>
{value}
); } // --- checkmark icon -------------------------------------------------------- function Check({ size = 18 }) { return ( ); } function Chevron({ open, size = 16 }) { return ( ); } // --- Row primitive (shared look across tabs) ------------------------------- function Row({ selected, onClick, left, right, children }) { return (
{left &&
{left}
}
{children}
{right &&
{right}
}
); } // --- Checkbox circle (selected / not) -------------------------------------- function CheckCircle({ selected, size = 26 }) { return (
{selected && }
); } // --- Radio dot ------------------------------------------------------------- function RadioDot({ selected, size = 22 }) { return (
{selected && (
)}
); } // =========================================================================== // QUICK OPTIONS TAB // =========================================================================== function QuickOptionsTab({ options, state, setState }) { return (
{options.map(opt => { const qty = state[opt.id] || 0; const selected = qty > 0; return ( setState({ ...state, [opt.id]: selected ? 0 : 1 })} left={!opt.multi && } right={ opt.multi ? ( selected ? ( setState({ ...state, [opt.id]: v })} /> ) : ( ) ) : null } >
{opt.label}
{opt.price > 0 && (
+€{opt.price.toFixed(2)} {opt.multi ? 'each' : ''}
)}
); })}
); } // =========================================================================== // EXTRAS TAB — each row expands inline to pick a sub-option // =========================================================================== function ExtrasTab({ extras, state, setState, expandedId, setExpandedId }) { return (
{extras.map(ex => { const selection = state[ex.id]; // { qty, subId } | undefined const selected = !!selection; const open = expandedId === ex.id; const subLabel = selection ? ex.subOptions.find(s => s.id === selection.subId)?.label : null; const toggle = () => { if (selected) { setState({ ...state, [ex.id]: undefined }); if (open) setExpandedId(null); } else { // default to first sub-option, auto-expand so user can change it setState({ ...state, [ex.id]: { qty: 1, subId: ex.subOptions[0].id } }); setExpandedId(ex.id); } }; return (
} right={ selected ? (
e.stopPropagation()}> {ex.multi && ( setState({ ...state, [ex.id]: v === 0 ? undefined : { ...selection, qty: v } })} /> )}
) : null } >
{ex.label}
{ex.price > 0 ? `+€${ex.price.toFixed(2)}${ex.multi ? ' each' : ''}` : 'Included'} {subLabel && · {subLabel}}
{/* Inline sub-option picker */} {selected && open && (
{ex.subLabel}
{ex.subOptions.map(sub => { const isSel = selection.subId === sub.id; return ( setState({ ...state, [ex.id]: { ...selection, subId: sub.id } })} left={} >
{sub.label}
{sub.price > 0 && (
+€{sub.price.toFixed(2)}
)}
); })}
)}
); })}
); } // =========================================================================== // INGREDIENTS TAB — remove only // =========================================================================== function IngredientsTab({ ingredients, state, setState }) { return (
Tap to remove ingredients from this item.
{ingredients.map(ing => { const removed = !!state[ing.id]; return ( setState({ ...state, [ing.id]: !removed })} right={
{removed ? 'Removed' : 'Remove'}
} >
{ing.label}
); })}
); } // =========================================================================== // PREFERENCES TAB — radio groups // =========================================================================== function PreferencesTab({ preferences, state, setState }) { return (
{preferences.map(pref => { const selected = state[pref.id]; return (
{pref.label}
{pref.required && (
Required
)}
{pref.subOptions.map(sub => { const isSel = selected === sub.id; return ( setState({ ...state, [pref.id]: sub.id })} left={} right={ sub.price !== 0 ? (
{fmtSigned(sub.price)}
) : null } >
{sub.label}
); })}
); })}
); } // =========================================================================== // NOTES TAB // =========================================================================== const QUICK_NOTES = ['No eye contact 😅', 'Table is in a hurry', 'Customer is allergic', 'Cut in smaller pieces', 'Leave box open']; function NotesTab({ note, setNote }) { return (
Anything specific for the kitchen. Short and clear works best.