/* * Distribution Tab Component for Enterprise Dashboard * Shows network-wide distribution status, route optimization, and delivery monitoring */ import React, { useEffect, useState } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '../ui/Card'; import { Button } from '../ui/Button'; import { Truck, AlertTriangle, CheckCircle2, Activity, Timer, Map, Route, Package, Clock, Bell, Calendar } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { useDistributionOverview } from '../../api/hooks/useEnterpriseDashboard'; import { useSSEEvents } from '../../hooks/useSSE'; import StatusCard from '../ui/StatusCard/StatusCard'; import { useTenantCurrency } from '../../hooks/useTenantCurrency'; interface DistributionTabProps { tenantId: string; selectedDate: string; onDateChange: (date: string) => void; } const DistributionTab: React.FC = ({ tenantId, selectedDate, onDateChange }) => { const { t } = useTranslation('dashboard'); const { currencySymbol } = useTenantCurrency(); // Get distribution data const { data: distributionOverview, isLoading: isDistributionLoading, error: distributionError } = useDistributionOverview(tenantId, selectedDate, { refetchInterval: 60000, // Refetch every minute enabled: !!tenantId, }); // Real-time SSE events const { events: sseEvents, isConnected: sseConnected } = useSSEEvents({ channels: ['*.alerts', '*.notifications', 'recommendations'] }); // State for real-time delivery status const [deliveryStatus, setDeliveryStatus] = useState({ total: 0, onTime: 0, delayed: 0, inTransit: 0, completed: 0 }); // State for route optimization metrics const [optimizationMetrics, setOptimizationMetrics] = useState({ distanceSaved: 0, timeSaved: 0, fuelSaved: 0, co2Saved: 0 }); // State for real-time events const [recentDeliveryEvents, setRecentDeliveryEvents] = useState([]); // Process SSE events for distribution updates useEffect(() => { if (sseEvents.length === 0) return; // Filter delivery and distribution-related events const deliveryEvents = sseEvents.filter(event => event.event_type.includes('delivery_') || event.event_type.includes('route_') || event.event_type.includes('shipment_') || event.entity_type === 'delivery' || event.entity_type === 'shipment' ); if (deliveryEvents.length === 0) return; // Update delivery status based on events let newStatus = { ...deliveryStatus }; let newMetrics = { ...optimizationMetrics }; deliveryEvents.forEach(event => { switch (event.event_type) { case 'delivery_completed': newStatus.completed += 1; newStatus.inTransit = Math.max(0, newStatus.inTransit - 1); break; case 'delivery_started': case 'delivery_in_transit': newStatus.inTransit += 1; break; case 'delivery_delayed': newStatus.delayed += 1; break; case 'route_optimized': if (event.event_metadata?.distance_saved) { newMetrics.distanceSaved += event.event_metadata.distance_saved; } if (event.event_metadata?.time_saved) { newMetrics.timeSaved += event.event_metadata.time_saved; } if (event.event_metadata?.fuel_saved) { newMetrics.fuelSaved += event.event_metadata.fuel_saved; } break; } }); setDeliveryStatus(newStatus); setOptimizationMetrics(newMetrics); setRecentDeliveryEvents(deliveryEvents.slice(0, 5)); }, [sseEvents]); // Initialize status from API data useEffect(() => { if (distributionOverview) { const statusCounts = distributionOverview.status_counts || {}; setDeliveryStatus({ total: Object.values(statusCounts).reduce((sum, count) => sum + count, 0), onTime: statusCounts['delivered'] || 0, delayed: statusCounts['overdue'] || 0, inTransit: (statusCounts['in_transit'] || 0) + (statusCounts['pending'] || 0), completed: statusCounts['delivered'] || 0 }); } }, [distributionOverview]); const isLoading = isDistributionLoading; // Mock route data - in Phase 2 this will come from real API const mockRoutes = [ { id: 'route-1', name: 'Madrid → Barcelona', status: 'in_transit', distance: '620 km', duration: '6h 30m', stops: 3, optimizationSavings: '12 km (1.9%)', vehicles: ['TRUCK-001', 'TRUCK-002'] }, { id: 'route-2', name: 'Barcelona → Valencia', status: 'completed', distance: '350 km', duration: '4h 15m', stops: 2, optimizationSavings: '8 km (2.3%)', vehicles: ['VAN-005'] }, { id: 'route-3', name: 'Central → Outlets (Daily)', status: 'pending', distance: '180 km', duration: '3h 00m', stops: 5, optimizationSavings: '25 km (13.9%)', vehicles: ['TRUCK-003', 'VAN-006', 'VAN-007'] } ]; return (
{/* Distribution Summary */}

{t('enterprise.distribution_summary')}

{/* Date selector */}
onDateChange(e.target.value)} className="border border-[var(--border-primary)] rounded-md px-3 py-2 text-sm bg-[var(--input-bg)] text-[var(--text-primary)]" />
{sseConnected && (
{t('enterprise.live_updates')}
)}
{/* Total Deliveries */} {t('enterprise.total_deliveries')}
{deliveryStatus.total}

