diff --git a/src/components/JobCard.tsx b/src/components/JobCard.tsx index 0862c39..7872189 100644 --- a/src/components/JobCard.tsx +++ b/src/components/JobCard.tsx @@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom'; import { Card, CardContent, CardHeader } from '@/components/ui/card'; import { IndJob } from '@/lib/types'; import { getStatusBackgroundColor } from '@/utils/jobStatusUtils'; +import { jobNeedsAttention, getAttentionGlowClasses } from '@/utils/jobAttentionUtils'; import JobCardHeader from './JobCardHeader'; import JobCardDetails from './JobCardDetails'; import JobCardMetrics from './JobCardMetrics'; @@ -25,6 +26,7 @@ const JobCard: React.FC = ({ isTracked = false }) => { const navigate = useNavigate(); + const needsAttention = jobNeedsAttention(job); const handleCardClick = (e: React.MouseEvent) => { const target = e.target as HTMLElement; @@ -39,7 +41,7 @@ const JobCard: React.FC = ({ return ( diff --git a/src/utils/jobAttentionUtils.ts b/src/utils/jobAttentionUtils.ts new file mode 100644 index 0000000..883fa10 --- /dev/null +++ b/src/utils/jobAttentionUtils.ts @@ -0,0 +1,48 @@ + +import { IndJob } from '@/lib/types'; + +export function jobNeedsAttention(job: IndJob): boolean { + // Acquisition jobs need attention when all materials are satisfied + if (job.status === 'Acquisition') { + if (!job.billOfMaterials || job.billOfMaterials.length === 0) { + return false; + } + + // Create a map of required materials from bill of materials + const requiredMaterials = new Map(); + job.billOfMaterials.forEach(item => { + requiredMaterials.set(item.name, item.quantity); + }); + + // Create a map of owned materials from expenditures + const ownedMaterials = new Map(); + job.expenditures?.forEach(transaction => { + const currentOwned = ownedMaterials.get(transaction.itemName) || 0; + ownedMaterials.set(transaction.itemName, currentOwned + transaction.quantity); + }); + + // Check if all materials are satisfied + let allMaterialsSatisfied = true; + requiredMaterials.forEach((required, materialName) => { + const owned = ownedMaterials.get(materialName) || 0; + if (owned < required) { + allMaterialsSatisfied = false; + } + }); + + return allMaterialsSatisfied; + } + + // Selling jobs need attention when sold count reaches produced count + if (job.status === 'Selling') { + const produced = job.produced || 0; + const sold = job.income?.reduce((sum, tx) => sum + tx.quantity, 0) || 0; + return sold >= produced && produced > 0; + } + + return false; +} + +export function getAttentionGlowClasses(): string { + return 'ring-2 ring-yellow-400/50 shadow-lg shadow-yellow-400/20 animate-pulse'; +}