"use client"; import { useMemo, useState } from "react"; import { apiGet, apiPost } from "@/lib/api"; import { useCachedFetch } from "@/hooks/useCachedFetch"; import { HardHat, Plus, Search, Filter, CheckCircle2, AlertTriangle, TrendingUp, } from "lucide-react"; import { Skeleton } from "@/components/ui/Skeleton"; interface Department { id: string; name: string; code: string; } interface Worker { id: string; name: string; email: string; role: string; department_id: string; is_active: boolean; current_workload: number; max_workload: number; resolved_total?: number; efficiency?: number; } interface WorkerPerformance { id: string; resolved_total: number; efficiency: number; } export default function WorkersPage() { const { data: departmentsData, loading: deptLoading, revalidate: revalidateDept, } = useCachedFetch("/admin/departments"); const { data: workersData, loading: workersLoading, revalidate: revalidateWorkers, } = useCachedFetch("/admin/members"); const { data: perfData, loading: perfLoading, revalidate: revalidatePerf, } = useCachedFetch("/admin/workers/performance"); const [showForm, setShowForm] = useState(false); const [formData, setFormData] = useState({ name: "", email: "", password: "", department_id: "", role: "worker", }); const [search, setSearch] = useState(""); const departments = departmentsData || []; const workers = useMemo(() => { if (!workersData) return []; const perfMap = new Map((perfData || []).map((p) => [p.id, p])); return workersData.map((w) => { const perf = perfMap.get(w.id); return { ...w, resolved_total: perf?.resolved_total || 0, efficiency: perf?.efficiency || 0, }; }); }, [workersData, perfData]); const loading = deptLoading || workersLoading || perfLoading; const refreshAll = () => { revalidateDept(); revalidateWorkers(); revalidatePerf(); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { await apiPost("/admin/members", formData); setShowForm(false); setFormData({ name: "", email: "", password: "", department_id: "", role: "worker", }); refreshAll(); } catch (error: unknown) { const message = error instanceof Error ? error.message : "Failed to create worker"; alert(message); } }; const getDepartmentName = (deptId: string) => { const dept = departments.find((d) => d.id === deptId); return dept ? dept.name : "Unassigned"; }; if (loading) { return (
{Array.from({ length: 6 }).map((_, i) => ( ))}
); } const filteredWorkers = workers .filter((w) => w.role !== "admin") .filter( (w) => search === "" || w.name.toLowerCase().includes(search.toLowerCase()) || w.email.toLowerCase().includes(search.toLowerCase()), ); return (

Workforce Management

Manage field workers, assign tasks, and monitor performance.

{showForm && (

New Worker Enrollment

setFormData({ ...formData, name: e.target.value }) } className="w-full px-4 py-2.5 bg-white/70 border border-slate-300 rounded-xl text-slate-900 focus:ring-4 focus:ring-urban-primary/10 focus:border-urban-primary/40 outline-none" placeholder="e.g. John Doe" required />
setFormData({ ...formData, email: e.target.value }) } className="w-full px-4 py-2.5 bg-white/70 border border-slate-300 rounded-xl text-slate-900 focus:ring-4 focus:ring-urban-primary/10 focus:border-urban-primary/40 outline-none" placeholder="worker@city.gov" required />
setFormData({ ...formData, password: e.target.value }) } className="w-full px-4 py-2.5 bg-white/70 border border-slate-300 rounded-xl text-slate-900 focus:ring-4 focus:ring-urban-primary/10 focus:border-urban-primary/40 outline-none" required minLength={8} placeholder="••••••••" />
)}
setSearch(e.target.value)} className="w-full pl-9 pr-4 py-2.5 bg-white/70 border border-slate-200 rounded-xl text-sm focus:border-urban-primary/40 focus:ring-4 focus:ring-urban-primary/10 outline-none" />

Active Workforce ({filteredWorkers.length})

{filteredWorkers.length === 0 ? (

No field workers found.

) : (
{filteredWorkers.map((worker) => (
{worker.name.charAt(0)}

{worker.name}

{worker.email}

{!worker.is_active && ( INACTIVE )}
Department {getDepartmentName(worker.department_id)}
Efficiency {worker.efficiency}{" "} /week {worker.efficiency && worker.efficiency > 5 && ( )}
Total Resolved {worker.resolved_total}
Current Workload {worker.current_workload} / {worker.max_workload}
= worker.max_workload ? "bg-red-500" : worker.current_workload > worker.max_workload * 0.7 ? "bg-amber-500" : "bg-urban-primary" }`} style={{ width: `${Math.min( (worker.current_workload / (worker.max_workload || 10)) * 100, 100, )}%`, }} >
{worker.current_workload >= worker.max_workload && (
Overloaded
)}
))}
)}
); }