@fleetbase/fleetops-engine
Version:
Fleet & Transport Management Extension for Fleetbase
626 lines (488 loc) • 18.3 kB
JavaScript
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { debug } from '@ember/debug';
import { task } from 'ember-concurrency';
export default class OrderDetailsTrackingComponent extends Component {
orderActions;
fetch;
notifications;
constructor() {
super(...arguments);
this.loadTrackerData.perform();
}
*loadTrackerData() {
if (!this.args.resource || typeof this.args.resource.loadTrackerData !== 'function') {
return;
}
try {
yield this.args.resource.loadTrackerData();
} catch (err) {
debug('Failed to load order tracker data: ' + err.message);
}
}
get trackerData() {
return this.args.resource?.tracker_data;
}
get hasTrackerData() {
return Boolean(this.trackerData);
}
get lifecycle() {
return this.trackerData?.lifecycle ?? {};
}
get lifecycleMode() {
if (this.lifecycle.mode) {
return this.lifecycle.mode;
}
const status = this.statusCode;
if (['completed', 'canceled'].includes(status)) {
return status;
}
if (!this.hasAssignedDriver) {
return 'unassigned';
}
if (!this.hasOrderStarted && status === 'dispatched') {
return 'dispatched';
}
if (!this.hasOrderStarted) {
return 'pre_start';
}
return 'active';
}
get statusCode() {
return String(this.lifecycle.status ?? this.args.resource?.status ?? 'created').toLowerCase();
}
get hasOrderStarted() {
return Boolean(this.lifecycle.has_started ?? this.args.resource?.started ?? this.args.resource?.started_at ?? this.statusCode === 'started');
}
get showLiveEta() {
if (this.lifecycle.show_live_eta !== undefined) {
return Boolean(this.lifecycle.show_live_eta);
}
return this.hasOrderStarted && !this.isTerminalLifecycle;
}
get showStartEta() {
if (this.lifecycle.show_start_eta !== undefined) {
return Boolean(this.lifecycle.show_start_eta);
}
return this.lifecycleMode === 'dispatched' && this.hasStartEta;
}
get isTerminalLifecycle() {
return Boolean(this.lifecycle.is_terminal ?? ['completed', 'canceled'].includes(this.statusCode));
}
get isPreStartLifecycle() {
return ['created', 'pre_start'].includes(this.lifecycleMode);
}
get isDispatchedLifecycle() {
return this.lifecycleMode === 'dispatched';
}
get lifecycleMessage() {
if (this.lifecycleMode === 'unassigned') {
return null;
}
return this.lifecycle.message ?? this.defaultLifecycleMessage;
}
get defaultLifecycleMessage() {
if (this.statusCode === 'completed') {
return 'Order has been completed.';
}
if (this.statusCode === 'canceled') {
return 'Order has been canceled.';
}
if (this.isDispatchedLifecycle) {
return 'Order has been dispatched. Estimated start is based on the assigned driver route to the first stop.';
}
if (this.isPreStartLifecycle) {
return 'Live ETA will begin once the order is started.';
}
return null;
}
get lifecycleMessageTitle() {
switch (this.lifecycleMode) {
case 'completed':
return 'Order completed';
case 'canceled':
return 'Order canceled';
case 'dispatched':
return 'Order dispatched';
case 'pre_start':
case 'created':
return 'Tracking pending start';
default:
return null;
}
}
get lifecycleMessageIcon() {
switch (this.lifecycleMode) {
case 'completed':
return 'circle-check';
case 'canceled':
return 'ban';
case 'dispatched':
return 'route';
default:
return 'clock';
}
}
get startEtaSeconds() {
return this.trackerData?.eta?.start_seconds;
}
get hasStartEta() {
return this.startEtaSeconds !== null && this.startEtaSeconds !== undefined;
}
get activeEtaSeconds() {
return this.trackerData?.eta?.active_stop_seconds;
}
get hasActiveEta() {
return this.showLiveEta && this.activeEtaSeconds !== null && this.activeEtaSeconds !== undefined;
}
get smartAdjustedEtaSeconds() {
if (!this.showLiveEta) {
return null;
}
return (
this.firstPositiveNumber(this.activeEtaSeconds) ??
this.firstPositiveNumber(this.trackerData?.route?.duration_in_traffic_s) ??
this.firstPositiveNumber(this.trackerData?.route?.duration_s) ??
this.firstPositiveNumber(this.reportedEtaSeconds) ??
null
);
}
get hasSmartAdjustedEta() {
return this.smartAdjustedEtaSeconds !== null && this.smartAdjustedEtaSeconds !== undefined;
}
get smartAdjustedEtaUnavailableLabel() {
if (this.driverSignal === 'Unassigned') {
return 'Pending driver assignment';
}
if (this.driverSignal === 'Missing' || this.driverSignal === 'Stale') {
return 'Pending GPS fix';
}
return 'Pending start';
}
get hasCompletionEta() {
return this.showLiveEta && Boolean(this.trackerData?.eta?.completion_at);
}
get hasRemainingDistance() {
return this.trackerData?.route?.distance_m !== null && this.trackerData?.route?.distance_m !== undefined;
}
get hasAssignedDriver() {
const order = this.args.resource;
return Boolean(order?.driver_assigned || order?.driver_assigned_uuid);
}
get driverSignal() {
const trackerData = this.trackerData;
if (!this.hasAssignedDriver) {
return 'Unassigned';
}
if (!trackerData?.driver?.location) {
return 'Missing';
}
if (trackerData?.insights?.is_location_stale) {
return 'Stale';
}
return trackerData?.driver?.online ? 'Live' : 'Offline';
}
get driverStatusLabel() {
switch (this.driverSignal) {
case 'Live':
return 'Driver live';
case 'Stale':
return 'Driver stale';
case 'Missing':
return 'Driver missing GPS';
case 'Unassigned':
return 'No driver assigned';
default:
return 'Driver offline';
}
}
get hasDriverLocationAge() {
return this.trackerData?.driver?.location_age_seconds !== null && this.trackerData?.driver?.location_age_seconds !== undefined;
}
get driverSignalClass() {
switch (this.driverSignal) {
case 'Live':
return 'text-green-600 dark:text-green-400';
case 'Stale':
return 'text-yellow-600 dark:text-yellow-400';
case 'Missing':
return 'text-red-600 dark:text-red-400';
case 'Unassigned':
return 'text-yellow-600 dark:text-yellow-400';
default:
return 'text-gray-600 dark:text-gray-300';
}
}
get routeQualityItems() {
const trackerData = this.trackerData;
if (!trackerData) {
return [];
}
const items = [`${this.humanize(trackerData.provider)} route`];
if (trackerData.confidence) {
items.push(`${this.humanize(trackerData.confidence)} confidence`);
}
if (trackerData.fallback_provider) {
items.push(`Fallback: ${this.humanize(trackerData.fallback_provider)}`);
}
return items;
}
get confidenceLabel() {
return this.humanize(this.trackerData?.confidence || 'unknown');
}
get confidencePercent() {
const score = this.trackerData?.confidence_score ?? this.trackerData?.confidence_percent ?? this.trackerData?.confidence_percentage;
if (score !== null && score !== undefined && !Number.isNaN(Number(score))) {
return Math.max(0, Math.min(100, Math.round(Number(score))));
}
switch (this.trackerData?.confidence) {
case 'high':
return 92;
case 'medium':
return 68;
case 'low':
return 34;
default:
return 0;
}
}
get providerLabel() {
return this.humanize(this.trackerData?.provider);
}
get fallbackProviderLabel() {
return this.humanize(this.trackerData?.fallback_provider);
}
get confidenceToneClass() {
switch (this.trackerData?.confidence) {
case 'high':
return 'tracking-intelligence-pill--good';
case 'medium':
return 'tracking-intelligence-pill--warn';
case 'low':
return 'tracking-intelligence-pill--bad';
default:
return 'tracking-intelligence-pill--muted';
}
}
get confidenceSegments() {
const confidence = this.trackerData?.confidence;
const litCount = confidence === 'high' ? 5 : confidence === 'medium' ? 3 : confidence === 'low' ? 2 : 1;
return Array.from({ length: 5 }, (_, index) => ({
lit: index < litCount,
}));
}
get activeStopIndex() {
const stops = this.trackerData?.stops ?? [];
const activeStop = this.trackerData?.active_stop;
const index = stops.findIndex((stop) => this.matchesStop(stop, activeStop));
return index >= 0 ? index + 1 : null;
}
get totalStops() {
return this.trackerData?.stops?.length ?? 0;
}
get activeStopLabel() {
if (!this.activeStopIndex || !this.totalStops) {
return 'NOW HEADING TO';
}
return `NOW HEADING TO - STOP ${this.activeStopIndex} OF ${this.totalStops}`;
}
get activeStopMarkerLabel() {
const activeStop = this.trackerData?.active_stop;
if (activeStop?.type === 'pickup') {
return 'P';
}
if (activeStop?.type === 'dropoff') {
return 'D';
}
return this.activeStopIndex ?? '•';
}
get reportedEtaSeconds() {
const activeStop = this.trackerData?.active_stop;
const eta = this.args.resource?.eta ?? {};
return activeStop?.eta_seconds ?? eta?.[activeStop?.id] ?? eta?.[activeStop?.uuid] ?? eta?.[activeStop?.public_id] ?? null;
}
get displayedReportedEtaSeconds() {
if (!this.showLiveEta) {
return null;
}
return (
this.firstPositiveNumber(this.reportedEtaSeconds) ??
this.firstPositiveNumber(this.activeEtaSeconds) ??
this.firstPositiveNumber(this.trackerData?.route?.duration_in_traffic_s) ??
this.firstPositiveNumber(this.trackerData?.route?.duration_s) ??
null
);
}
get hasDisplayedReportedEta() {
return this.displayedReportedEtaSeconds !== null && this.displayedReportedEtaSeconds !== undefined;
}
get isReportedEtaUntrusted() {
const trackerData = this.trackerData;
if (!trackerData) {
return false;
}
if (!this.showLiveEta) {
return false;
}
return !trackerData?.driver?.location || trackerData?.insights?.is_location_stale || trackerData.fallback_provider || (trackerData.confidence && trackerData.confidence !== 'high');
}
get reportedEtaWarning() {
if (!this.isReportedEtaUntrusted) {
return 'Reported from existing route data';
}
return this.operatorWarning ?? 'Reported ETA may not reflect the latest tracking signal.';
}
get etaUnavailableLabel() {
if (this.driverSignal === 'Unassigned') {
return 'Pending driver assignment';
}
if (this.driverSignal === 'Missing' || this.driverSignal === 'Stale') {
return 'Pending GPS fix';
}
return '-';
}
get operatorWarningTitle() {
switch (this.driverSignal) {
case 'Unassigned':
return 'No driver assigned';
case 'Missing':
return 'Pending GPS fix';
case 'Stale':
return 'Stale driver location';
default:
return 'Tracking estimate warning';
}
}
get canAssignDriver() {
return this.driverSignal === 'Unassigned';
}
get canPingDriver() {
return this.driverSignal === 'Missing' || this.driverSignal === 'Stale';
}
get warningsCount() {
return (this.trackerData?.warnings ?? []).length;
}
get diagnosticsSummaryLabel() {
return this.warningsCount === 1 ? '1 warning' : `${this.warningsCount} warnings`;
}
get totalProgressPercentage() {
const percentage = Number(this.trackerData?.progress?.percentage);
if (Number.isFinite(percentage)) {
return Math.max(0, Math.min(100, percentage));
}
const stops = this.trackerData?.stops ?? [];
const completedStops = stops.filter((stop) => stop.completed).length;
if (stops.length) {
return Math.max(0, Math.min(100, Math.round((completedStops / stops.length) * 100)));
}
return 0;
}
get totalProgressStyle() {
const percentage = this.hasRemainingDistance && this.totalProgressPercentage === 0 ? 2 : this.totalProgressPercentage;
return `width: ${percentage}%;`;
}
get currentLeg() {
return this.trackerData?.route?.legs?.[0] ?? null;
}
get hasCurrentLegDistance() {
return this.currentLeg?.distance_m !== null && this.currentLeg?.distance_m !== undefined;
}
get currentLegProgressPercentage() {
const explicit = Number(this.currentLeg?.progress_percentage ?? this.trackerData?.progress?.active_leg_percentage);
if (Number.isFinite(explicit)) {
return Math.max(0, Math.min(100, explicit));
}
if (this.driverSignal === 'Unassigned' || this.driverSignal === 'Missing') {
return 0;
}
if (this.driverSignal === 'Stale') {
return 18;
}
return Math.max(8, Math.min(92, this.totalProgressPercentage));
}
get currentLegProgressStyle() {
return `width: ${this.currentLegProgressPercentage}%;`;
}
get hasWarnings() {
return (this.trackerData?.warnings ?? []).length > 0;
}
get diagnostics() {
const trackerData = this.trackerData;
if (!trackerData) {
return [];
}
return [
{ label: 'Provider', value: this.humanize(trackerData.provider) },
{ label: 'Fallback', value: trackerData.fallback_provider ? this.humanize(trackerData.fallback_provider) : 'No' },
{ label: 'Traffic aware', value: trackerData.options?.traffic_enabled ? 'Yes' : 'No' },
{ label: 'Confidence', value: this.confidenceLabel },
{ label: 'Driver signal', value: this.driverSignal },
{ label: 'Warnings', value: String((trackerData.warnings ?? []).length) },
];
}
get operatorWarning() {
const trackerData = this.trackerData;
if (!trackerData) {
return null;
}
if (this.isTerminalLifecycle || this.isPreStartLifecycle || this.isDispatchedLifecycle) {
return null;
}
if (!this.hasAssignedDriver) {
return 'Assign a driver to start live tracking and improve ETA accuracy.';
}
if (!trackerData?.driver?.location) {
return 'Driver location is missing, so ETA accuracy may be limited.';
}
if (trackerData?.insights?.is_location_stale) {
return 'Driver location is stale. ETA may not reflect the latest movement.';
}
if (trackerData.fallback_provider) {
return `Using ${this.humanize(trackerData.fallback_provider)} fallback because the preferred tracking provider was unavailable.`;
}
if (trackerData.confidence && trackerData.confidence !== 'high') {
return `${this.humanize(trackerData.confidence)} confidence ETA. Treat the estimate as directional.`;
}
if ((trackerData.warnings ?? []).some((warning) => String(warning).startsWith('provider_failed'))) {
return 'Tracking provider returned an error. Showing the best available estimate.';
}
return null;
}
humanize(value) {
return String(value ?? '')
.replace(/[_:-]+/g, ' ')
.replace(/\s+/g, ' ')
.trim()
.replace(/\b\w/g, (character) => character.toUpperCase());
}
firstPositiveNumber(value) {
const number = Number(value);
return Number.isFinite(number) && number > 0 ? number : null;
}
matchesStop(stop, activeStop) {
if (!stop || !activeStop) {
return false;
}
return stop.uuid === activeStop.uuid || stop.public_id === activeStop.public_id || stop.id === activeStop.id;
}
assignDriver() {
const order = this.args.resource;
if (!order || typeof this.orderActions.assignDriver !== 'function') {
return;
}
return this.orderActions.assignDriver(order);
}
*pingDriver() {
const order = this.args.resource;
if (!order) {
return;
}
try {
yield this.fetch.post(`orders/${order.id}/ping-driver`);
this.notifications.success('Driver app ping sent.');
} catch (err) {
this.notifications.error(err.message ?? 'Unable to ping driver app.');
}
}
}