diff --git a/apps/edr-freight-web/backoffice/src/App.tsx b/apps/edr-freight-web/backoffice/src/App.tsx index 7d8d07ab5..8c1562bc4 100644 --- a/apps/edr-freight-web/backoffice/src/App.tsx +++ b/apps/edr-freight-web/backoffice/src/App.tsx @@ -6,6 +6,7 @@ import { FileText, LayoutDashboard, LayoutGrid, + MapPin, Network, Package, PackageCheck, @@ -62,6 +63,7 @@ import FuelStatsPage from "./pages/fleet/FuelStatsPage"; import { MaintenancePage } from "./pages/fleet/MaintenancePage"; import { FinancialReportsPage } from "./pages/fleet/FinancialReportsPage"; import { FleetDashboard } from "./pages/fleet/FleetDashboard"; +import { TrackingPage } from "./pages/fleet/TrackingPage"; import { getCategorySidebarChildren } from "./pages/ruleEngine/config/resources"; import RuleEngineLegacyRedirect from "./pages/ruleEngine/RuleEngineLegacyRedirect"; import RuleEngineResourcePage from "./pages/ruleEngine/RuleEngineResourcePage"; @@ -211,6 +213,12 @@ const buildSidebarSections = (demoItems: SidebarItem[]): SidebarSection[] => [ icon: , permission: FREIGHT_PERMS.fleet.view, }, + { + label: "Track Vehicles", + href: "/dashboard/tracking", + icon: , + permission: FREIGHT_PERMS.fleet.view, + }, { label: "Fuel Purchases", href: "/dashboard/fuel-purchases", @@ -800,6 +808,14 @@ const App = () => { } /> + + + + } + /> ({ + lat: 9.0 + Math.random() * 0.5, + lng: 38.7 + Math.random() * 0.5, + speed: Math.floor(Math.random() * 120), + heading: Math.floor(Math.random() * 360), + lastUpdate: new Date(Date.now() - Math.random() * 300000).toLocaleTimeString(), +}); + +export function TrackingPage() { + const [selectedVehicleId, setSelectedVehicleId] = useState(null); + const [mapCenter] = useState({ lat: 9.0, lng: 38.8 }); + const mapZoom = 10; + + const { data: vehicles = [] } = useQuery({ + queryKey: QUERY_KEYS.VEHICLES.list(), + queryFn: async () => { + const res = await vehiclesService.getAll({ limit: 1000 }); + return res.data || []; + }, + }); + + // Generate mock GPS data for each vehicle + const vehiclesWithGPS = useMemo(() => { + return (vehicles as Vehicle[]).map((v, idx) => ({ + ...v, + gps: generateMockGPS(idx), + })); + }, [vehicles]); + + const selectedVehicle = vehiclesWithGPS.find(v => v.id === selectedVehicleId); + const vehicleOptions = useMemo( + () => vehiclesWithGPS.map(v => ({ label: v.registrationNumber, value: v.id })), + [vehiclesWithGPS] + ); + + // Map dimensions + const mapWidth = 800; + const mapHeight = 500; + const pixelsPerLat = mapHeight / 0.6; + const pixelsPerLng = mapWidth / 0.6; + + const getMapCoords = (lat: number, lng: number) => ({ + x: ((lng - (mapCenter.lng - 0.3)) * pixelsPerLng), + y: ((mapCenter.lat + 0.3 - lat) * pixelsPerLat), + }); + + return ( + + + + + + + + Real-Time Vehicle Tracking + + + Monitor vehicle locations, speed, and status + + + + + + {/* Map Section */} + + + + + Map View + + }> + {vehiclesWithGPS.filter(v => v.status === 'ACTIVE').length} Active + + + + + + + + {/* Grid background */} + + {/* Latitude lines */} + {[0, 1, 2, 3, 4, 5, 6].map(i => ( + + ))} + {/* Longitude lines */} + {[0, 1, 2, 3, 4, 5, 6].map(i => ( + + ))} + + + {/* Vehicle markers */} + {vehiclesWithGPS.map((vehicle) => { + const coords = getMapCoords(vehicle.gps.lat, vehicle.gps.lng); + const isSelected = vehicle.id === selectedVehicleId; + + return ( + setSelectedVehicleId(vehicle.id)} + title={vehicle.registrationNumber} + > + + + + + ); + })} + + {/* Map labels */} + + + 📍 Addis Ababa, Ethiopia + + + + + + + + {/* Sidebar */} + + + {/* Vehicle Selector */} + + + + {selectedVehicle && ( + + + + + Registration + + {selectedVehicle.registrationNumber} + + + + Vehicle + + + {selectedVehicle.manufacturer} {selectedVehicle.model} + + + + + Status + + + {selectedVehicle.status || 'Unknown'} + + + + + )} + + + + {/* GPS Details */} + {selectedVehicle && ( + + + + GPS Location + }> + Live + + + + + + + Latitude + + + {selectedVehicle.gps.lat.toFixed(4)}° + + + + + Longitude + + + {selectedVehicle.gps.lng.toFixed(4)}° + + + + + Speed + + + {selectedVehicle.gps.speed} km/h + + + + + Heading + + + {selectedVehicle.gps.heading}° + + + + + + + Last Update + + {selectedVehicle.gps.lastUpdate} + + + }> + View Full History + + + + )} + + {/* All Vehicles List */} + + + All Vehicles + + + + {vehiclesWithGPS.slice(0, 10).map(v => ( + setSelectedVehicleId(v.id)} + > + + + + {v.registrationNumber} + + + {v.gps.speed} km/h + + + + + + {v.status || 'N/A'} + + + + ))} + + + + + + + + + + + ); +}