/* ============================================================= CoreIQ Office — Stores, transfers, reports, admin ============================================================= */ const { useState: oxUseState, useMemo: oxUseMemo } = React; // ================================================================= // STORES (list & detail) // ================================================================= function Stores() { const { setScreen, setScope, setScreenState, pushToast } = window.useOffice(); return (
Multi-store

Stores

s + st.patients, 0).toLocaleString()} delta={{dir: "up", text: "+182 this month"}}/> s + st.takings.mtd, 0))} delta={{dir: "up", text: "▲ 11.2% YoY"}}/> s + st.stockValue, 0))} delta={{text: "Ex-GST · at cost"}}/>
Code
Store
Manager
Registers
Patients
Today
MTD
Stock value
Open
{OD.STORES.map(s => (
{s.code}
{s.name}
{s.address}
{s.manager}
{s.registers}
{s.patients.toLocaleString()}
{oMoney(s.takings.today)}
{oMoney(s.takings.mtd)}
{oMoney(s.stockValue)}
))}
Compare · MTD takings
{OD.REVENUE_30D["S-001"].map((_, i) => { const a = OD.REVENUE_30D["S-001"][i]; const b = OD.REVENUE_30D["S-002"][i]; const c = OD.REVENUE_30D["S-003"][i]; const max = 6500; return (
); })}
Camberwell Glen Iris Ringwood
); } function StoreDetail() { const { setScreen, screenState } = window.useOffice(); const s = findS(screenState.activeStoreId) || OD.STORES[0]; const stock = OD.STOCK[s.id] || {}; const stockedSkus = Object.keys(stock).length; const stockValue = Object.entries(stock).reduce((acc, [pid, v]) => acc + (v.onHand * (findP(pid)?.cost || 0)), 0); const lowStock = Object.entries(stock).filter(([pid, v]) => v.onHand <= v.min && v.min > 0).length; const STORE_COLOURS = { "S-001": "var(--teal-700)", "S-002": "var(--navy-600)", "S-003": "var(--violet-600)" }; return (
Store · {s.code}

{s.name}

{s.code}
{s.name}
{s.address} · {s.phone}
{s.type === "flagship" ? "Flagship" : s.type === "suburban" ? "Suburban" : "Regional"} {s.registers} registers Open · {s.hours.split("·")[0]} Manager · {s.manager} Opened {s.openedOn}

Revenue · last 30 days

{oMoney(s.takings.mtd)} MTD
{OD.REVENUE_30D[s.id].map((v, i) => (
))}
Top movers · 30d
{OD.PRODUCTS.slice(0, 6).map((p, i) => (
{p.name} {Math.max(20, 180 - i * 18)} units
))}
); } // ================================================================= // TRANSFERS // ================================================================= function Transfers() { const { pushToast } = window.useOffice(); const [filter, setFilter] = oxUseState("all"); const [creating, setCreating] = oxUseState(false); const FILTERS = [ { key: "all", label: "All", pred: () => true }, { key: "pending", label: "Pending", pred: t => t.status === "pending" }, { key: "in-transit", label: "In transit", pred: t => t.status === "in-transit" }, { key: "received", label: "Received", pred: t => t.status === "received" }, { key: "cancelled", label: "Cancelled", pred: t => t.status === "cancelled" }, ]; return (
Multi-store

Stock transfers

{FILTERS.map(f => { const c = OD.TRANSFERS.filter(f.pred).length; return ( ); })}
ID
From
To
Items
Lines
Requested
Expected
Status
{OD.TRANSFERS.filter(FILTERS.find(f => f.key === filter).pred).map(t => { const from = findS(t.from); const to = findS(t.to); return (
{t.id}
{from.name}
{to.name}
{t.items.slice(0, 2).map((i, j) => (
{findP(i.productId)?.name} × {i.qty}
))} {t.items.length > 2 &&
+{t.items.length - 2} more
}
{t.items.length}
{t.requested}
{t.expected}
{t.status === "pending" && Pending} {t.status === "in-transit" && In transit} {t.status === "received" && Received} {t.status === "cancelled" && Cancelled}
); })}
{creating && setCreating(false)} onSubmit={() => { setCreating(false); pushToast({kind:'paid', icon:'transfer', title:'Transfer requested', meta:'Awaiting source store packing'}); }}/>}
); } function TransferModal({ onClose, onSubmit }) { const [from, setFrom] = oxUseState("S-001"); const [to, setTo] = oxUseState("S-002"); const [items, setItems] = oxUseState([{ productId: "", qty: 1 }]); return (
e.stopPropagation()}>

New stock transfer

Items
{items.map((it, i) => (
setItems(arr => arr.map((x, j) => j === i ? { ...x, qty: parseInt(e.target.value) || 0 } : x))}/>
))}