155 lines
9.6 KiB
TypeScript
155 lines
9.6 KiB
TypeScript
import React from 'react';
|
|
import { CardHeader, CardTitle, CardDescription } from '@/Components/ui/card';
|
|
import { Button } from '@/Components/ui/button';
|
|
import { Input } from '@/Components/ui/input';
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/Components/ui/table';
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/Components/ui/select';
|
|
import { Plus, Trash2, Wrench, ChevronLeft, ChevronRight } from 'lucide-react';
|
|
import { ProjectWizardData, Equipment } from '../../../types/project-wizard';
|
|
|
|
interface Step5EquipmentProps {
|
|
project: ProjectWizardData;
|
|
localEquipment: any[];
|
|
equipments: Equipment[];
|
|
addEquipmentAllocation: () => void;
|
|
removeEquipmentAllocation: (idx: number) => void;
|
|
updateEquipmentAllocation: (idx: number, field: string, val: string) => void;
|
|
calculatedEquipmentCost: number;
|
|
formatCurrency: (v: string | number) => string;
|
|
onOpenEquipmentLookup: (idx: number) => void;
|
|
handleBack: () => void;
|
|
handleSaveEquipment: () => void;
|
|
}
|
|
|
|
export default function Step5Equipment({
|
|
project,
|
|
localEquipment,
|
|
equipments,
|
|
addEquipmentAllocation,
|
|
removeEquipmentAllocation,
|
|
updateEquipmentAllocation,
|
|
calculatedEquipmentCost,
|
|
formatCurrency,
|
|
onOpenEquipmentLookup,
|
|
handleBack,
|
|
handleSaveEquipment
|
|
}: Step5EquipmentProps) {
|
|
return (
|
|
<div className="p-6 space-y-6">
|
|
<CardHeader className="p-0 pb-4 border-b border-slate-100 flex flex-row items-center justify-between">
|
|
<div>
|
|
<CardTitle className="text-md font-semibold text-slate-800">Step 5: Equipment & Machinery Allocation</CardTitle>
|
|
<CardDescription className="text-xs">Allocate standard machinery/equipment and estimate total utilization hours required.</CardDescription>
|
|
</div>
|
|
<Button onClick={addEquipmentAllocation} className="bg-emerald-600 hover:bg-emerald-700 text-white font-medium">
|
|
<Plus className="mr-2 h-4 w-4" /> Assign Equipment
|
|
</Button>
|
|
</CardHeader>
|
|
|
|
{localEquipment.length === 0 ? (
|
|
<div className="py-12 text-center border border-dashed border-slate-200 rounded-xl bg-slate-50/50">
|
|
<Wrench className="mx-auto h-8 w-8 text-slate-400" />
|
|
<p className="text-xs italic text-slate-500 mt-2">No equipment assigned yet. Click "Assign Equipment" to allocate machinery to tasks.</p>
|
|
</div>
|
|
) : (
|
|
<div className="border border-slate-200/80 rounded-xl overflow-hidden shadow-sm">
|
|
<Table>
|
|
<TableHeader className="bg-slate-50/60">
|
|
<TableRow>
|
|
<TableHead className="font-semibold text-slate-700">Target Task</TableHead>
|
|
<TableHead className="font-semibold text-slate-700">Equipment / Tool</TableHead>
|
|
<TableHead className="font-semibold text-slate-700 w-36">Hourly Rate</TableHead>
|
|
<TableHead className="font-semibold text-slate-700 w-32">Estimated Hours</TableHead>
|
|
<TableHead className="font-semibold text-slate-700 text-right w-36">Total Equip. Cost</TableHead>
|
|
<TableHead className="text-right w-16"></TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{localEquipment.map((item, idx) => {
|
|
const rateObj = equipments.find(r => r.ulid === item.equipment_ulid);
|
|
const rate = rateObj ? Number(rateObj.hourly_rate) : 0;
|
|
const total = Number(item.estimated_hours || 0) * rate;
|
|
return (
|
|
<TableRow key={idx} className="hover:bg-slate-50/20 transition-colors">
|
|
<TableCell>
|
|
<Select
|
|
value={item.task_ulid}
|
|
onValueChange={val => updateEquipmentAllocation(idx, 'task_ulid', val || '')}
|
|
items={[
|
|
{ value: 'general', label: 'General Project / Unassigned' },
|
|
...project.tasks.map((t: any) => ({ value: t.ulid, label: t.name }))
|
|
]}
|
|
>
|
|
<SelectTrigger className="h-8 text-xs border-slate-200">
|
|
<SelectValue placeholder="Select Task" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="general">General Project / Unassigned</SelectItem>
|
|
{project.tasks.map((t: any) => (
|
|
<SelectItem key={t.ulid} value={t.ulid}>{t.name}</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</TableCell>
|
|
<TableCell>
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
size="sm"
|
|
className="h-8 w-full justify-start text-xs border-slate-200 font-normal hover:bg-slate-50 text-left"
|
|
onClick={() => onOpenEquipmentLookup(idx)}
|
|
>
|
|
{rateObj ? (
|
|
<span className="truncate">
|
|
<span className="font-semibold text-slate-800">{rateObj.name}</span>
|
|
{rateObj.owner_name && (
|
|
<span className="text-slate-500 ml-1">({rateObj.owner_name})</span>
|
|
)}
|
|
</span>
|
|
) : (
|
|
<span className="text-slate-450">Select Equipment...</span>
|
|
)}
|
|
</Button>
|
|
</TableCell>
|
|
<TableCell className="font-mono text-xs text-slate-600">
|
|
{rateObj ? `${formatCurrency(rateObj.hourly_rate)} / hr` : '—'}
|
|
</TableCell>
|
|
<TableCell>
|
|
<Input
|
|
type="number"
|
|
value={item.estimated_hours}
|
|
onChange={e => updateEquipmentAllocation(idx, 'estimated_hours', e.target.value)}
|
|
className="h-8 text-xs border-slate-200"
|
|
/>
|
|
</TableCell>
|
|
<TableCell className="font-mono font-medium text-slate-700 text-right">{formatCurrency(total)}</TableCell>
|
|
<TableCell className="text-right">
|
|
<Button variant="ghost" size="icon" onClick={() => removeEquipmentAllocation(idx)} className="h-8 w-8 text-rose-500 hover:text-rose-700 hover:bg-rose-50">
|
|
<Trash2 className="h-4 w-4" />
|
|
</Button>
|
|
</TableCell>
|
|
</TableRow>
|
|
);
|
|
})}
|
|
<TableRow className="bg-slate-50/40 hover:bg-slate-50/40">
|
|
<TableCell colSpan={4} className="font-semibold text-slate-800">Total Equipment Cost Estimate</TableCell>
|
|
<TableCell className="font-mono font-bold text-slate-900 text-right">{formatCurrency(calculatedEquipmentCost)}</TableCell>
|
|
<TableCell></TableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex justify-between pt-6 border-t border-slate-100">
|
|
<Button variant="outline" onClick={handleBack}>
|
|
<ChevronLeft className="mr-2 h-4 w-4" /> Back
|
|
</Button>
|
|
<Button onClick={handleSaveEquipment} className="bg-emerald-600 hover:bg-emerald-700 text-white font-medium">
|
|
Save & Next <ChevronRight className="ml-2 h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|