useUnifiedFleetData.ts
The primary data hook that aggregates real-time fleet data from three sources: drivers, vehicles, and trailers.Purpose
- Fetch and manage data from three separate API sources
- Maintain SSE connections for real-time vehicle and trailer updates
- Calculate fleet statistics (utilization, counts, averages)
- Provide unified data structure for dashboard components
Import
Dependencies
| Import | Purpose |
|---|---|
sonner → toast | Error notifications displayed to user |
safeParseSSEJSON | Safely parses SSE event data (handles malformed JSON) |
Return Type
| Property | Type | Description |
|---|---|---|
data | UnifiedFleetData | Combined data from all three sources |
statistics | FleetStatistics | Computed statistics for KPIs |
connectionState | FleetConnectionState | SSE connection status for each source |
isLoading | boolean | Initial loading state |
refresh | () => Promise<void> | Manual refresh function |
topDrivers | DriverSummary[] | Top 10 active drivers |
topVehicles | TractorSummary[] | Top 10 vehicles with drivers |
topTrailers | TrailerSummary[] | Top 10 moving trailers |
UnifiedFleetData Structure
Thedata object contains raw arrays plus metadata:
Timestamps: The
*PolledAt fields indicate when each data source was last fetched/updated. Useful for showing “Last updated X seconds ago” in the UI.API Endpoints
| Source | REST Endpoint | SSE Endpoint |
|---|---|---|
| Drivers | /api/drivers/current | None (polling only) |
| Vehicles | /locations/current | /stream/locations |
| Trailers | /api/trailers/current | /api/trailers/stream |
Base URL: All endpoints use
NEXT_PUBLIC_TRACKING_BACKEND_URL environment variable.Data Flow
Internal Functions
fetchDrivers
fetchDrivers
Fetches driver data from REST API.Endpoint: State updates:
GET /api/drivers/currentResponse handling:- Supports both old (
drivers[]) and new (items[]) API structures - Extracts
drivers_countor falls back toitems.length - Extracts
polled_atormaxLastUpdatedAtor current timestamp
driversarraydriversCountdriversPolledAtconnectionState.drivers
fetchVehicles
fetchVehicles
Fetches vehicle data from REST API with structure transformation.Endpoint:
GET /locations/currentResponse handling:- Supports both old (
vehicles[]) and new (items[]) API structures - Transforms flat structure to
VehicleLocationformat if needed
fetchTrailers
fetchTrailers
Fetches trailer data from REST API.Endpoint:
GET /api/trailers/currentResponse type: TrailerLocationBatchState updates:trailersarraytrailersCounttrailersPolledAtconnectionState.trailers
connectVehicleSSE
connectVehicleSSE
Establishes SSE connection for real-time vehicle updates.Endpoint:
Merge logic:
GET /stream/locations (EventSource)Event handlers:| Event | Action |
|---|---|
connected | Update connection state to “connected” |
location_update | Merge new vehicle data with existing (preserves mcleod_tractor_id, tractor_number) |
onerror | Set connection state to “disconnected” |
connectTrailerSSE
connectTrailerSSE
Establishes SSE connection for real-time trailer updates.Endpoint:
GET /api/trailers/stream (EventSource)Event handlers:| Event | Action |
|---|---|
connected | Update connection state to “connected” |
location_update | Replace trailer array with new data |
onerror | Set connection state to “disconnected” |
Statistics Calculation
Thestatistics object is computed via useMemo and recalculates when data changes.
Driver Statistics
| Stat | Calculation |
|---|---|
total | drivers.length |
active | Count where status === "active" |
inactive | Count where status === "inactive" |
onDuty | 0 (requires additional HOS data) |
offDuty | 0 (requires additional HOS data) |
hosWarnings | 0 (requires additional HOS data) |
Vehicle Statistics
| Stat | Calculation |
|---|---|
total | vehicles.length |
engineOn | Count where engine_state === "on" |
engineOff | Count where engine_state === "off" |
withDrivers | Count where driver_id exists (truthy) |
available | Count where driver_id is falsy |
lowFuel | Count where fuel.primary_percentage < 25 |
avgSpeed | Average speed of “active” vehicles |
avgSpeed calculation: Only includes vehicles where:
engine_state === "on"ANDspeed !== nullANDspeed !== undefined
Trailer Statistics
| Stat | Calculation |
|---|---|
total | trailers.length |
moving | Count where converted speed ≥ 5 mph |
stationary | Count where converted speed < 5 mph |
recentUpdates | Count updated within last 5 minutes |
staleData | Count not updated in 10+ minutes |
avgSpeed | Average speed of moving trailers |
providerCounts | Record<string, number> by provider |
Speed conversion for trailers:
- Motive provider: Speed is in km/h → converted to mph
- Other providers: Speed assumed to already be in mph (used as-is)
- Null speed: Treated as 0
Top Items
The hook provides pre-filtered “top” lists for compact dashboard displays:| Property | Filter | Limit |
|---|---|---|
topDrivers | status === "active" | 10 |
topVehicles | driver_id is truthy and not empty string | 10 |
topTrailers | Converted speed ≥ 5 mph | 10 |
Usage Example
useVehicleLocations.ts
A focused hook for vehicle location data only, used internally byLiveVehicleMap when no filtered data is provided.
Purpose
- Fetch vehicle locations via REST API
- Maintain SSE connection for real-time updates
- Track cache status for debugging
- Provide simpler interface than
useUnifiedFleetData
Import
Dependencies
| Import | Purpose |
|---|---|
sonner → toast | Error notifications |
safeParseSSEJSON | Safely parses SSE event data |
Return Type
| Property | Type | Description |
|---|---|---|
vehicles | VehicleLocation[] | Array of vehicle location objects |
connectionState | SSEConnectionState | SSE connection status |
vehiclesCount | number | Total count from API |
polledAt | string | null | ISO timestamp of last poll |
cacheStatus | "hit" | "miss" | null | Backend cache status |
refresh | () => Promise<void> | Manual refresh function |
isLoading | boolean | Initial loading state |
API Endpoints
| Type | Endpoint |
|---|---|
| REST | GET /locations/current |
| SSE | GET /stream/locations |
SSE Event Types
| Event | Description | Data |
|---|---|---|
connected | Connection established | { message, timestamp, cached_data? } |
location_update | New vehicle data | VehicleLocationsResponse |
heartbeat | Keep-alive ping | { message? } |
Internal Functions
fetchInitialData
fetchInitialData
Fetches vehicle data via REST before SSE connection.Endpoint:
GET /locations/currentResponse type: VehicleLocationsResponseUpdates state:vehiclesvehiclesCountpolledAtcacheStatusconnectionState.lastUpdate
connectSSE
connectSSE
Establishes SSE connection for real-time updates.Endpoint:
GET /stream/locationsEvent handlers:| Event | Handler |
|---|---|
connected | Set status to “connected”, optionally load cached data |
location_update | Replace vehicles array, update timestamps |
heartbeat | Log heartbeat (no state change) |
onerror | Set status to “disconnected”, show toast error |
onmessage | Fallback for untyped messages (logged only) |
The browser’s
EventSource automatically handles reconnection on network errors.refresh
refresh
Manual refresh that calls
fetchInitialData().Lifecycle
Note: The
reconnectTimeoutRef is defined but not actively used in the current implementation. The browser’s native EventSource auto-reconnect handles reconnection. This ref may be for future custom reconnection logic.Difference from useUnifiedFleetData
| Aspect | useVehicleLocations | useUnifiedFleetData |
|---|---|---|
| Data sources | Vehicles only | Drivers + Vehicles + Trailers |
| SSE connections | 1 | 2 |
| Statistics | None | Computed statistics |
| Top items | None | topDrivers, topVehicles, topTrailers |
| Cache status | Tracked | Not tracked |
| Data transformation | None (expects VehicleLocationsResponse) | Transforms flat API structures |
| Use case | Standalone map component | Full dashboard |
Usage Example
SSE Connection States
Both hooks use similar connection state management:State Transitions
Environment Variables
Both hooks require:This URL should point to the Tracking Backend service. In production, this would be the deployed backend URL.

