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 { Card, CardContent, CardHeader } from '@/components/ui/card';
|
||||||
import { IndJob } from '@/lib/types';
|
import { IndJob } from '@/lib/types';
|
||||||
import { getStatusBackgroundColor } from '@/utils/jobStatusUtils';
|
import { getStatusBackgroundColor } from '@/utils/jobStatusUtils';
|
||||||
|
import { jobNeedsAttention, getAttentionGlowClasses } from '@/utils/jobAttentionUtils';
|
||||||
import JobCardHeader from './JobCardHeader';
|
import JobCardHeader from './JobCardHeader';
|
||||||
import JobCardDetails from './JobCardDetails';
|
import JobCardDetails from './JobCardDetails';
|
||||||
import JobCardMetrics from './JobCardMetrics';
|
import JobCardMetrics from './JobCardMetrics';
|
||||||
@@ -25,6 +26,7 @@ const JobCard: React.FC<JobCardProps> = ({
|
|||||||
isTracked = false
|
isTracked = false
|
||||||
}) => {
|
}) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const needsAttention = jobNeedsAttention(job);
|
||||||
|
|
||||||
const handleCardClick = (e: React.MouseEvent) => {
|
const handleCardClick = (e: React.MouseEvent) => {
|
||||||
const target = e.target as HTMLElement;
|
const target = e.target as HTMLElement;
|
||||||
@@ -39,7 +41,7 @@ const JobCard: React.FC<JobCardProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<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}
|
onClick={handleCardClick}
|
||||||
>
|
>
|
||||||
<CardHeader className="flex-shrink-0">
|
<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