diff --git a/apps/edr-freight-web/backoffice/src/pages/fleet/FleetDashboard.tsx b/apps/edr-freight-web/backoffice/src/pages/fleet/FleetDashboard.tsx index 7eee0e657..a977c592d 100644 --- a/apps/edr-freight-web/backoffice/src/pages/fleet/FleetDashboard.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/fleet/FleetDashboard.tsx @@ -1,7 +1,7 @@ import { useMemo } from 'react'; import { useQuery } from '@tanstack/react-query'; -import { Card, Stack, Group, Grid, Text, ThemeIcon, Progress, Badge, Table, RingProgress, Container } from '@mantine/core'; -import { Truck, Fuel, Wrench, TrendingUp, AlertCircle } from 'lucide-react'; +import { Card, Stack, Group, Grid, Text, ThemeIcon, Progress, Badge, Table, RingProgress, Container, Title, Box, Tabs } from '@mantine/core'; +import { Truck, Fuel, Wrench, TrendingUp, AlertCircle, Users, User, MapPin, Calendar } from 'lucide-react'; import Breadcrumbs from '@/components/ui/Breadcrumbs'; import { QUERY_KEYS } from '@/constants/QUERY_KEYS'; import { api } from '@/auth/http'; @@ -16,6 +16,16 @@ interface Vehicle { status?: string; } +interface Driver { + id: string; + firstName: string; + lastName: string; + licenseNumber?: string; + email?: string; + phone?: string; + assignedVehicle?: string; +} + interface FleetMetrics { totalVehicles: number; activeVehicles: number; @@ -24,23 +34,28 @@ interface FleetMetrics { totalMaintenanceSpend: number; averageFuelEfficiency: number; costPerKm: number; + totalDrivers: number; + assignedDrivers: number; } -const StatCard = ({ icon: Icon, label, value, color = 'blue' }: any) => ( - - - - - {label} - - - {value} - - - - +const StatCard = ({ icon: Icon, label, value, color = 'blue', change }: any) => ( + + + + + + + {label} + + + + {value} + + {change && 0 ? 'green' : 'red'} size="lg">{change > 0 ? '+' : ''}{change}%} + + ); @@ -53,6 +68,18 @@ export function FleetDashboard() { }, }); + const { data: drivers = [] } = useQuery({ + queryKey: ['drivers'], + queryFn: async () => { + try { + const res = await api.get('/drivers'); + return res.data || []; + } catch { + return []; + } + }, + }); + const { data: fuelStats } = useQuery({ queryKey: ['fleet-fuel-stats'], queryFn: async () => { @@ -80,6 +107,8 @@ export function FleetDashboard() { const metrics = useMemo((): FleetMetrics => { const totalVehicles = (vehicles as Vehicle[]).length; const activeVehicles = (vehicles as Vehicle[]).filter(v => v.status === 'ACTIVE').length; + const totalDrivers = (drivers as Driver[]).length; + const assignedDrivers = (drivers as Driver[]).filter(d => d.assignedVehicle).length; const fuelTotal = fuelStats?.totalCost || 0; const maintenanceTotal = maintenanceStats?.totalCost || 0; @@ -92,8 +121,10 @@ export function FleetDashboard() { totalMaintenanceSpend: maintenanceTotal, averageFuelEfficiency: fuelStats?.averageEfficiency || 0, costPerKm: (fuelTotal + maintenanceTotal) / 100000, // Placeholder + totalDrivers, + assignedDrivers, }; - }, [vehicles, fuelStats, maintenanceStats]); + }, [vehicles, drivers, fuelStats, maintenanceStats]); const operatingCost = metrics.totalFuelSpend + metrics.totalMaintenanceSpend; const fuelPercent = operatingCost > 0 ? Math.round((metrics.totalFuelSpend / operatingCost) * 100) : 0; @@ -102,24 +133,29 @@ export function FleetDashboard() { - - Fleet Overview - + + + Fleet Management Dashboard + + + Real-time fleet overview, vehicle & driver management + + - {/* Key Metrics */} - + {/* Primary Metrics */} + + + + - - - {/* Fleet Status */} @@ -216,46 +252,108 @@ export function FleetDashboard() { - {/* Fleet List */} + {/* Vehicles & Drivers Tabs */} - - Fleet Vehicles - - - {(vehicles as Vehicle[]).length > 0 ? ( - - - - Registration - Plate - Model - Status - - - - {(vehicles as Vehicle[]).slice(0, 10).map(v => ( - - {v.registrationNumber} - {v.plateNumber} - - {v.manufacturer} {v.model} - - - {v.status || 'UNKNOWN'} - + + + }> + Vehicles ({(vehicles as Vehicle[]).length}) + + }> + Drivers ({(drivers as Driver[]).length}) + + + + + {(vehicles as Vehicle[]).length > 0 ? ( +
+ + + Registration + Plate + Model + Status - ))} - -
- ) : ( - - + + + {(vehicles as Vehicle[]).slice(0, 15).map(v => ( + + {v.registrationNumber} + {v.plateNumber} + + {v.manufacturer} {v.model} + + + + {v.status || 'UNKNOWN'} + + + + ))} + + + ) : ( + No vehicles in fleet - - )} -
+ )} + + + + {(drivers as Driver[]).length > 0 ? ( + + + + Name + License + Contact + Assigned Vehicle + + + + {(drivers as Driver[]).slice(0, 15).map(d => ( + + + + + + + {d.firstName} {d.lastName} + + + {d.licenseNumber || 'N/A'} + + + {d.phone && ( + + + {d.phone} + + + )} + {d.email && {d.email}} + + + + {d.assignedVehicle ? ( + Assigned + ) : ( + Unassigned + )} + + + ))} + +
+ ) : ( + + + No drivers in system + + )} +
+
);