Add bill of materials after job creation

Add functionality to add bill of materials to a job after it has been created.
This commit is contained in:
gpt-engineer-app[bot]
2025-07-09 12:56:32 +00:00
committed by PhatPhuckDave
parent 260c1c0af3
commit dc5b91d104
2 changed files with 45 additions and 6 deletions

View File

@@ -1,4 +1,3 @@
import React, { useState } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
@@ -12,7 +11,7 @@ import { parseISKAmount } from '@/utils/priceUtils';
interface JobFormProps {
job?: IndJob;
onSubmit: (job: IndJobRecordNoId) => void;
onSubmit: (job: IndJobRecordNoId, billOfMaterials?: { name: string; quantity: number }[]) => void;
onCancel: () => void;
}
@@ -26,9 +25,13 @@ const JobForm: React.FC<JobFormProps> = ({ job, onSubmit, onCancel }) => {
});
const [jobDump, setJobDump] = useState('');
const [parsedBillOfMaterials, setParsedBillOfMaterials] = useState<{ name: string; quantity: number }[]>([]);
const parseJobDump = (dumpText: string) => {
if (!dumpText.trim()) return;
if (!dumpText.trim()) {
setParsedBillOfMaterials([]);
return;
}
const lines = dumpText.trim().split('\n').filter(line => line.trim());
@@ -54,6 +57,26 @@ const JobForm: React.FC<JobFormProps> = ({ job, onSubmit, onCancel }) => {
projectedCost: cost,
projectedRevenue: revenue
}));
// Parse BOM starting from line 4 (after empty line)
const bomLines = lines.slice(4); // Skip first 3 lines and empty line
const billOfMaterials: { name: string; quantity: number }[] = [];
for (const line of bomLines) {
const trimmedLine = line.trim();
if (trimmedLine) {
const lastSpaceIndex = trimmedLine.lastIndexOf(' ');
if (lastSpaceIndex > 0) {
const materialName = trimmedLine.substring(0, lastSpaceIndex).trim();
const materialQuantity = parseInt(trimmedLine.substring(lastSpaceIndex + 1).trim()) || 0;
if (materialName && materialQuantity > 0) {
billOfMaterials.push({ name: materialName, quantity: materialQuantity });
}
}
}
}
setParsedBillOfMaterials(billOfMaterials);
}
}
};
@@ -73,7 +96,7 @@ const JobForm: React.FC<JobFormProps> = ({ job, onSubmit, onCancel }) => {
status: formData.status,
projectedCost: formData.projectedCost,
projectedRevenue: formData.projectedRevenue
});
}, parsedBillOfMaterials.length > 0 ? parsedBillOfMaterials : undefined);
};
const statusOptions = Object.values(IndJobStatusOptions);
@@ -175,6 +198,11 @@ const JobForm: React.FC<JobFormProps> = ({ job, onSubmit, onCancel }) => {
className="bg-gray-800 border-gray-600 text-white min-h-[120px]"
rows={6}
/>
{parsedBillOfMaterials.length > 0 && (
<div className="text-sm text-gray-400">
<p>Parsed {parsedBillOfMaterials.length} materials from dump</p>
</div>
)}
</div>
<div className="flex gap-2 pt-4">

View File

@@ -93,9 +93,20 @@ const Index = () => {
const { totalJobs, totalProfit, totalRevenue, calculateJobRevenue, calculateJobProfit } = useJobMetrics(regularJobs);
const handleCreateJob = async (jobData: IndJobRecordNoId) => {
const handleCreateJob = async (jobData: IndJobRecordNoId, billOfMaterials?: { name: string; quantity: number }[]) => {
try {
await createJob(jobData);
const newJob = await createJob(jobData);
// If we have bill of materials from the job dump, add them to the newly created job
if (billOfMaterials && billOfMaterials.length > 0) {
const billItems = billOfMaterials.map(item => ({
name: item.name,
quantity: item.quantity,
unitPrice: 0
}));
await createMultipleBillItems(newJob.id, billItems, 'billOfMaterials');
}
setShowJobForm(false);
} catch (error) {
console.error('Error creating job:', error);