'use client'; import { useMemo, useState } from 'react'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { ChevronRight, Download, Truck, UserPlus, X } from 'lucide-react'; import type { WorkforceData } from '@/lib/workforce-store'; import { attendanceSummary, employeeSlug } from '@/lib/workforce'; import { buildBadgesPdf, downloadPdf } from '@/lib/qr-pdf'; import { Kpi, StatusChip, rateText } from './WorkforceBits'; /** * The people register. Every operator and mechanic, with the machine an operator runs * and their rate — the information that used to live only on /running/operators. */ export function EmployeesView({data}:{data:WorkforceData}) { const router=useRouter(); const [query,setQuery]=useState(''); const [role,setRole]=useState('all'); const [adding,setAdding]=useState(false); const [kind,setKind]=useState<'operators'|'mechanics'>('operators'); const [busy,setBusy]=useState(false); const [error,setError]=useState(''); const [building,setBuilding]=useState(false); const mechanics=data.employees.filter(e=>e.kind==='mechanics' && e.employeeNo.trim()); async function downloadBadges() { setBuilding(true); try{downloadPdf(await buildBadgesPdf(mechanics.map(m=>({name:m.name,employee_code:m.employeeNo,role:m.role}))),'mega-plant-mechanic-badges.pdf');} catch{alert('Could not build the PDF. Please try again.');} finally{setBuilding(false);} } const status=useMemo(()=>{ const byEmployee=new Map(); for(const e of data.events){const l=byEmployee.get(e.employee)??[];l.push(e);byEmployee.set(e.employee,l);} return new Map(data.employees.map(e=>[e.id,attendanceSummary(byEmployee.get(e.id)??[],data.asOf).status])); },[data]); const staffed=new Set(data.employees.map(e=>e.machine?.id).filter(Boolean)); // Same scope as the old operator register: machines on the operator sheet. const emptyMachines=data.machines.filter(m=>m.onSheet && !staffed.has(m.id)); const operators=data.employees.filter(e=>e.kind==='operators'); const filtered=data.employees.filter(e=>`${e.name} ${e.employeeNo} ${e.role} ${e.machine?.code??''} ${e.machine?.name??''}`.toLowerCase().includes(query.toLowerCase()) && (role==='all' || (role==='operators'?e.kind==='operators':role==='mechanics'?e.kind==='mechanics':e.kind==='operators'&&!e.machine))); async function add(ev:React.FormEvent) { ev.preventDefault();const fd=new FormData(ev.currentTarget);setBusy(true);setError(''); try { const body=kind==='operators' ?{name:fd.get('name'),employeeCode:fd.get('employeeCode'),rate:fd.get('rate'),assetId:fd.get('assetId')||''} :{name:fd.get('name'),employeeCode:fd.get('employeeCode'),role:fd.get('role')||'Mechanic'}; const r=await fetch(`/api/${kind}`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}); const out=await r.json(); if(!out.ok)throw new Error(out.error||'Could not add the employee.'); setAdding(false);router.refresh(); }catch(e){setError(e instanceof Error?e.message:'Could not save — check your connection.');} finally{setBusy(false);} } return

MEGA PLANT / WORKFORCE

Employees

Everyone on the Plant roster, the machine they run and their rate. Open someone for their dashboard.

{mechanics.length>0 && } {!adding && }
s==='in').length}/> o.machine).length} / ${operators.length}`}/>
{adding &&

Add an employee

{kind==='operators' ? <> : }

The employee number is what their QR badge encodes, so it must be unique.

{error &&

{error}

}
}
{filtered.map(e=>
{e.employeeNo||'No employee number'}

{e.name}

{e.role}{e.kind==='operators'?` · ${rateText(e.rate)}`:''}

{e.machine?<>{e.machine.code} · {e.machine.name}:e.kind==='operators'?No machine allocated:Not on a machine}
)}
{!filtered.length &&
No employees match.
} {emptyMachines.length>0 &&

Machines with no operator

On the operator sheet but nobody allocated. Open an operator to put them on one.

    {emptyMachines.map(m=>
  • {m.code}{m.name}
  • )}
}
; }