// VMAX Store Manager — Shift management: who worked, what they did (from the event ledger), // and a full attributed audit log. (function () { const DS = window.VMAX365DesignSystem_0f78b2; const { Button, Badge, SegmentedControl } = DS; const { Icon, Overline } = window.VMAXUI; const { Avatar, EmptyState, pushToast } = window.VMAXW; const { K } = window.VMAXP; const { useVMAX } = window.VMAXStore; const { Panel } = window.VMAXMGRUI; const TYPE = { sale: { icon: 'register', c: 'var(--vmax-ink)', bg: 'var(--surface-ground)', label: 'Sale' }, refund: { icon: 'undo', c: 'var(--vmax-red)', bg: 'var(--vmax-danger-tint)', label: 'Refund' }, remake: { icon: 'repeat', c: 'var(--vmax-amber-deep)', bg: 'var(--vmax-warn-tint)', label: 'Remake' }, transfer: { icon: 'swap', c: 'var(--vmax-red-deep)', bg: 'var(--vmax-mint)', label: 'Transfer' }, receive: { icon: 'truck', c: 'var(--vmax-ink)', bg: 'var(--surface-ground)', label: 'Receive' }, count: { icon: 'clipboard', c: 'var(--vmax-ink)', bg: 'var(--surface-ground)', label: 'Count' }, close: { icon: 'check', c: 'var(--vmax-ok)', bg: 'var(--vmax-ok-tint)', label: 'Close' }, cashup: { icon: 'cash', c: 'var(--vmax-ink)', bg: 'var(--surface-ground)', label: 'Cash-up' }, people: { icon: 'members', c: 'var(--vmax-red-deep)', bg: 'var(--vmax-mint)', label: 'People' }, price: { icon: 'edit', c: 'var(--vmax-ink)', bg: 'var(--surface-ground)', label: 'Catalogue' }, claim: { icon: 'check', c: 'var(--vmax-red-deep)', bg: 'var(--vmax-mint)', label: 'Claim' }, open: { icon: 'login', c: 'var(--vmax-ink-soft)', bg: 'var(--surface-ground)', label: 'Open' }, }; const typ = (t) => TYPE[t] || { icon: 'info', c: 'var(--vmax-ink-soft)', bg: 'var(--surface-ground)', label: t }; function Shifts({ mobile, who }) { const [s, a] = useVMAX(); const [filter, setFilter] = React.useState(null); const [typeFilter, setTypeFilter] = React.useState('all'); const ledger = s.ledger; const names = [...new Set(ledger.map((e) => e.by).filter((n) => n && n !== '—'))]; const roleOf = (n) => { const p = s.people.find((x) => x.name === n); return p ? p.roles.join(' + ') : 'past staff'; }; const salesBy = (n) => s.sales.filter((x) => x.by === n); const countType = (n, t) => ledger.filter((e) => e.by === n && e.type === t && !e.reverted).length; const span = (n) => { const ts = ledger.filter((e) => e.by === n).map((e) => e.at).sort(); return ts.length ? ts[0] + ' – ' + ts[ts.length - 1] : '—'; }; let log = filter ? ledger.filter((e) => e.by === filter) : ledger; if (typeFilter !== 'all') log = log.filter((e) => e.type === typeFilter); const revert = (e) => { if (e.type === 'count' && e.ref) a.revertCount(e.ref, who); else a.revertLedger(e.id, who); pushToast('Reverted · audit trail kept'); }; return (
{names.length} active · from the record}> {names.length === 0 ? : (
{names.map((n) => { const sb = salesBy(n); const val = sb.reduce((x, o) => x + o.amount, 0); const on = filter === n; return ( ); })}
)}
{filter && }
}>
{log.length === 0 &&
No matching events.
} {log.map((e) => { const t = typ(e.type); return (
{e.at}
{e.text}
{e.by}{e.reason && · {e.reason}}
{e.revertible && !e.reverted && !e.revertOf && }
); })}
); } function Metric({ label, value, sub }) { return
{value}{sub && {sub}}
{label}
; } window.VMAXSHIFTS = { Shifts }; })();