import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'; import { Head, Link, router, usePage } from '@inertiajs/react'; import { Badge } from '@/Components/ui/badge'; import { Button } from '@/Components/ui/button'; import { Card, CardContent } from '@/Components/ui/card'; import { DataTableToolbar } from '@/Components/DataTableToolbar'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/Components/ui/select'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/Components/ui/table'; import { PaginatedData, PageProps } from '@/types'; import { Plus, Eye, Pencil, Trash2, FolderKanban } from 'lucide-react'; import { FormEvent, useMemo, useState } from 'react'; interface Project { id: number; ulid: string; name: string; code: string; location?: string; status: string; client_name?: string; contract_value: string; total_capitalization: string; capitalization_percentage: number; is_over_budget: boolean; completion_percentage: string; start_date?: string; target_end_date?: string; created_at: string; personnel?: { id: number; ulid: string; name: string }[]; } interface StatusOption { value: string; label: string; } interface Props extends PageProps { projects: PaginatedData; filters: { search?: string; status?: string }; statuses: StatusOption[]; } const statusVariant = (status: string) => { switch (status) { case 'under_bidding': return 'outline'; case 'planning': return 'secondary'; case 'in_progress': return 'default'; case 'on_hold': return 'destructive'; case 'completed': return 'default'; case 'closed': return 'secondary'; default: return 'outline'; } }; const statusLabel = (status: string) => { return status.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()); }; const formatCurrency = (val: string) => { return new Intl.NumberFormat('en-PH', { style: 'currency', currency: 'PHP' }).format(Number(val)); }; export default function Index({ projects, filters, statuses }: Props) { const { flash } = usePage().props; const [search, setSearch] = useState(filters.search || ''); const [statusFilter, setStatusFilter] = useState(filters.status || 'all'); // Items array for Select label lookup const statusFilterItems = useMemo(() => [{ value: 'all', label: 'All Statuses' }, ...statuses.map(s => ({ value: s.value, label: s.label }))], [statuses]); const applyFilters = (e?: FormEvent) => { e?.preventDefault(); router.get(route('projects.index'), { search: search || undefined, status: statusFilter !== 'all' ? statusFilter : undefined, }, { preserveState: true, replace: true }); }; const handleDelete = (project: Project) => { if (confirm(`Delete project "${project.name}"?`)) { router.delete(route('projects.destroy', project.ulid)); } }; return (

Projects

} >
{flash?.success && (
{flash.success}
)} {flash?.error && (
{flash.error}
)} { if (v) setStatusFilter(v); }} items={statusFilterItems}> All Statuses {statuses.map((s) => ( {s.label} ))} } actions={ } /> Code Name Client Status Contract Value Capitalization Progress Actions {projects.data.length === 0 ? ( No projects found. ) : ( projects.data.map((project) => ( {project.code} {project.name} {project.client_name || '-'} {statusLabel(project.status)} {formatCurrency(project.contract_value)}
= 80 ? 'bg-amber-500' : 'bg-emerald-500' }`} style={{ width: `${Math.min(project.capitalization_percentage, 100)}%` }} />
= 80 ? 'text-amber-600' : 'text-gray-600' }`}> {project.capitalization_percentage.toFixed(1)}%
{Number(project.completion_percentage).toFixed(0)}%
)) )}
{projects.last_page > 1 && (

Showing {projects.from} to {projects.to} of {projects.total}

{projects.prev_page_url && ( )} {projects.next_page_url && ( )}
)}
); }