Add job card glow effect
Highlight job cards based on completion criteria for "Acquisition" and "Selling" jobs.
This commit is contained in:
@@ -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<JobCardProps> = ({
|
||||
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<JobCardProps> = ({
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={`bg-gray-900 border-gray-700 text-white h-full flex flex-col cursor-pointer hover:bg-gray-800/50 transition-colors ${job.status === 'Tracked' ? 'border-l-4 border-l-cyan-600' : ''} ${getStatusBackgroundColor(job.status)}`}
|
||||
className={`bg-gray-900 border-gray-700 text-white h-full flex flex-col cursor-pointer hover:bg-gray-800/50 transition-colors ${job.status === 'Tracked' ? 'border-l-4 border-l-cyan-600' : ''} ${getStatusBackgroundColor(job.status)} ${needsAttention ? getAttentionGlowClasses() : ''}`}
|
||||
onClick={handleCardClick}
|
||||
>
|
||||
<CardHeader className="flex-shrink-0">
|
||||
|
48
src/utils/jobAttentionUtils.ts
Normal file
48
src/utils/jobAttentionUtils.ts
Normal file
@@ -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<string, number>();
|
||||
job.billOfMaterials.forEach(item => {
|
||||
requiredMaterials.set(item.name, item.quantity);
|
||||
});
|
||||
|
||||
// Create a map of owned materials from expenditures
|
||||
const ownedMaterials = new Map<string, number>();
|
||||
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';
|
||||
}
|
Reference in New Issue
Block a user