// 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 (
{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 };