{t('enterprise.all_shipments')}

{/* On-time Deliveries */} {t('enterprise.on_time_deliveries')}
{deliveryStatus.onTime}

{deliveryStatus.total > 0 ? `${Math.round((deliveryStatus.onTime / deliveryStatus.total) * 100)}% ${t('enterprise.on_time_rate')}` : t('enterprise.no_deliveries')}

{/* Delayed Deliveries */} {t('enterprise.delayed_deliveries')}
{deliveryStatus.delayed}

{deliveryStatus.total > 0 ? `${Math.round((deliveryStatus.delayed / deliveryStatus.total) * 100)}% ${t('enterprise.delay_rate')}` : t('enterprise.no_delays')}

{/* In Transit */} {t('enterprise.in_transit')}
{deliveryStatus.inTransit}

{t('enterprise.currently_en_route')}

{/* Route Optimization Metrics */}

{t('enterprise.route_optimization')}

{/* Distance Saved */} {t('enterprise.distance_saved')}
{optimizationMetrics.distanceSaved} km

{t('enterprise.total_distance_saved')}

{/* Time Saved */} {t('enterprise.time_saved')}
{optimizationMetrics.timeSaved} min

{t('enterprise.total_time_saved')}

{/* Fuel Saved */} {t('enterprise.fuel_saved')}
{currencySymbol}{optimizationMetrics.fuelSaved.toFixed(2)}

{t('enterprise.estimated_fuel_savings')}

{/* CO2 Saved */} {t('enterprise.co2_saved')}
{optimizationMetrics.co2Saved} kg

{t('enterprise.estimated_co2_reduction')}

{/* Active Routes */}

{t('enterprise.active_routes')}

{mockRoutes.map((route) => { // Determine status configuration const getStatusConfig = () => { switch (route.status) { case 'completed': return { color: '#10b981', // emerald-500 text: t('enterprise.route_completed'), icon: CheckCircle2 }; case 'delayed': case 'overdue': return { color: '#ef4444', // red-500 text: t('enterprise.route_delayed'), icon: AlertTriangle, isCritical: true }; case 'in_transit': return { color: '#3b82f6', // blue-500 text: t('enterprise.route_in_transit'), icon: Activity, isHighlight: true }; default: // pending, planned return { color: '#f59e0b', // amber-500 text: t('enterprise.route_pending'), icon: Clock }; } }; const statusConfig = getStatusConfig(); return ( { // In Phase 2, this will navigate to route tracking page console.log(`Track route ${route.name}`); }, priority: 'primary' } ]} onClick={() => { // In Phase 2, this will navigate to route detail page console.log(`View route ${route.name}`); }} /> ); })}
{/* Real-time Delivery Events */}

{t('enterprise.real_time_delivery_events')}

{t('enterprise.recent_delivery_activity')}
{recentDeliveryEvents.length > 0 ? (
{recentDeliveryEvents.map((event, index) => { // Determine event icon and color based on type const getEventConfig = () => { switch (event.event_type) { case 'delivery_delayed': case 'delivery_overdue': return { icon: AlertTriangle, color: 'text-[var(--color-warning)]' }; case 'delivery_completed': case 'delivery_received': return { icon: CheckCircle2, color: 'text-[var(--color-success)]' }; case 'delivery_started': case 'delivery_in_transit': return { icon: Activity, color: 'text-[var(--color-info)]' }; case 'route_optimized': return { icon: Route, color: 'text-[var(--color-primary)]' }; default: return { icon: Bell, color: 'text-[var(--color-secondary)]' }; } }; const { icon: EventIcon, color } = getEventConfig(); const eventTime = new Date(event.timestamp || event.created_at || Date.now()); return (

{event.event_type.replace(/_/g, ' ')}

{eventTime.toLocaleTimeString()}

{event.message && (

{event.message}

)} {event.entity_type && event.entity_id && (

{event.entity_type}: {event.entity_id}

)} {event.event_metadata?.route_name && (

{t('enterprise.route')}: {event.event_metadata.route_name}

)}
); })}
) : (
{sseConnected ? t('enterprise.no_recent_delivery_activity') : t('enterprise.waiting_for_updates')}
)}
{/* Quick Actions */}

{t('enterprise.quick_actions')}

{t('enterprise.optimize_routes')}

{t('enterprise.optimize_routes_description')}

{t('enterprise.manage_vehicles')}

{t('enterprise.manage_vehicle_fleet')}

{t('enterprise.live_tracking')}

{t('enterprise.real_time_gps_tracking')}

); }; export default DistributionTab;