// Employees.jsx — Master Data › Employees. Operators & Riggers master records. // Admin: full CRUD + certification editing. Other roles: view-only. // Modal to record/renew an operator's certifications and their expiry dates. function CertEditModal({ operator, onClose, onSave }) { const [rows, setRows] = React.useState(() => { const byCode = Object.fromEntries((operator.certs || []).map(c => [c.code, c.exp])); return CERT_LEGEND.map(l => ({ code: l.code, label: l.label, color: l.color, held: l.code in byCode, exp: byCode[l.code] || '' })); }); const update = (code, patch) => setRows(rs => rs.map(r => r.code === code ? { ...r, ...patch } : r)); const incomplete = rows.some(r => r.held && !r.exp); const save = () => { const certs = rows.filter(r => r.held && r.exp).map(r => ({ code: r.code, exp: r.exp })); onSave(certs); }; return (
e.stopPropagation()} style={{maxWidth: 560, width: '94vw'}}>
Certifications — {operator.name}
Tick each cert held and set its expiry date. Expired certs are hidden from booking; renewal reminders fire {CERT_RENEW_WINDOW_DAYS} days before.
{rows.map(r => { const st = r.held && r.exp ? certState(r.exp) : null; const badge = st === 'expired' ? {t: 'Expired', c: 'var(--color-danger)', bg: 'rgba(239,68,68,0.1)'} : st === 'expiring' ? {t: 'Renew soon', c: '#b45309', bg: 'rgba(217,119,6,0.12)'} : st === 'valid' ? {t: 'Valid', c: '#15803d', bg: 'rgba(34,197,94,0.1)'} : null; return (
{badge ? {badge.t} : null} update(r.code, { exp: e.target.value })} className="input" style={{width: 150, padding: '6px 8px', fontSize: 12, opacity: r.held ? 1 : 0.45}}/>
); })}
{incomplete ? 'Set an expiry date for every ticked cert.' : 'Changes apply to booking immediately.'}
); } function EmployeesPage({ role }) { const [tab, setTab] = React.useState('operators'); const [ops, setOps] = React.useState(OPERATORS); const [editOp, setEditOp] = React.useState(null); const isAdmin = role === 'Admin'; return (
Employees — field crew master records: crane operators and riggers, with licences and live certifications. {isAdmin ? 'You can add, edit and renew certs.' : 'View-only — only Admin can edit employee records.'}
{tab === 'operators' ? (

Operators

Crane drivers · NIOSH/OPL licensed
{isAdmin ? : Admin only}
{ops.map(o => { const active = activeCerts(o.certs); const expired = (o.certs || []).filter(c => certState(c.exp) === 'expired'); const soon = active.filter(c => certState(c.exp) === 'expiring').length; return ( ); })}
IDNamePhoneLicenseCertificationsStatus
{o.id} {o.name} {o.phone} {o.license}
{active.length === 0 ? None valid : null} {active.map(c => { const exp = certState(c.exp) === 'expiring'; return ( {c.code} ); })} {soon > 0 ? · {soon} renew soon : null} {expired.length > 0 ? c.code + ' expired ' + fmtCertDate(c.exp)).join(', ')} style={{fontSize: 10.5, color: 'var(--color-danger)', fontWeight: 600}}>· {expired.length} expired : null}
{o.status} {isAdmin ? : null}
) : null} {editOp ? ( setEditOp(null)} onSave={(certs) => { setOps(prev => prev.map(o => o.id === editOp.id ? { ...o, certs } : o)); setEditOp(null); }} /> ) : null} {tab === 'riggers' ? (

Riggers

Lift assistants · Slung-load certified
{isAdmin ? : Admin only}
{RIGGERS.map(r => ( ))}
IDNamePhoneCertStatus
{r.id} {r.name} {r.phone} {r.cert} {r.status} {isAdmin ? : null}
) : null}
); } Object.assign(window, { EmployeesPage });