import { Input } from '@/Components/ui/input'; import { Label } from '@/Components/ui/label'; import { Textarea } from '@/Components/ui/textarea'; import { Card, CardContent, CardHeader, CardTitle } from '@/Components/ui/card'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/Components/ui/select'; import { Button } from '@/Components/ui/button'; import { ChevronDown, ChevronUp, Building2, Search, CheckCircle2, Tags } from 'lucide-react'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, DialogFooter } from '@/Components/ui/dialog'; import { Avatar, AvatarFallback, AvatarImage } from '@/Components/ui/avatar'; import { Badge } from '@/Components/ui/badge'; import { useEffect, useMemo, useState } from 'react'; const MAIN_CONTRACTOR = 'Great SwissMetal Builders Corporation'; interface Employee { id: number; ulid: string; name: string; email?: string; profile_picture?: string | null; roles?: { id: number; name: string }[]; employee_profile?: { department?: string; position?: string; phone?: string; }; } function ProjectManagerLookup({ employees, selectedId, onSelect, disabled }: { employees: Employee[], selectedId: string, onSelect: (id: string) => void, disabled?: boolean }) { const [open, setOpen] = useState(false); const [search, setSearch] = useState(''); const [tempSelectedId, setTempSelectedId] = useState(selectedId); const filteredEmployees = useMemo(() => { if (!search) return employees; const lowerSearch = search.toLowerCase(); return employees.filter(e => e.name.toLowerCase().includes(lowerSearch) || (e.email && e.email.toLowerCase().includes(lowerSearch)) || (e.employee_profile?.position && e.employee_profile.position.toLowerCase().includes(lowerSearch)) ); }, [employees, search]); const handleConfirm = () => { onSelect(tempSelectedId); setOpen(false); }; const handleOpenChange = (newOpen: boolean) => { setOpen(newOpen); if (newOpen) { setTempSelectedId(selectedId); setSearch(''); } }; const selectedEmployee = employees.find(e => e.ulid === selectedId); return ( <> Select Project Manager
setSearch(e.target.value)} className="pl-9 bg-background text-sm h-9" />
{filteredEmployees.length === 0 ? (
No project managers found matching your search.
) : (
{filteredEmployees.map((emp) => { const isSelected = tempSelectedId === emp.ulid; return (
setTempSelectedId(emp.ulid)} className={`flex items-center gap-3 p-3 rounded-lg border cursor-pointer transition-all ${ isSelected ? 'border-primary bg-primary/5 ring-1 ring-primary' : 'border-border hover:bg-accent/40' }`} > {emp.profile_picture && ( )} {emp.name.substring(0, 2).toUpperCase()}

{emp.name}

{isSelected && }

{emp.email || 'No email provided'}

{(emp.employee_profile?.position || (emp.roles && emp.roles.length > 0)) && (
{emp.employee_profile?.position || (emp.roles?.[0]?.name === 'Main Contractor Admin' ? 'Contractor Admin' : emp.roles?.[0]?.name)}
)}
); })}
)}
); } interface ParentProject { id: number; ulid: string; name: string; code: string; project_type?: string; parent_project?: { id: number; ulid: string; name: string; code: string } | null; } function ParentProjectLookup({ projects, selectedId, onSelect, disabled }: { projects: ParentProject[], selectedId: string, onSelect: (id: string) => void, disabled?: boolean }) { const [open, setOpen] = useState(false); const [search, setSearch] = useState(''); const [tempSelectedId, setTempSelectedId] = useState(selectedId); const filteredProjects = useMemo(() => { if (!search) return projects; const lowerSearch = search.toLowerCase(); return projects.filter(p => p.name.toLowerCase().includes(lowerSearch) || p.code.toLowerCase().includes(lowerSearch) ); }, [projects, search]); const handleConfirm = () => { onSelect(tempSelectedId); setOpen(false); }; const handleOpenChange = (newOpen: boolean) => { setOpen(newOpen); if (newOpen) { setTempSelectedId(selectedId); setSearch(''); } }; const selectedProject = projects.find(p => p.ulid === selectedId); return ( <> Select Parent Project
setSearch(e.target.value)} className="pl-9 bg-background" />
{filteredProjects.length === 0 ? (
No active projects found matching your search.
) : (
{filteredProjects.map((proj) => { const isSelected = tempSelectedId === proj.ulid; return (
setTempSelectedId(proj.ulid)} className={`flex items-start gap-3 p-3 rounded-lg border cursor-pointer transition-colors ${ isSelected ? 'border-primary bg-primary/5 ring-1 ring-primary' : 'border-border hover:bg-accent/50' }`} >
{proj.code} {isSelected && }

{proj.name}

{proj.project_type === 'extension' && proj.parent_project && (
Ext of {proj.parent_project.code} {proj.parent_project.name}
)}
); })}
)}
); } export interface ProjectClassificationItem { id: number; code?: string; name: string; description?: string; } export const DEFAULT_PROJECT_CLASSIFICATIONS: ProjectClassificationItem[] = [ { id: 1, code: 'ROAD-HWY', name: 'Road, Highway, Pavement, Railways, Airport Horizontal Structures and Bridges' }, { id: 2, code: 'IRR-FLD', name: 'Irrigation and Flood Control' }, { id: 3, code: 'DAM-RES', name: 'Dam, Reservoir, and Tunneling' }, { id: 4, code: 'WAT-SUP', name: 'Water Supply' }, { id: 5, code: 'PORT-ENG', name: 'Port, Harbor and Offshore Engineering' }, { id: 6, code: 'BLD-PLANT', name: 'Building and Industrial Plant' }, { id: 7, code: 'SEW-TREAT', name: 'Sewerage Treatment / Disposal Plant' }, { id: 8, code: 'WTR-TREAT', name: 'Water Treatment Plant and System' }, { id: 9, code: 'REC-PARK', name: 'Park, Playground and Recreational Work' }, { id: 10, code: 'ELEC-WRK', name: 'Electrical Work' }, ]; export interface ProjectFormData { name: string; client_name: string; location: string; start_date: string; target_end_date: string; contract_duration: string; // Additional details description: string; pm_id: string; contract_value: string; project_type: string; classifications?: string[]; parent_project_id: string; is_unprofitable: boolean; } interface Props { data: ProjectFormData; setData: (key: K, value: ProjectFormData[K]) => void; errors: Partial>; employees: Employee[]; projects?: { id: number; ulid: string; name: string; code: string }[]; classifications?: ProjectClassificationItem[]; isLocked?: boolean; } export function ProjectForm({ data, setData, errors, employees, projects = [], classifications = [], isLocked = false }: Props) { const [showAdvanced, setShowAdvanced] = useState(true); const activeClassificationOptions = useMemo(() => { return classifications && classifications.length > 0 ? classifications : DEFAULT_PROJECT_CLASSIFICATIONS; }, [classifications]); const employeeSelectItems = useMemo( () => employees.map(e => ({ value: e.ulid, label: e.name })), [employees], ); // Auto-calculate contract duration when both dates are set useEffect(() => { if (data.start_date && data.target_end_date) { const start = new Date(data.start_date); const end = new Date(data.target_end_date); const diffMs = end.getTime() - start.getTime(); if (!isNaN(diffMs) && diffMs >= 0) { const days = Math.max(1, Math.round(diffMs / (1000 * 60 * 60 * 24)) + 1); // inclusive of start & end setData('contract_duration', String(days)); } else if (diffMs < 0) { setData('contract_duration', '0'); } } }, [data.start_date, data.target_end_date]); const handleProjectTypeChange = (val: string | null) => { const typeVal = val || 'standard'; setData('project_type', typeVal); if (typeVal === 'special') { setData('is_unprofitable', true); } else if (typeVal === 'standard') { setData('is_unprofitable', false); } if (typeVal !== 'extension') { setData('parent_project_id', ''); } }; const toggleClassification = (name: string) => { if (isLocked) return; const current = Array.isArray(data.classifications) ? [...data.classifications] : []; const index = current.indexOf(name); if (index > -1) { current.splice(index, 1); } else { current.push(name); } setData('classifications', current); }; return (
{/* Primary Fields — 1.1 to 1.7 */} Project Core Parameters {/* 1.1 Project Name */}
setData('name', e.target.value)} placeholder="e.g., Construction of FGEN-PPA Access Road" disabled={isLocked} className="h-10 text-sm border-slate-200" /> {errors.name &&

{errors.name}

}
{/* Project Classification Multi-Tag Checkbox Group */}
|

