// ================================================================ // frontend/src/components/dashboard/ExecutionProgressTracker.tsx // ================================================================ /** * Execution Progress Tracker - Plan vs Actual * * Shows how today's execution is progressing vs the plan. * Helps identify bottlenecks early (e.g., deliveries running late). * * Features: * - Production progress (plan vs actual batches) * - Delivery status (received, pending, overdue) * - Approval tracking * - "What's next" preview * - Status indicators (on_track, at_risk, completed) */ import React from 'react'; import { Package, Truck, CheckCircle, Clock, AlertCircle, TrendingUp, Calendar, } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { formatTime as formatTimeUtil } from '../../utils/date'; // ============================================================ // Types // ============================================================ export interface ProductionProgress { status: 'no_plan' | 'completed' | 'on_track' | 'at_risk'; total: number; completed: number; inProgress: number; pending: number; inProgressBatches?: Array<{ id: string; batchNumber: string; productName: string; quantity: number; actualStartTime: string; estimatedCompletion: string; }>; nextBatch?: { productName: string; plannedStart: string; // ISO datetime batchNumber: string; }; } export interface DeliveryProgress { status: 'no_deliveries' | 'completed' | 'on_track' | 'at_risk'; total: number; received: number; pending: number; overdue: number; } export interface ApprovalProgress { status: 'completed' | 'on_track' | 'at_risk'; pending: number; } export interface ExecutionProgress { production: ProductionProgress; deliveries: DeliveryProgress; approvals: ApprovalProgress; } interface ExecutionProgressTrackerProps { progress: ExecutionProgress | null | undefined; loading?: boolean; } // ============================================================ // Helper Functions // ============================================================ function getStatusColor(status: string): { bg: string; border: string; text: string; icon: string; } { switch (status) { case 'completed': return { bg: 'var(--color-success-50)', border: 'var(--color-success-300)', text: 'var(--color-success-900)', icon: 'var(--color-success-600)', }; case 'on_track': return { bg: 'var(--color-info-50)', border: 'var(--color-info-300)', text: 'var(--color-info-900)', icon: 'var(--color-info-600)', }; case 'at_risk': return { bg: 'var(--color-error-50)', border: 'var(--color-error-300)', text: 'var(--color-error-900)', icon: 'var(--color-error-600)', }; case 'no_plan': case 'no_deliveries': return { bg: 'var(--bg-secondary)', border: 'var(--border-secondary)', text: 'var(--text-secondary)', icon: 'var(--text-tertiary)', }; default: return { bg: 'var(--bg-secondary)', border: 'var(--border-secondary)', text: 'var(--text-primary)', icon: 'var(--text-secondary)', }; } } function formatTime(isoDate: string): string { return formatTimeUtil(isoDate, 'HH:mm'); } // ============================================================ // Sub-Components // ============================================================ interface SectionProps { title: string; icon: React.ElementType; status: string; statusLabel: string; children: React.ReactNode; } function Section({ title, icon: Icon, status, statusLabel, children }: SectionProps) { const colors = getStatusColor(status); return (
{t('dashboard:execution_progress.subtitle')}
{t('dashboard:execution_progress.no_production_plan')}
) : ( <> {/* Progress Bar */}{progress.production.nextBatch.productName}
{progress.production.nextBatch.batchNumber} · {t('dashboard:execution_progress.starts_at')}{' '} {formatTime(progress.production.nextBatch.plannedStart)}
{t('dashboard:execution_progress.no_deliveries_today')}
) : (