/* ============================================================= CoreIQ Office — Shelf Marketplace (pharmacy side) List shelf spots from the Floor Planner, run live auctions, review & award bids, track earnings. Uses window.MARKET. Registers window.OFFICE_SCREENS.shelfMarket (+ detail). ============================================================= */ const { useState: smUseState, useEffect: smUseEffect, useMemo: smUseMemo } = React; // CoreIQ group store identities in the marketplace const MY_PH = ["PH-0001", "PH-0002", "PH-0003"]; const MY_STORES = [ { id: "PH-0001", name: "CoreIQ Camberwell", state: "VIC", tier: "Large", metro: true }, { id: "PH-0002", name: "CoreIQ Glen Iris", state: "VIC", tier: "Medium", metro: true }, { id: "PH-0003", name: "CoreIQ Ringwood", state: "VIC", tier: "Medium", metro: true }, ]; // preset fixtures (from the Floor & Shelf Planner) the pharmacy can list const FIXTURES = [ { fixtureLabel: "Gondola G3", bayLabel: "Bay 2 · eye + reach", position: "Eye level", category: "Pain Management", monthlySales: 5400, facings: 4 }, { fixtureLabel: "End-cap E1", bayLabel: "Promotional end-cap", position: "End-cap", category: "Vitamins & Supplements", monthlySales: 4300, facings: 4 }, { fixtureLabel: "Wall Bay W2", bayLabel: "Bay 3 · eye level", position: "Eye level", category: "Skin & Suncare", monthlySales: 3700, facings: 3 }, { fixtureLabel: "Dispensary front", bayLabel: "Counter end-cap", position: "Counter", category: "Cough & Cold", monthlySales: 3100, facings: 2 }, { fixtureLabel: "Gondola G1", bayLabel: "Bay 1 · eye level", position: "Eye level", category: "Allergy & Hayfever", monthlySales: 4600, facings: 3 }, { fixtureLabel: "Front counter", bayLabel: "Impulse rack", position: "Counter", category: "Confectionery", monthlySales: 2400, facings: 2 }, ]; function useMktSync() { const [, s] = smUseState(0); smUseEffect(() => window.MARKET.subscribe(() => s(n => n + 1)), []); } function useMktTick() { const [, s] = smUseState(0); smUseEffect(() => { const id = setInterval(() => s(n => n + 1), 1000); return () => clearInterval(id); }, []); } function smCountPill(id) { const M = window.MARKET; const st = M.effectiveStatus(M.listing(id)); if (st === "awarded") return Awarded; if (st === "ended") return Closed; return {M.fmtTimeLeft(M.timeLeft(id))}; } function SmShelfStrip({ facings }) { const n = Math.max(5, facings + 3); const hi = Math.floor(n / 2); return (<>{Array.from({ length: n }).map((_, i) =>
= hi && i < hi + facings ? " mkt-shelf-box--hi" : "")} style={{ height: (40 + ((i * 37) % 45)) + "%" }}/>)}
); } function smBidderAv(id, size = 30) { const b = window.MARKET.BIDDERS[id] || { short: "?", color: "var(--text-subtle)" }; return
{b.short}
; } // ================================================================= // MAIN — tabbed // ================================================================= function ShelfMarket() { const M = window.MARKET; const { setScreen, setScreenState, pushToast } = window.useOffice(); useMktSync(); useMktTick(); const [tab, setTab] = smUseState("live"); const [creating, setCreating] = smUseState(false); const mine = M.listingsByPharmacy(MY_PH); const live = mine.filter(l => ["open", "closing"].includes(M.effectiveStatus(l))); const ended = mine.filter(l => M.effectiveStatus(l) === "ended"); const awarded = mine.filter(l => M.effectiveStatus(l) === "awarded"); const monthlyEarnings = awarded.reduce((s, l) => s + M.currentPrice(l.id), 0); const liveTopBids = live.reduce((s, l) => s + M.currentPrice(l.id), 0); function openListing(id) { setScreenState(s => ({ ...s, smListingId: id })); setScreen("shelfMarketListing"); } const TABS = [["live", "Live auctions", live.length], ["award", "Awaiting award", ended.length], ["earnings", "Earnings", awarded.length]]; return (
Shelf marketplace · earn from your space

Shelf auctions

