import { useState, useMemo } from 'react'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/Components/ui/dialog'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/Components/ui/tabs'; import { Input } from '@/Components/ui/input'; import { Button } from '@/Components/ui/button'; import { Badge } from '@/Components/ui/badge'; import { Search, Users, Check, Layers, Plus, HardHat, Wrench, Zap, Hammer, Paintbrush, Pipette } from 'lucide-react'; export interface Skill { id: number; ulid: string; name: string; } export interface Labor { id: number; ulid: string; name: string; category: 'skilled' | 'unskilled'; hourly_rate: string; skills: Skill[]; } export interface LaborBundleOption { id: string; name: string; job_type: string; description: string; category: string; badge_color?: string; items: { labor_name: string; category: 'skilled' | 'unskilled'; default_hours?: number; estimated_hourly_rate?: number; rate_per_sqm: number; }[]; } export const PREDEFINED_LABOR_BUNDLES: LaborBundleOption[] = [ { id: 'excavation-crew', name: 'Excavation & Earthworks Crew Package', job_type: 'Excavation & Earthworks', category: 'Earthworks & Foundation', badge_color: 'bg-amber-100 text-amber-800 border-amber-200', description: 'Complete manpower package for site excavation, trenching, soil hauling, and ground leveling.', items: [ { labor_name: 'Excavator Operator', category: 'skilled', rate_per_sqm: 80 }, { labor_name: 'Heavy Equipment Hand', category: 'skilled', rate_per_sqm: 40 }, { labor_name: 'Earthwork Laborer', category: 'unskilled', rate_per_sqm: 30 }, { labor_name: 'Flagman & Site Safety', category: 'unskilled', rate_per_sqm: 15 }, ] }, { id: 'steelworks-crew', name: 'Steelworks & Rebar Crew Package', job_type: 'Steelworks & Structural Rebar', category: 'Structural & Reinforcement', badge_color: 'bg-slate-100 text-slate-800 border-slate-200', description: 'Specialized crew for rebar cutting, bending, column/beam tying, and structural steel welding.', items: [ { labor_name: 'Master Welder', category: 'skilled', rate_per_sqm: 110 }, { labor_name: 'Steel Fixer', category: 'skilled', rate_per_sqm: 95 }, { labor_name: 'Rebar Craftsman', category: 'skilled', rate_per_sqm: 75 }, { labor_name: 'Rigging Helper', category: 'unskilled', rate_per_sqm: 40 }, ] }, { id: 'electricity-crew', name: 'Electricity & MEP Rough-In Package', job_type: 'Electrical & MEP', category: 'Electrical & Utility Systems', badge_color: 'bg-yellow-100 text-yellow-800 border-yellow-200', description: 'Crew for main feeder line installation, conduit laying, breaker panel wiring, and rough-in.', items: [ { labor_name: 'Master Electrician', category: 'skilled', rate_per_sqm: 90 }, { labor_name: 'Journeyman Electrician', category: 'skilled', rate_per_sqm: 75 }, { labor_name: 'Cable Puller', category: 'unskilled', rate_per_sqm: 45 }, { labor_name: 'Conduit Installer', category: 'skilled', rate_per_sqm: 40 }, ] }, { id: 'masonry-crew', name: 'Masonry & Concrete Pouring Package', job_type: 'Masonry & Civil Works', category: 'Masonry & Concrete', badge_color: 'bg-emerald-100 text-emerald-800 border-emerald-200', description: 'Full manpower setup for CHB block laying, wall plastering, slab pouring, and concrete finishing.', items: [ { labor_name: 'Master Mason', category: 'skilled', rate_per_sqm: 110 }, { labor_name: 'Concrete Finisher', category: 'skilled', rate_per_sqm: 85 }, { labor_name: 'Masonry Helper', category: 'unskilled', rate_per_sqm: 55 }, { labor_name: 'Mixer Attendant', category: 'unskilled', rate_per_sqm: 30 }, ] }, { id: 'plumbing-crew', name: 'Plumbing & Piping Package', job_type: 'Plumbing & Sanitary', category: 'Plumbing & Piping', badge_color: 'bg-blue-100 text-blue-800 border-blue-200', description: 'Specialized crew for potable water supply distribution, DWV sanitary piping, and fixture rough-in.', items: [ { labor_name: 'Master Plumber', category: 'skilled', rate_per_sqm: 95 }, { labor_name: 'Pipefitter', category: 'skilled', rate_per_sqm: 75 }, { labor_name: 'Drainage Installer', category: 'skilled', rate_per_sqm: 50 }, { labor_name: 'Plumbing Helper', category: 'unskilled', rate_per_sqm: 30 }, ] }, { id: 'carpentry-crew', name: 'Carpentry & Formwork Package', job_type: 'Carpentry & Formwork', category: 'Formwork & Framing', badge_color: 'bg-orange-100 text-orange-800 border-orange-200', description: 'Team for column/beam formwork fabrication, scaffolding erection, and temporary shoring.', items: [ { labor_name: 'Master Carpenter', category: 'skilled', rate_per_sqm: 100 }, { labor_name: 'Formwork Installer', category: 'skilled', rate_per_sqm: 85 }, { labor_name: 'Scaffold Erector', category: 'skilled', rate_per_sqm: 55 }, { labor_name: 'Carpentry Helper', category: 'unskilled', rate_per_sqm: 35 }, ] }, { id: 'painting-crew', name: 'Painting & Architectural Finishing Package', job_type: 'Painting & Finishing', category: 'Architectural & Finishing', badge_color: 'bg-purple-100 text-purple-800 border-purple-200', description: 'Crew for surface preparation, skimcoating, primer application, and topcoat architectural painting.', items: [ { labor_name: 'Lead Painter', category: 'skilled', rate_per_sqm: 85 }, { labor_name: 'Surface Applicator', category: 'skilled', rate_per_sqm: 65 }, { labor_name: 'Sanding & Skimcoat Helper', category: 'unskilled', rate_per_sqm: 40 }, ] } ]; interface Props { open: boolean; onOpenChange: (open: boolean) => void; labors: Labor[]; onSelectLabor: (labor: Labor) => void; onAddLaborBundle?: (bundle: LaborBundleOption, crewMultiplier: number) => void; selectedLaborUlid?: string; } export default function LaborLookupModal({ open, onOpenChange, labors, onSelectLabor, onAddLaborBundle, selectedLaborUlid }: Props) { const [search, setSearch] = useState(''); const [categoryFilter, setCategoryFilter] = useState<'all' | 'skilled' | 'unskilled'>('all'); const [crewMultiplier, setCrewMultiplier] = useState>({}); const formatCurrency = (v: string | number) => { return new Intl.NumberFormat('en-PH', { style: 'currency', currency: 'PHP' }).format(Number(v)); }; const handleOpenChange = (isOpen: boolean) => { if (!isOpen) { setSearch(''); setCategoryFilter('all'); } onOpenChange(isOpen); }; const filteredLabors = useMemo(() => { return labors.filter(labor => { if (categoryFilter !== 'all' && labor.category !== categoryFilter) { return false; } if (!search) return true; const query = search.toLowerCase(); const matchesName = labor.name.toLowerCase().includes(query); const matchesCategory = labor.category.toLowerCase().includes(query); const matchesSkills = labor.skills && labor.skills.some(skill => skill.name.toLowerCase().includes(query) ); return matchesName || matchesCategory || matchesSkills; }); }, [labors, search, categoryFilter]); const filteredBundles = useMemo(() => { if (!search) return PREDEFINED_LABOR_BUNDLES; const query = search.toLowerCase(); return PREDEFINED_LABOR_BUNDLES.filter(b => b.name.toLowerCase().includes(query) || b.job_type.toLowerCase().includes(query) || b.description.toLowerCase().includes(query) || b.items.some(item => item.labor_name.toLowerCase().includes(query)) ); }, [search]); const handleAddBundleClick = (bundle: LaborBundleOption) => { const mult = crewMultiplier[bundle.id] || 1; if (onAddLaborBundle) { onAddLaborBundle(bundle, mult); } else { // Fallback: select first trade in bundle const matched = labors.find(l => l.name.toLowerCase().includes(bundle.items[0]?.labor_name.toLowerCase() || '')); if (matched) { onSelectLabor(matched); } } }; return ( Labor Manpower Catalog Browse single laborer trades or select predefined job bundles (excavation, steelworks, electricity, masonry, plumbing, etc.) for quick crew allocation.
Single Laborers & Trades ({filteredLabors.length}) Job Bundles & Crew Packages ({filteredBundles.length})
setSearch(e.target.value)} />
{/* TAB 1: SINGLE LABORERS */} {/* Category Filters */}
Filter Category:
{filteredLabors.length === 0 ? (
No labor records found matching "{search}".
) : (
{filteredLabors.map(labor => { const isSelected = selectedLaborUlid === labor.ulid; return ( ); })}
Labor Trade Record Category Skills / Specialties Hourly Rate Action
{labor.name} {isSelected && ( Selected )}
{labor.category}
{labor.skills && labor.skills.length > 0 ? ( labor.skills.map(skill => ( {skill.name} )) ) : ( Standard Construction Trade )}
{formatCurrency(labor.hourly_rate)}/hr
)}
{/* TAB 2: JOB BUNDLES & CREW PACKAGES */}

Predefined Job Manpower Assemblies & Crews

Instantly allocate complete specialized teams for specific construction activities (excavation, steelworks, electricity, masonry, plumbing, etc.).

{filteredBundles.map(bundle => { const sqmArea = crewMultiplier[bundle.id] || 10; const ratePerSqm = bundle.items.reduce((sum, item) => sum + (item.rate_per_sqm || item.estimated_hourly_rate || 0), 0); const totalEstCost = ratePerSqm * sqmArea; return (
{bundle.job_type} Est. {formatCurrency(ratePerSqm)} / m²

{bundle.name}

{bundle.description}

Crew Breakdown ({bundle.items.length} Trades): Total: {formatCurrency(totalEstCost)} ({sqmArea} m²)

{bundle.items.map((item, idx) => (
{item.labor_name} {formatCurrency(item.rate_per_sqm || item.estimated_hourly_rate || 0)} / m²
))}
Target Area:
setCrewMultiplier({ ...crewMultiplier, [bundle.id]: Math.max(1, parseInt(e.target.value) || 1) })} className="w-20 h-8 text-center text-xs font-mono font-bold" />
); })}
); }