/* ============================================================ STORE / BACKEND — estado del negocio (abierto-cerrado + disponibilidad) Se guarda en este dispositivo (localStorage 'do_store'). El panel de administración permite al restaurante: · Forzar Abierto / Cerrado / Automático (por horario) · Marcar cada plato como disponible o agotado ============================================================ */ const { CATS: ST_CATS, FEATURE: ST_FEATURE, HOURS: ST_HOURS, ReservationsAdmin } = window; const DEFAULT_STORE = { mode: "auto", off: {} }; function loadStore() { try { const s = JSON.parse(localStorage.getItem("do_store") || "null"); if (s && typeof s === "object") return { mode: s.mode || "auto", off: s.off || {} }; } catch (e) {} return { ...DEFAULT_STORE }; } // ¿está abierto ahora? (override manual o por horario) function isStoreOpen(store) { if (store.mode === "open") return true; if (store.mode === "closed") return false; const now = new Date(); const h = now.getHours() + now.getMinutes() / 60; return h >= ST_HOURS.open && h < ST_HOURS.close; } function closedReason(store) { if (store.mode === "closed") return "Pedidos en pausa por el momento"; return "Abrimos " + ST_HOURS.days.toLowerCase() + " de " + ST_HOURS.label; } function itemAvailable(store, name) { return !(store.off && store.off[name]); } // catálogo plano (incluye el plato estrella) function allItems() { const out = []; ST_CATS.forEach(c => c.items.forEach(it => out.push({ item: it, cat: c }))); const fcat = ST_CATS.find(c => c.id === ST_FEATURE.catId); out.push({ item: ST_FEATURE, cat: fcat }); return out; } function findItem(name) { return allItems().find(x => x.item.n === name) || null; } /* ---- Interruptor ---- */ function Switch({ on, onChange }) { return ( ); } /* ---- Panel de administración ---- */ function AdminPanel({ store, setStore, onClose }) { const [q, setQ] = useState(""); const [tab, setTab] = useState("carta"); useEffect(() => { document.body.style.overflow = "hidden"; const esc = (e) => e.key === "Escape" && onClose(); window.addEventListener("keydown", esc); return () => { document.body.style.overflow = ""; window.removeEventListener("keydown", esc); }; }, []); const open = isStoreOpen(store); const setMode = (mode) => setStore(s => ({ ...s, mode })); const toggleItem = (name) => setStore(s => { const off = { ...s.off }; if (off[name]) delete off[name]; else off[name] = true; return { ...s, off }; }); const offCount = Object.keys(store.off || {}).length; const cats = ST_CATS.map(c => ({ ...c, items: c.items.filter(it => it.n.toLowerCase().includes(q.toLowerCase())), })).filter(c => c.items.length); return (
e.stopPropagation()}>
Panel del restaurante

{tab === "carta" ? "Gestiona tu carta" : "Gestiona tus reservas"}

{tab === "reservas" ? (
) : (
{open ? "Recibiendo pedidos" : "Pedidos bloqueados"} {store.mode === "auto" ? "Automático según horario · " + ST_HOURS.label : store.mode === "open" ? "Forzado: Abierto" : "Forzado: Cerrado"}
Disponibilidad de platos {offCount > 0 ? offCount + " agotado(s)" : "Todo disponible"}
setQ(sanitizeBase(e.target.value, 40))} placeholder="Buscar plato…" />
{cats.map(c => (
{c.name} {c.items.map(it => { const av = itemAvailable(store, it.n); return (
{it.n}{!av && · agotado} toggleItem(it.n)} />
); })}
))}
)}
); } Object.assign(window, { loadStore, isStoreOpen, closedReason, itemAvailable, allItems, findItem, Switch, AdminPanel, });