Live auctions
{live.length}
{ended.length} awaiting award
Current top bids
{M.money(liveTopBids)}/mo
if awarded now
Monthly earnings
{M.money(monthlyEarnings)}/mo
{awarded.length} live placements
Annualised
{M.money(monthlyEarnings * 12)}
from shelf space
{TABS.map(([k, l, n]) => ( ))}
{tab === "live" && (live.length ? (
{live.map(l => (
openListing(l.id)}>
{l.fixtureLabel}{l.position}
{l.pharmacy}
{l.bayLabel}
{l.category}
{M.money(l.monthlySales)}/mocategory sales here
{M.bidCount(l.id)} bids{M.uniqueBidders(l.id)} bidders{M.leader(l.id) && leader {M.BIDDERS[M.leader(l.id)].name}}
{M.bidCount(l.id) ? "Top bid" : "Reserve"}
{M.money(M.currentPrice(l.id))}/mo
{smCountPill(l.id)}
))}
) : )} {tab === "award" && (ended.length ? (
Closed auctions — award the winner
PositionCategoryBidsTop bidderWinning bid
{ended.map(l => { const lead = M.leader(l.id); return (
openListing(l.id)}>
{l.fixtureLabel}
{l.pharmacy} · {l.position}
{l.category}
{M.bidCount(l.id)}
{lead ? {smBidderAv(lead, 24)} {M.BIDDERS[lead].name} : No bids}
{lead ? M.money(M.currentPrice(l.id)) : "—"}
{lead ? : }
); })}
) : )} {tab === "earnings" && (awarded.length ? (
Live placements & earnings
{M.money(monthlyEarnings)}/mo total
PositionCategoryManufacturer$/moTerm
{awarded.map(l => (
openListing(l.id)}>
{l.fixtureLabel}
{l.pharmacy} · {l.position}
{l.category}
{smBidderAv(l.awardedTo, 24)} {M.BIDDERS[l.awardedTo] ? M.BIDDERS[l.awardedTo].name : "—"}
{M.money(M.currentPrice(l.id))}
{l.term}mo
))}
) : )}
{creating && setCreating(false)} onCreate={(o) => { const l = M.createListing(o); setCreating(false); pushToast({ kind: "paid", icon: "check-circle", title: "Listing live", meta: l.fixtureLabel + " · reserve " + M.money(l.reserve) + "/mo" }); setTab("live"); }}/>}
); } function EmptyCard({ icon, title, meta }) { return

{title}

{meta}

; } // ================================================================= // CREATE LISTING (modal) — pick a fixture from the planner // ================================================================= function CreateListing({ onClose, onCreate }) { const M = window.MARKET; const [storeId, setStoreId] = smUseState(MY_STORES[0].id); const [fxIdx, setFxIdx] = smUseState(0); const [rate, setRate] = smUseState(10); // % of sales as reserve const [term, setTerm] = smUseState(6); const [days, setDays] = smUseState(3); const [catOnly, setCatOnly] = smUseState(true); const fx = FIXTURES[fxIdx]; const store = MY_STORES.find(s => s.id === storeId); const reserve = Math.round(fx.monthlySales * rate / 100 / 5) * 5; function submit() { onCreate({ pharmacyId: store.id, pharmacy: store.name, state: store.state, tier: store.tier, metro: store.metro, category: fx.category, fixtureLabel: fx.fixtureLabel, bayLabel: fx.bayLabel, position: fx.position, monthlySales: fx.monthlySales, facings: fx.facings, reserve, term, days, eligibility: { categoryOnly: catOnly }, }); } return (
e.stopPropagation()}>

List a shelf spot

Pick a fixture from your Floor & Shelf Planner. The reserve is anchored on the category sales the position drives.

{FIXTURES.map((f, i) => (
setFxIdx(i)} style={{ cursor: "pointer", border: "1px solid " + (i === fxIdx ? "var(--brand)" : "var(--border)"), borderRadius: 10, padding: "11px 13px", background: i === fxIdx ? "var(--brand-bg)" : "var(--surface)", boxShadow: i === fxIdx ? "0 0 0 3px var(--brand-bg)" : "none" }}>
{f.fixtureLabel} {f.category}
{f.bayLabel} · {f.facings} facings
{M.money(f.monthlySales)}/mo sales
))}
setRate(+e.target.value)} style={{ width: "100%" }}/>
{M.money(reserve)}/mo
); } // ================================================================= // DETAIL — review bids & award // ================================================================= function ShelfMarketListing() { const M = window.MARKET; const { screenState, setScreen, pushToast } = window.useOffice(); useMktSync(); useMktTick(); const id = screenState.smListingId; const l = M.listing(id); if (!l) return
Listing not found.
; const st = M.effectiveStatus(l); const bids = M.bidsFor(id); const lead = M.leader(id); const maxSales = Math.max(...l.salesHistory, 1); const months = ["6mo", "5mo", "4mo", "3mo", "2mo", "Now"]; function awardTo(bidder) { M.award(id, bidder); pushToast({ kind: "paid", icon: "check-circle", title: "Awarded to " + M.BIDDERS[bidder].name, meta: l.fixtureLabel + " · " + M.money(bids.find(b => b.bidder === bidder).amount) + "/mo" }); } return (

{l.fixtureLabel} · {l.category}

{l.pharmacy} {smCountPill(id)}
Position value
Reserve is anchored on the category sales this spot drives
{M.money(l.monthlySales)}/mocategory sales from this position
Reserve
{M.money(l.reserve)}/mo
{Math.round(l.reserve / l.monthlySales * 100)}% of sales
Category sales · last 6 months
{l.salesHistory.map((v, i) =>
{months[i]}
)}
Position details
Fixture{l.fixtureLabel}
Bay{l.bayLabel}
Position{l.position}
Facings{l.facings}
Term{l.term} months
Eligibility{l.eligibility.categoryOnly ? l.category + " only" : "Open"}
{/* side — bids + award */}
{st === "awarded" ? "Awarded" : st === "ended" ? "Closed · review bids" : "Closes in"}
{st === "awarded" ? "Done" : st === "ended" ? M.money(M.currentPrice(id)) : M.fmtTimeLeft(M.timeLeft(id))}
{M.bidCount(id) ? "Top bid" : "Reserve"}
{M.money(M.currentPrice(id))}/mo
Total contract
{M.money(M.currentPrice(id) * l.term)}
{st === "awarded" ? (
Awarded to {M.BIDDERS[l.awardedTo] ? M.BIDDERS[l.awardedTo].name : "—"}
) : lead ? ( <>
{st === "ended" ? "Auction closed — award the highest bid, or pick another bidder below." : "You can award early to the current leader, or wait for close."}
) :
No bids yet.
}
Bids
{bids.length} · {M.uniqueBidders(id)} bidders
{bids.length === 0 ?
No bids yet.
: (
{bids.map((b, i) => (
{smBidderAv(b.bidder)}
{M.BIDDERS[b.bidder].name}{i === 0 && High}
{M.money(b.amount)}/mo
{st !== "awarded" && }
))}
)}
); } window.OFFICE_SCREENS = Object.assign(window.OFFICE_SCREENS || {}, { shelfMarket: ShelfMarket, shelfMarketListing: ShelfMarketListing });