// Dashboard cards — KPIs, tables overview, hourly chart, reservations const { Avatar, Card, StatPill, Btn, Icon } = window.OpsUI; const { OPS_DATA } = window; // ---------------------------------------------------------------- KPI big card function KpiCard({ label, value, sub, delta, accent = 'var(--brand-500)', tone, children }) { return (
{label}
{value}
{sub &&
{sub}
} {children}
); } // Progress bar used inside KPI cards function ProgressBar({ pct, color = 'var(--brand-500)' }) { return (
); } // ---------------------------------------------------------------- Tables function TablesOverview() { // Build a synthetic 18-table layout const states = { 'A1': 'occupied', 'A2': 'occupied', 'A3': 'open', 'A4': 'alert', 'B1': 'reserved','B2': 'occupied', 'B3': 'open', 'B4': 'occupied', 'C1': 'open', 'C2': 'reserved','C3': 'open', 'C4': 'open', 'D1': 'occupied','D2': 'dirty', 'D3': 'open', 'D4': 'open', 'T1': 'occupied','T2': 'open', }; const colors = { occupied: { bg: 'var(--occ-100)', fg: 'var(--occ-700)', accent: 'var(--occ-500)' }, open: { bg: 'var(--open-50)', fg: 'var(--open-700)', accent: 'var(--open-500)' }, reserved: { bg: 'var(--res-100)', fg: 'var(--res-700)', accent: 'var(--res-500)' }, alert: { bg: 'var(--alert-100)', fg: 'var(--alert-700)', accent: 'var(--alert-500)' }, dirty: { bg: 'var(--dirty-100)', fg: 'var(--dirty-700)', accent: 'var(--dirty-500)' }, }; const counts = Object.values(states).reduce((acc, s) => (acc[s] = (acc[s] || 0) + 1, acc), {}); return ( View floor}>
{Object.entries(states).map(([name, status]) => { const c = colors[status]; return (
{name}
); })}
{[ ['occupied', 'Occupied'], ['open', 'Open'], ['reserved', 'Reserved'], ['alert', 'Alert'], ['dirty', 'Cleaning'], ].map(([k, label]) => (
{label} {counts[k] || 0}
))}
); } // ---------------------------------------------------------------- Hourly chart function HourlyRevenueCard() { const data = OPS_DATA.hourly; const max = Math.max(...data.map(d => d.revenue), 800); const currentHour = '19'; return ( Today
}>
{data.map(d => { const h = max > 0 ? (d.revenue / max) * 100 : 0; const isCurrent = d.hour === currentHour; const isFuture = parseInt(d.hour) > parseInt(currentHour); return (
0 ? 4 : 0, background: isCurrent ? 'var(--brand-500)' : isFuture ? 'var(--ink-100)' : 'var(--brand-200)', }} />
{d.hour}
); })}
); } // ---------------------------------------------------------------- Reservations function ReservationsCard() { return ( + Add}>
{OPS_DATA.reservations.map(r => (
{r.time}
{r.name}
{r.guests} guests · Table {r.table} {r.notes && <> · {r.notes}}
))}
); } window.OpsCards = { KpiCard, ProgressBar, TablesOverview, HourlyRevenueCard, ReservationsCard };