/* Banyan Pharmacy — app shell, routing, chrome, the guided loop */ const { useState, useEffect, useRef, useMemo, createContext, useContext } = React; const D = window.DATA; const { cx, Icons, Glyph, TerraceLogo, Avatar, Drawer, useClickOutside } = window; const AppCtx = createContext(null); window.AppCtx = AppCtx; const useApp = () => useContext(AppCtx); window.useApp = useApp; const SETTLED = 99; // settled (normal browsing) stage — everything flipped /* shelf-health of a store at a given loop stage (Gariahat & Mukundapur rewind) */ function storeStatusAt(store, stage) { if (store.loopStore === "gariahat") return stage < 1 ? "watch" : "atrisk"; if (store.loopStore === "mukundapur") return stage < 4 ? "watch" : "critical"; return store.status; } window.storeStatusAt = storeStatusAt; /* alerts visible at a given stage, sorted by urgency */ function alertsAt(stage) { return D.alerts.filter((a) => stage >= a.loopStage).sort((a, b) => a.sort - b.sort); } window.alertsAt = alertsAt; /* ============ Chrome ============ */ function Header() { const app = useApp(); const [menu, setMenu] = useState(false); const ref = useRef(); useClickOutside(ref, () => setMenu(false)); return (
app.nav({ name: "today" })} aria-label="Terrace">
{menu && (
{D.SESSION.name}
{D.SESSION.email}
)}
); } const NAV = [ { name: "today", label: "Dashboard" }, { name: "stores", label: "Stores" }, { name: "suppliers", label: "Suppliers" }, { name: "alerts", label: "Alerts" }, { name: "pilots", label: "Pilots" }, ]; function Nav() { const app = useApp(); const cur = app.route.name === "store" ? "stores" : app.route.name === "supplier" ? "suppliers" : app.route.name; const alertCount = alertsAt(app.stage).length; return ( ); } /* ============ The Field, docked (the "same event, both levels" moment) ===== */ if (!document.getElementById("field-dock-css")) { const _fds = document.createElement("style"); _fds.id = "field-dock-css"; _fds.textContent = ` .field-dock { position: fixed; right: 22px; bottom: 116px; z-index: 60; width: 272px; display: flex; flex-direction: column; gap: 0; animation: fd-in 420ms cubic-bezier(0.2, 0, 0, 1); } @keyframes fd-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } } .field-dock .fd-head { display: flex; align-items: center; gap: 8px; padding: 0 4px 7px; } .field-dock .fd-lbl { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.16em; color: var(--mute); } .field-dock .fd-dot { width: 6px; height: 6px; border-radius: 999px; background: var(--clay); flex-shrink: 0; } .field-dock .fd-x { margin-left: auto; width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center; background: transparent; border: 0; color: var(--mute); cursor: pointer; font-size: 15px; line-height: 1; border-radius: 4px; } .field-dock .fd-x:hover { color: var(--ink); background: var(--stone-deep); } .field-dock iframe { width: 272px; height: 583px; border: 0; display: block; background: transparent; filter: drop-shadow(0 24px 50px rgba(26,26,26,0.35)); } @media (max-height: 820px) { .field-dock iframe { height: 56vh; width: calc(56vh * 0.4667); } .field-dock { width: auto; } } @media (max-width: 900px) { .field-dock { display: none; } }`; document.head.appendChild(_fds); } function FieldDock() { const app = useApp(); const dock = app.loopActive ? D.LOOP[app.loopIdx].dock : null; const [hiddenFor, setHiddenFor] = useState(null); if (!dock) return null; const key = dock.thread + "·" + dock.state; if (hiddenFor === key) return null; return (
The Field · live
); } /* ============ The guided loop ============ */ function LoopBar() { const app = useApp(); if (!app.loopActive) { return ( ); } const step = D.LOOP[app.loopIdx]; const last = app.loopIdx === D.LOOP.length - 1; return (
{D.LOOP.map((_, i) => )}
{String(app.loopIdx + 1).padStart(2, "0")} / {String(D.LOOP.length).padStart(2, "0")}{step.kicker}
{step.title}
{step.body}
{step.field && ( Open Field )} {last ? : }
); } /* ============ App ============ */ function App() { const [route, setRoute] = useState({ name: "today" }); const [loopActive, setLoopActive] = useState(false); const [loopIdx, setLoopIdx] = useState(0); const stage = loopActive ? D.LOOP[loopIdx].stage : SETTLED; const loopFocus = loopActive ? D.LOOP[loopIdx].focus : null; const goToStep = (idx) => { const step = D.LOOP[idx]; setLoopIdx(idx); setRoute(step.route); window.scrollTo({ top: 0, behavior: "smooth" }); }; const app = { route, stage, loopActive, loopIdx, loopFocus, nav: (r) => { setRoute(r); window.scrollTo(0, 0); }, startLoop: () => { setLoopActive(true); setLoopIdx(0); setRoute(D.LOOP[0].route); window.scrollTo(0, 0); }, stopLoop: () => { setLoopActive(false); setRoute({ name: "today" }); window.scrollTo(0, 0); }, loopNext: () => goToStep(Math.min(loopIdx + 1, D.LOOP.length - 1)), loopPrev: () => goToStep(Math.max(loopIdx - 1, 0)), }; const Page = { today: window.Pages.Today, stores: window.Pages.Stores, store: window.Pages.StoreDetail, suppliers: window.Pages.Suppliers, supplier: window.Pages.SupplierDetail, alerts: window.Pages.Alerts, pilots: window.Pages.Pilots, }[route.name] || window.Pages.Today; return (
); } window.__mountApp = () => ReactDOM.createRoot(document.getElementById("root")).render();