Files
GSB-Construction/Modules/ProjectManagement/resources/js/Pages/Projects/Wizard/Step3Materials.tsx
Ajjj b98951f65f
Some checks failed
Tests / PHP 8.3 (push) Has been cancelled
Tests / PHP 8.4 (push) Has been cancelled
Tests / PHP 8.5 (push) Has been cancelled
feat: decompose project god components, add database performance indexes, and isolate contractor admin retention
2026-08-14 16:20:15 +08:00

119 lines
7.0 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 { Badge } from '@/Components/ui/badge';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/Components/ui/table';
import { Plus, Trash2, ClipboardList, ChevronLeft, ChevronRight } from 'lucide-react';
interface Step3MaterialsProps {
localEstimates: any[];
setLocalEstimates: React.Dispatch<React.SetStateAction<any[]>>;
calculatedMaterialsCost: number;
formatCurrency: (v: string | number) => string;
onOpenCatalog: () => void;
handleBack: () => void;
handleSaveEstimates: () => void;
}
export default function Step3Materials({
localEstimates,
setLocalEstimates,
calculatedMaterialsCost,
formatCurrency,
onOpenCatalog,
handleBack,
handleSaveEstimates
}: Step3MaterialsProps) {
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 3: Materials Estimation</CardTitle>
<CardDescription className="text-xs">Estimate the types and quantities of materials required for this project.</CardDescription>
</div>
<Button onClick={onOpenCatalog} className="bg-emerald-600 hover:bg-emerald-700 text-white font-medium">
<Plus className="mr-2 h-4 w-4" /> Add Materials
</Button>
</CardHeader>
{localEstimates.length === 0 ? (
<div className="py-12 text-center border border-dashed border-slate-200 rounded-xl bg-slate-50/50">
<ClipboardList className="mx-auto h-8 w-8 text-slate-400" />
<p className="text-xs italic text-slate-500 mt-2">No material estimates added yet. Use "Add Materials" to query standard materials.</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">Material Name</TableHead>
<TableHead className="font-semibold text-slate-700">Unit</TableHead>
<TableHead className="font-semibold text-slate-700 w-32">Estimated Qty</TableHead>
<TableHead className="font-semibold text-slate-700 w-36">Est. Unit Cost (PHP)</TableHead>
<TableHead className="font-semibold text-slate-700 text-right w-36">Total Cost</TableHead>
<TableHead className="text-right w-16"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{localEstimates.map((item, idx) => {
const total = Number(item.estimated_qty || 0) * Number(item.unit_cost || 0);
return (
<TableRow key={idx} className="hover:bg-slate-50/20 transition-colors">
<TableCell className="font-medium text-slate-900">{item.material_name}</TableCell>
<TableCell><Badge variant="outline" className="bg-slate-50 text-slate-650 font-normal">{item.unit}</Badge></TableCell>
<TableCell>
<Input
type="number"
value={item.estimated_qty}
onChange={e => {
const copy = [...localEstimates];
copy[idx].estimated_qty = e.target.value;
setLocalEstimates(copy);
}}
className="h-8 text-xs border-slate-200"
/>
</TableCell>
<TableCell>
<Input
type="number"
value={item.unit_cost}
onChange={e => {
const copy = [...localEstimates];
copy[idx].unit_cost = e.target.value;
setLocalEstimates(copy);
}}
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={() => setLocalEstimates(localEstimates.filter((_, i) => i !== 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 Materials Cost Estimate</TableCell>
<TableCell className="font-mono font-bold text-slate-900 text-right">{formatCurrency(calculatedMaterialsCost)}</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={handleSaveEstimates} 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>
);
}