/* ============================================================= CoreIQ Office — Electronic Shelf Labels (ESL) Manage device fleet, price sync, layout templates, batch updates ============================================================= */ const { useState: eslUseState, useMemo: eslUseMemo } = React; // ESL sample data const ESL_DEVICES_SUMMARY = { total: 1842, online: 1804, lowBattery: 18, needsSync: 11, offline: 9, }; const ESL_GATEWAYS = [ { id: "GW-CMW-1", store: "S-001", model: "SES-imagotag · AP V2", devices: 720, signal: "−54 dBm", status: "online" }, { id: "GW-CMW-2", store: "S-001", model: "SES-imagotag · AP V2", devices: 240, signal: "−61 dBm", status: "online" }, { id: "GW-GLI-1", store: "S-002", model: "SES-imagotag · AP V2", devices: 410, signal: "−58 dBm", status: "online" }, { id: "GW-RNG-1", store: "S-003", model: "SES-imagotag · AP V2", devices: 472, signal: "−52 dBm", status: "online" }, ]; const ESL_TEMPLATES = [ { id: "esl-shelf", name: "Shelf-edge · 2.9″", size: "296×128 px", uses: 1480, fields: ["name","strength","price","unitPrice","barcode"], color: false }, { id: "esl-promo", name: "Promo highlight · 2.9″", size: "296×128 px", uses: 142, fields: ["promoBadge","name","priceWas","priceNow","ends"], color: true }, { id: "esl-bin", name: "Dispensary bin · 4.2″", size: "400×300 px", uses: 158, fields: ["name","strength","schedule","location","barcode"], color: false }, { id: "esl-ndss", name: "NDSS small · 1.6″", size: "200×96 px", uses: 38, fields: ["name","copay","fullPrice","eligible"], color: false }, { id: "esl-osa", name: "On-shelf availability · 2.9″", size: "296×128 px", uses: 24, fields: ["name","stockStatus","reorderETA"], color: true }, ]; const ESL_RECENT_UPDATES = [ { ts: "Today 14:18", title: "Summer Saver · Skincare 30%", scope: "Skincare category · all stores", items: 142, status: "delivered", elapsed: "4m 12s" }, { ts: "Today 11:48", title: "Atorvastatin price refresh", scope: "Atorvastatin 40mg · all stores", items: 3, status: "delivered", elapsed: "52s" }, { ts: "Today 09:14", title: "PO-4422 receive · price changes", scope: "Camberwell · 4 SKUs", items: 4, status: "delivered", elapsed: "1m 04s" }, { ts: "Yesterday", title: "Mother's Day promo · ended", scope: "Skincare · revert to retail", items: 142, status: "delivered", elapsed: "3m 48s" }, { ts: "Yesterday", title: "NDSS sensor price update", scope: "FreeStyle Libre 2 · 3 stores", items: 3, status: "partial", elapsed: "—", note: "1 ESL offline at Ringwood" }, { ts: "23/05/2026", title: "Vitamins · weekly refresh", scope: "All vitamins · all stores", items: 88, status: "delivered", elapsed: "5m 30s" }, ]; // ================================================================= // ESL MANAGEMENT // ================================================================= function ESLs() { const { pushToast } = window.useOffice(); const [tab, setTab] = eslUseState("fleet"); const STORE_COLOURS = { "S-001": "var(--teal-700)", "S-002": "var(--navy-600)", "S-003": "var(--violet-600)" }; return (
Head-office function · SES-imagotag

Electronic shelf labels

