'use client'; import { useState, useEffect, useCallback } from 'react'; import { api } from '@/lib/api'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { DataTable } from '@/components/ui/data-table'; import { ActionIcon } from '@/components/ui/action-icon'; import { Modal } from '@/components/ui/modal'; import { FormModal } from '@/components/ui/form-modal'; import { useToast } from '@/components/ui/toast'; interface Area { id: string; name: string; description: string | null; isActive: boolean; _count: { clients: number }; } export default function AreasPage() { const { toast } = useToast(); const [areas, setAreas] = useState([]); const [loading, setLoading] = useState(true); const [showCreate, setShowCreate] = useState(false); const [deleteTarget, setDeleteTarget] = useState(null); const [deleting, setDeleting] = useState(false); const [search, setSearch] = useState(''); const loadAreas = useCallback(async () => { try { const res = await api.get<{ data: Area[] }>('/areas'); setAreas(res.data.data); } catch { toast('Failed to load areas', 'error'); } finally { setLoading(false); } }, [toast]); useEffect(() => { loadAreas(); }, [loadAreas]); async function handleDelete() { if (!deleteTarget) return; setDeleting(true); try { await api.delete(`/areas/${deleteTarget.id}`); toast(`Area "${deleteTarget.name}" deleted`, 'success'); setDeleteTarget(null); loadAreas(); } catch (err: any) { toast(err.response?.data?.error || 'Failed to delete area', 'error'); } finally { setDeleting(false); } } const filtered = search ? areas.filter((a) => a.name.toLowerCase().includes(search.toLowerCase()) || (a.description || '').toLowerCase().includes(search.toLowerCase())) : areas; return (

Define service areas and zones for client assignment

a.id} emptyTitle="No areas yet" emptyDescription="Create your first service area to start organizing clients by location." searchPlaceholder="Search areas..." searchValue={search} onSearchChange={setSearch} columns={[ { key: 'name', label: 'Name', sortable: true, render: (a: Area) => {a.name} }, { key: 'description', label: 'Description', render: (a: Area) => {a.description || '—'} }, { key: 'isActive', label: 'Status', sortable: true, render: (a: Area) => }, { key: 'clients', label: 'Clients', align: 'right' as const, render: (a: Area) => {a._count.clients} }, { key: 'actions', label: '', align: 'right', render: (a: Area) => (
e.stopPropagation()}> {a._count.clients === 0 && ( setDeleteTarget(a)} /> )}
), }, ]} /> setDeleteTarget(null)} title="Delete Area" description={`Are you sure you want to delete "${deleteTarget?.name}"? This action cannot be undone.`} variant="danger" confirmLabel="Delete Area" onConfirm={handleDelete} loading={deleting} /> {showCreate && ( { setShowCreate(false); loadAreas(); toast('Area created', 'success'); }} onClose={() => setShowCreate(false)} /> )}
); } function CreateAreaModal({ onCreated, onClose }: { onCreated: () => void; onClose: () => void }) { const { toast } = useToast(); const [name, setName] = useState(''); const [description, setDescription] = useState(''); const [error, setError] = useState(''); const [submitting, setSubmitting] = useState(false); const ic = 'mt-1 block w-full rounded-lg border border-surface-200 dark:border-surface-600 bg-white dark:bg-surface-800 px-3.5 py-2.5 text-sm text-surface-900 dark:text-surface-100 placeholder:text-surface-400 dark:placeholder:text-surface-500 focus:border-primary-500 dark:focus:border-primary-400 focus:outline-none focus:ring-2 focus:ring-primary-500/20 transition-all duration-200'; async function handleSubmit(e: React.FormEvent) { e.preventDefault(); setError(''); setSubmitting(true); try { await api.post('/areas', { name, description: description || undefined }); onCreated(); } catch (err: any) { setError(err.response?.data?.error || 'Failed to create area'); toast(err.response?.data?.error || 'Failed to create area', 'error'); } finally { setSubmitting(false); } } return (
{error && (
{error}
)}
setName(e.target.value)} className={ic} placeholder="e.g. Barangay 1 - Centro" />
setDescription(e.target.value)} className={ic} placeholder="Description of the service area" />
); }