// Shifts card + Messages card
const { Avatar, Card, Btn, Icon } = window.OpsUI;
const { OPS_DATA } = window;
// ---------------------------------------------------------------- Shifts
function ShiftsCard({ onMessage }) {
return (
+ Start shift}
>
{OPS_DATA.shifts.map(s => (
{s.name}
{s.status === 'break' && (
On break
)}
{s.section} · in at {s.clockIn} · {s.hoursWorked.toFixed(1)}h worked
{s.tables.length > 0 && <> · tables {s.tables.join(', ')}>}
))}
{/* scheduled / not yet started */}
Scheduled later
{OPS_DATA.scheduledShifts.map(s => (
{s.name}
{s.section} · starts at {s.scheduledAt}
Start now
))}
);
}
// ---------------------------------------------------------------- Messages
function MessagesCard({ openCompose }) {
return (
openCompose()}> New}
>
{/* Quick presets */}
Quick send
{OPS_DATA.presets.map(p => (
))}
Recent
{OPS_DATA.recentMessages.map(m => (
))}
);
}
// ---------------------------------------------------------------- Compose modal
function ComposeModal({ open, prefilled, prefilledTo, onClose }) {
const [text, setText] = React.useState('');
const [recipient, setRecipient] = React.useState('Everyone');
React.useEffect(() => {
if (open) {
setText(prefilled || '');
setRecipient(prefilledTo || 'Everyone');
}
}, [open, prefilled, prefilledTo]);
if (!open) return null;
const recipients = ['Everyone', ...OPS_DATA.shifts.map(s => s.name)];
return (
e.stopPropagation()} style={{
width: 'min(520px, 100%)',
background: 'white',
borderRadius: 18,
padding: 24,
boxShadow: '0 20px 60px rgba(0,0,0,0.25)',
}}>
To
{recipients.map(r => (
))}
Message
);
}
// ---------------------------------------------------------------- End-day modal
function EndDayModal({ open, onClose, onConfirm }) {
if (!open) return null;
const k = OPS_DATA.kpis;
return (
e.stopPropagation()} style={{
width: 'min(560px, 100%)',
background: 'white', borderRadius: 18, padding: 28,
boxShadow: '0 20px 60px rgba(0,0,0,0.25)',
}}>
End business day?
Today's session will close. Make sure all tables are paid and waiters have clocked out.
{[
['Revenue', '€' + k.revenue.toFixed(2)],
['Covers', k.covers.toString()],
['Open tables', `${k.tablesOpen} of ${k.tablesTotal}`],
['Avg ticket', '€' + k.avgTicket.toFixed(2)],
].map(([lbl, val]) => (
))}
{k.tablesOpen > 0 && (
⚠ {k.tablesOpen} tables are still open. They'll need to be closed manually.
)}
Cancel
End day
);
}
window.OpsCards2 = { ShiftsCard, MessagesCard, ComposeModal, EndDayModal };