Select one or more construction classification tags applicable to this project (minimum 1 required):

{activeClassificationOptions.map((item, idx) => { const isChecked = Array.isArray(data.classifications) && data.classifications.includes(item.name); return (
toggleClassification(item.name)} className={`flex items-start gap-3 p-3 rounded-lg border text-left transition-all select-none cursor-pointer ${ isChecked ? 'bg-emerald-50/90 border-emerald-300 ring-1 ring-emerald-400/40 text-emerald-950 shadow-2xs' : 'bg-white hover:bg-slate-50 border-slate-200/80 text-slate-700' } ${isLocked ? 'opacity-60 cursor-not-allowed' : ''}`} >
{}} // Handled by parent container click disabled={isLocked} className="h-4 w-4 rounded border-slate-300 text-emerald-600 focus:ring-emerald-500 cursor-pointer" />
{idx + 1} {item.name}
); })}
{errors.classifications &&

{errors.classifications}

}
{/* Project Type & Scope Selection */}
{errors.project_type &&

{errors.project_type}

}
{data.project_type === 'extension' && (
setData('parent_project_id', val || '')} disabled={isLocked} />
{errors.parent_project_id &&

{errors.parent_project_id}

}
)}
{/* Unprofitable Flag Checkbox */}
setData('is_unprofitable', e.target.checked)} className="rounded border-slate-300 text-amber-600 focus:ring-amber-500 h-4 w-4 cursor-pointer" disabled={isLocked} />
Displays budget warning highlights on procurement approval panels and executive dashboards.
{/* 1.2 Project Location & 1.3 Client */}
setData('location', e.target.value)} placeholder="e.g., Bolbok, Batangas City" disabled={isLocked} className="h-10 text-sm border-slate-200" /> {errors.location &&

{errors.location}

}
setData('client_name', e.target.value)} placeholder="e.g., First Gen Corporation" disabled={isLocked} className="h-10 text-sm border-slate-200" /> {errors.client_name &&

{errors.client_name}

}
{/* 1.4 Main Contractor — Hard-coded */}
{MAIN_CONTRACTOR}
{/* 1.5 & 1.6 — Start Date / Project Completion */}
setData('start_date', e.target.value)} disabled={isLocked} className="h-10 text-sm border-slate-200" /> {errors.start_date &&

{errors.start_date}

}
setData('target_end_date', e.target.value)} disabled={isLocked} className="h-10 text-sm border-slate-200" /> {errors.target_end_date &&

{errors.target_end_date}

}
{/* 1.7 Contract Duration */}
setData('contract_duration', e.target.value)} className="max-w-[160px] h-10 text-sm border-slate-200 bg-slate-50/50 font-semibold" placeholder="0" disabled={isLocked} /> calendar days
{errors.contract_duration &&

{errors.contract_duration}

}
{/* Additional Project Parameters */} setShowAdvanced(!showAdvanced)} >
Additional Project Parameters
{showAdvanced && ( {/* Description */}