{tab === "fleet" && ( <> {/* Per-store fleet cards */}
{OD.STORES.map(s => { const gw = ESL_GATEWAYS.filter(g => g.store === s.id); const devices = gw.reduce((sum, g) => sum + g.devices, 0); const lowBatt = s.id === "S-001" ? 8 : s.id === "S-002" ? 4 : 6; const needsSync = s.id === "S-001" ? 5 : s.id === "S-002" ? 2 : 4; const offline = s.id === "S-003" ? 4 : s.id === "S-001" ? 3 : 2; return (
{s.code}
{s.name}
{gw.length} {gw.length === 1 ? "gateway" : "gateways"} · {devices.toLocaleString()} ESLs
{offline > 2 || lowBatt > 6 ? Attention : Healthy}
Online
{(devices - offline).toLocaleString()}
Needs sync
0 ? 'var(--hold-text)' : 'var(--text)'}}>{needsSync}
Low battery
6 ? 'var(--hold-text)' : 'var(--text)'}}>{lowBatt}
); })}
{/* Gateway table */}
Gateways
Gateway
Store
Model
Devices
Signal
Last beacon
Status
{ESL_GATEWAYS.map(g => (
{g.id}
{findS(g.store)?.name}
{g.model}
{g.devices.toLocaleString()}
{g.signal}
12s ago
Online
))}
{/* Devices needing attention */}

Devices needing attention

ESL ID
Bound product
Store
Location
Battery
Last sync
Issue
{[ { id:"E-0188-A22", store:"S-001", prod:"Insulin Glargine 100u/ml", loc:"Fridge-1", batt:18, sync:"Today 11:48", issue:"low-battery" }, { id:"E-0188-B41", store:"S-001", prod:"Atorvastatin 40mg", loc:"Disp-B2", batt:24, sync:"Today 11:48", issue:"low-battery" }, { id:"E-0188-C18", store:"S-003", prod:"FreeStyle Libre 2", loc:"Fridge-2", batt:62, sync:"22/05 14:20", issue:"needs-sync" }, { id:"E-0188-D04", store:"S-003", prod:"Salbutamol Spacer", loc:"Resp-09", batt:81, sync:"Yesterday", issue:"offline" }, { id:"E-0188-E11", store:"S-002", prod:"Esomeprazole 20mg", loc:"Disp-C1", batt:74, sync:"Today 10:14", issue:"needs-sync" }, { id:"E-0188-F02", store:"S-001", prod:"Ventolin 100mcg inhaler", loc:"Resp-04", batt:12, sync:"Today 14:18", issue:"low-battery" }, ].map(d => (
{d.id}
{d.prod}
{findS(d.store)?.code}
{d.loc}
{d.batt}%
{d.sync}
{d.issue === "low-battery" && Low battery} {d.issue === "needs-sync" && Needs sync} {d.issue === "offline" && Offline}
))}
)} {tab === "updates" && (
Price & promotion changes are sent to ESLs in batches. Most updates land in under 5 minutes. Delivery failures retry automatically up to 3×.
When
Update
Scope
Items
Time taken
Status
{ESL_RECENT_UPDATES.map((u, i) => (
{u.ts}
{u.title} {u.note &&
{u.note}
}
{u.scope}
{u.items}
{u.elapsed}
{u.status === "delivered" && Delivered} {u.status === "partial" && Partial} {u.status === "failed" && Failed}
))}
)} {tab === "templates" && (
{ESL_TEMPLATES.map(t => (
{/* Mini preview */} {t.id === "esl-promo" ? (
Goldfinger banana
Honduras · per lb
Special
$1.9/lb
) : (
{t.id === "esl-ndss" ? "BD Pen Needles 4mm" : "Atorvastatin 40mg"}
{t.id === "esl-ndss" ? "100 pieces" : "30 tablets"}
9333091001284
{t.id === "esl-ndss" ? "$1.20" : "$18.20"}
)}
{t.name}
{t.size}
{t.color && Colour}
Used on {t.uses.toLocaleString()} {t.uses === 1 ? "ESL" : "ESLs"}
{t.fields.map(f => {f})}
))}
)} {tab === "rules" && (

Auto-sync rules

When CoreIQ pushes price changes to ESLs automatically.
When a price changes in Manage stock
Push affected ESLs within seconds of save.
When a promotion starts or ends
Switch to / revert from the promo template automatically.
When stock receives change cost / margin
Auto-flag for review — manager confirms before push.
Out-of-stock indicator
Switch to "Out of stock · ETA" template when on-hand = 0.
Daily sync window
Catch-up sync for any ESLs that missed live pushes.
Quiet hours
No screen flashes between these times (saves battery, avoids customer disturbance).
)}
); } window.OFFICE_SCREENS = Object.assign(window.OFFICE_SCREENS || {}, { esls: ESLs, });