// ================================================================ // frontend/src/components/procurement/CriticalRequirements.tsx // ================================================================ /** * Critical Requirements Component * Displays urgent procurement requirements that need immediate attention */ import React from 'react'; import type { ProcurementRequirement } from '@/api/types/procurement'; import { Priority, RequirementStatus } from '@/api/types/procurement'; export interface CriticalRequirementsProps { requirements: ProcurementRequirement[]; onViewDetails?: (requirementId: string) => void; onUpdateStatus?: (requirementId: string, status: string) => void; } export const CriticalRequirements: React.FC = ({ requirements, onViewDetails, onUpdateStatus, }) => { const formatCurrency = (amount: number | undefined) => { if (!amount) return 'N/A'; return new Intl.NumberFormat('es-ES', { style: 'currency', currency: 'EUR' }).format(amount); }; const formatDate = (dateString: string) => { const date = new Date(dateString); const today = new Date(); const diffTime = date.getTime() - today.getTime(); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); if (diffDays < 0) { return `Overdue by ${Math.abs(diffDays)} days`; } else if (diffDays === 0) { return 'Due today'; } else if (diffDays === 1) { return 'Due tomorrow'; } else { return `Due in ${diffDays} days`; } }; const getStatusColor = (status: string) => { const colors = { [RequirementStatus.PENDING]: 'bg-yellow-100 text-yellow-800', [RequirementStatus.APPROVED]: 'bg-blue-100 text-blue-800', [RequirementStatus.ORDERED]: 'bg-purple-100 text-purple-800', [RequirementStatus.PARTIALLY_RECEIVED]: 'bg-orange-100 text-orange-800', [RequirementStatus.RECEIVED]: 'bg-green-100 text-green-800', [RequirementStatus.CANCELLED]: 'bg-red-100 text-red-800', }; return colors[status as keyof typeof colors] || 'bg-gray-100 text-gray-800'; }; const getDueDateColor = (dateString: string) => { const date = new Date(dateString); const today = new Date(); const diffTime = date.getTime() - today.getTime(); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); if (diffDays < 0) return 'text-red-600 font-medium'; // Overdue if (diffDays <= 1) return 'text-orange-600 font-medium'; // Due soon return 'text-gray-600'; }; const getStockLevelColor = (current: number, needed: number) => { const ratio = current / needed; if (ratio <= 0.1) return 'text-red-600 font-medium'; // Critical if (ratio <= 0.3) return 'text-orange-600 font-medium'; // Low return 'text-gray-600'; }; if (requirements.length === 0) { return (

No critical requirements at this time

); } return (
{requirements.map((requirement) => (

{requirement.product_name}

{requirement.status.replace('_', ' ').toUpperCase()} CRITICAL
Required:
{requirement.net_requirement} {requirement.unit_of_measure}
Current Stock:
{requirement.current_stock_level} {requirement.unit_of_measure}
Due Date:
{formatDate(requirement.required_by_date)}
Est. Cost:
{formatCurrency(requirement.estimated_total_cost)}
{requirement.supplier_name && (
Supplier: {requirement.supplier_name} {requirement.supplier_lead_time_days && ( ({requirement.supplier_lead_time_days} days lead time) )}
)} {requirement.special_requirements && (
Special Requirements:

{requirement.special_requirements}

)}
{requirement.status === RequirementStatus.PENDING && ( )} {requirement.status === RequirementStatus.APPROVED && ( )}
{/* Progress indicator for ordered items */} {requirement.status === RequirementStatus.ORDERED && requirement.ordered_quantity > 0 && (
Order Progress {requirement.received_quantity} / {requirement.ordered_quantity} {requirement.unit_of_measure}
{requirement.expected_delivery_date && (
Expected: {formatDate(requirement.expected_delivery_date)}
)}
)}
))}
); };