// ================================================================ // frontend/src/components/procurement/ProcurementPlanCard.tsx // ================================================================ /** * Procurement Plan Card Component * Displays a procurement plan with key information and actions */ import React from 'react'; import { Card } from '@/components/ui/Card'; import { Button } from '@/components/ui/Button'; import type { ProcurementPlan } from '@/api/types/procurement'; import { PlanStatus, Priority } from '@/api/types/procurement'; export interface ProcurementPlanCardProps { plan: ProcurementPlan; onViewDetails?: (planId: string) => void; onUpdateStatus?: (planId: string, status: string) => void; showActions?: boolean; } export const ProcurementPlanCard: React.FC = ({ plan, onViewDetails, onUpdateStatus, showActions = false, }) => { const getStatusColor = (status: string) => { const colors = { [PlanStatus.DRAFT]: 'bg-gray-100 text-gray-800', [PlanStatus.PENDING_APPROVAL]: 'bg-yellow-100 text-yellow-800', [PlanStatus.APPROVED]: 'bg-blue-100 text-blue-800', [PlanStatus.IN_EXECUTION]: 'bg-green-100 text-green-800', [PlanStatus.COMPLETED]: 'bg-green-100 text-green-800', [PlanStatus.CANCELLED]: 'bg-red-100 text-red-800', }; return colors[status as keyof typeof colors] || 'bg-gray-100 text-gray-800'; }; const getPriorityColor = (priority: string) => { const colors = { [Priority.CRITICAL]: 'text-red-600', [Priority.HIGH]: 'text-orange-600', [Priority.NORMAL]: 'text-blue-600', [Priority.LOW]: 'text-gray-600', }; return colors[priority as keyof typeof colors] || 'text-gray-600'; }; const getRiskColor = (risk: string) => { const colors = { 'critical': 'text-red-600', 'high': 'text-orange-600', 'medium': 'text-yellow-600', 'low': 'text-green-600', }; return colors[risk as keyof typeof colors] || 'text-gray-600'; }; const formatCurrency = (amount: number) => { return new Intl.NumberFormat('es-ES', { style: 'currency', currency: 'EUR' }).format(amount); }; const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString('es-ES', { day: 'numeric', month: 'short', year: 'numeric' }); }; const nextStatusOptions = () => { const options = { [PlanStatus.DRAFT]: [PlanStatus.PENDING_APPROVAL, PlanStatus.CANCELLED], [PlanStatus.PENDING_APPROVAL]: [PlanStatus.APPROVED, PlanStatus.CANCELLED], [PlanStatus.APPROVED]: [PlanStatus.IN_EXECUTION, PlanStatus.CANCELLED], [PlanStatus.IN_EXECUTION]: [PlanStatus.COMPLETED, PlanStatus.CANCELLED], [PlanStatus.COMPLETED]: [], [PlanStatus.CANCELLED]: [], }; return options[plan.status as keyof typeof options] || []; }; return (
{/* Header */}

{plan.plan_number}

{plan.status.replace('_', ' ').toUpperCase()}

Plan Date: {formatDate(plan.plan_date)} | Period: {formatDate(plan.plan_period_start)} - {formatDate(plan.plan_period_end)}

{plan.priority.toUpperCase()} Priority
{plan.supply_risk_level.toUpperCase()} Risk
{/* Key Metrics */}
{plan.total_requirements}
Requirements
{formatCurrency(plan.total_estimated_cost)}
Est. Cost
{plan.primary_suppliers_count}
Suppliers
{plan.safety_stock_buffer}%
Safety Buffer
{/* Requirements Summary */} {plan.requirements && plan.requirements.length > 0 && (

Top Requirements ({plan.requirements.length} total)

{plan.requirements.slice(0, 3).map((req) => (
{req.product_name}
{req.net_requirement} {req.unit_of_measure} {req.priority}
))} {plan.requirements.length > 3 && (
+{plan.requirements.length - 3} more requirements
)}
)} {/* Performance Metrics */} {(plan.fulfillment_rate || plan.on_time_delivery_rate) && (
{plan.fulfillment_rate && ( Fulfillment: {plan.fulfillment_rate}% )} {plan.on_time_delivery_rate && ( On-time: {plan.on_time_delivery_rate}% )}
)} {/* Actions */} {showActions && (
{nextStatusOptions().map((status) => ( ))}
)} {/* Special Requirements */} {plan.special_requirements && (
Special Requirements

{plan.special_requirements}

)}
); };