/* ============================================================= CoreIQ Office — Store setup (onboarding) The front door for a new site: confirm the organisation's trading name / legal name / ABN, the site's address + registration numbers (PBS approval, AHPRA), seed the built-in RBAC roles, and manage operators. Everything writes to the real tenant rows and flows to the tills via PowerSync. PINs are never handled here — an operator's PIN is established on the till itself. ============================================================= */ const { useState: suUseState, useEffect: suUseEffect } = React; function SetupField({ label, value, onChange, placeholder, required, type }) { return ( ); } function StoreSetupScreen() { const [state, setState] = suUseState(null); const [err, setErr] = suUseState(null); const [busy, setBusy] = suUseState(false); const [savedMsg, setSavedMsg] = suUseState(null); // Drafts (uncontrolled by server state until Save). const [orgDraft, setOrgDraft] = suUseState(null); const [siteDraft, setSiteDraft] = suUseState(null); const [opDraft, setOpDraft] = suUseState({ firstName: "", lastName: "", email: "", loginCode: "", roleId: "" }); const load = () => window.OfficeAPI.getOnboarding() .then((d) => { setState(d); setOrgDraft({ ...d.organisation }); setSiteDraft(d.sites[0] ? { ...d.sites[0] } : null); setErr(null); }) .catch((e) => setErr(String(e.message || e))); suUseEffect(() => { load(); }, []); const flash = (msg) => { setSavedMsg(msg); setTimeout(() => setSavedMsg(null), 2500); }; const run = (p, done) => { setBusy(true); p.then((d) => { if (d && d.onboarding) { setState(d.onboarding); setOrgDraft({ ...d.onboarding.organisation }); setSiteDraft(d.onboarding.sites[0] ? { ...d.onboarding.sites[0] } : null); } setErr(null); setBusy(false); if (done) done(d); }).catch((e) => { setErr(String(e.message || e)); setBusy(false); }); }; if (err && !state) return
{err}
; if (!state || !orgDraft) return
Loading…
; const pendingName = /pending/i.test(state.organisation.name); const rolesReady = state.roles.length > 0; const saveOrg = () => run(window.OfficeAPI.patchOrganisation({ name: orgDraft.name || undefined, legalName: orgDraft.legalName || null, groupAbn: orgDraft.groupAbn || null, timezone: orgDraft.timezone || null, }), () => flash("Organisation saved")); const saveSite = () => run(window.OfficeAPI.patchSite(siteDraft.id, { name: siteDraft.name || undefined, pbsApprovalNumber: siteDraft.pbsApprovalNumber || null, ahpraPharmacyNumber: siteDraft.ahpraPharmacyNumber || null, addressLine1: siteDraft.addressLine1 || null, locality: siteDraft.locality || null, region: siteDraft.region || null, postalCode: siteDraft.postalCode || null, phone: siteDraft.phone || null, email: siteDraft.email || null, }), () => flash("Site saved")); const addOperator = () => { if (!opDraft.firstName || !opDraft.lastName || !opDraft.roleId) { setErr("Operator needs a first name, last name and role"); return; } setBusy(true); window.OfficeAPI.createOperator({ firstName: opDraft.firstName, lastName: opDraft.lastName, email: opDraft.email || null, loginCode: opDraft.loginCode || null, roleId: opDraft.roleId, }).then(() => { setOpDraft({ firstName: "", lastName: "", email: "", loginCode: "", roleId: opDraft.roleId }); flash("Operator added"); return load(); }).then(() => setBusy(false)) .catch((e) => { setErr(String(e.message || e)); setBusy(false); }); }; const patchOperator = (id, patch, msg) => run(window.OfficeAPI.patchOperator(id, patch), () => flash(msg)); return (
Administration · onboarding

Store setup

{savedMsg ? {savedMsg} : null} {pendingName ? ⚠ store name not confirmed yet : null}
{err ?
{err}
: null} {/* --- Organisation identity --- */}

Organisation

setOrgDraft({ ...orgDraft, name: v })} /> setOrgDraft({ ...orgDraft, legalName: v })} /> setOrgDraft({ ...orgDraft, groupAbn: v.replace(/\D/g, "") })} /> setOrgDraft({ ...orgDraft, timezone: v })} />
{/* --- Site details --- */} {siteDraft ? (

Pharmacy site {siteDraft.code ? `· ${siteDraft.code}` : ""}

setSiteDraft({ ...siteDraft, name: v })} /> setSiteDraft({ ...siteDraft, pbsApprovalNumber: v })} /> setSiteDraft({ ...siteDraft, ahpraPharmacyNumber: v })} /> setSiteDraft({ ...siteDraft, phone: v })} /> setSiteDraft({ ...siteDraft, email: v })} /> setSiteDraft({ ...siteDraft, addressLine1: v })} /> setSiteDraft({ ...siteDraft, locality: v })} /> setSiteDraft({ ...siteDraft, region: v })} /> setSiteDraft({ ...siteDraft, postalCode: v })} />
) : null} {/* --- Roles --- */}

Roles

{rolesReady ? (
{state.roles.map((r) => (
{r.name} · {r.permissions.length} permission{r.permissions.length === 1 ? "" : "s"}
))}
) : (

No roles yet. Seed the standard set (Owner, Manager, Pharmacist, Cashier) — they can be tuned later.

)}
{/* --- Operators --- */}

Operators

Operators sync to the tills. A PIN is set on the till at first sign-in — it is never entered here.

{state.operators.length > 0 ? ( {state.operators.map((o) => ( ))}
NameLogin codeEmailRoleStatus
{o.displayName || `${o.firstName} ${o.lastName}`} {o.loginCode || "—"} {o.email || "—"} {o.isActive ? "Active" : "Inactive"}
) : (

No operators yet.

)}
setOpDraft({ ...opDraft, firstName: v })} /> setOpDraft({ ...opDraft, lastName: v })} /> setOpDraft({ ...opDraft, email: v })} /> setOpDraft({ ...opDraft, loginCode: v.toUpperCase() })} />
{!rolesReady ?

Seed roles first, then add operators.

: null}
); } window.OFFICE_SCREENS = Object.assign(window.OFFICE_SCREENS || {}, { storeSetup: StoreSetupScreen, });