@fleetbase/fleetops-engine 0.6.71 → 0.6.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (378) hide show
  1. package/RELEASE.md +15 -18
  2. package/addon/components/admin/tracking-page-settings.hbs +56 -0
  3. package/addon/components/admin/tracking-page-settings.js +67 -0
  4. package/addon/components/device/form.hbs +2 -2
  5. package/addon/components/driver/details.hbs +1 -1
  6. package/addon/components/driver/form.hbs +1 -1
  7. package/addon/components/equipment/form.hbs +1 -1
  8. package/addon/components/layout/fleet-ops-sidebar.js +11 -3
  9. package/addon/components/maintenance/form.hbs +3 -3
  10. package/addon/components/map/google-live-map.js +2 -2
  11. package/addon/components/map/leaflet-live-map.js +45 -32
  12. package/addon/components/orchestrator/phase-builder.js +2 -1
  13. package/addon/components/orchestrator-workbench.hbs +7 -1
  14. package/addon/components/orchestrator-workbench.js +16 -2
  15. package/addon/components/order/form/route.hbs +1 -1
  16. package/addon/components/order/form/route.js +13 -1
  17. package/addon/components/service-rate/details.hbs +1 -1
  18. package/addon/components/service-rate/form.hbs +1 -1
  19. package/addon/components/tracking-page/full-view.hbs +276 -0
  20. package/addon/components/tracking-page/full-view.js +474 -0
  21. package/addon/components/tracking-page/locale-selector.js +30 -0
  22. package/addon/components/tracking-page/map.hbs +44 -0
  23. package/addon/components/tracking-page/map.js +328 -0
  24. package/addon/components/tracking-page/order-list.hbs +35 -0
  25. package/addon/components/tracking-page/public-view.hbs +60 -0
  26. package/addon/components/tracking-page/settings-preview.hbs +21 -0
  27. package/addon/components/tracking-page/settings-preview.js +23 -0
  28. package/addon/components/tracking-page/verify-panel.hbs +109 -0
  29. package/addon/components/tracking-page.hbs +142 -0
  30. package/addon/components/tracking-page.js +564 -0
  31. package/addon/components/trailer/form.hbs +2 -2
  32. package/addon/components/vehicle/form.hbs +3 -3
  33. package/addon/components/warranty/form.hbs +2 -2
  34. package/addon/components/widget/live-fleet.js +54 -6
  35. package/addon/components/widget/proof-of-delivery.hbs +49 -0
  36. package/addon/components/widget/proof-of-delivery.js +62 -0
  37. package/addon/components/work-order/form.hbs +3 -3
  38. package/addon/controllers/operations/orders/index/details.js +19 -3
  39. package/addon/controllers/operations/scheduler/index.js +45 -14
  40. package/addon/controllers/settings/index.js +6 -0
  41. package/addon/controllers/settings/map.js +75 -0
  42. package/addon/controllers/settings/orchestrator.js +8 -6
  43. package/addon/controllers/settings/tracking-page.js +212 -0
  44. package/addon/extension.js +65 -1
  45. package/addon/helpers/parcel-box-image.js +16 -0
  46. package/addon/routes/operations/orders/index/new.js +5 -4
  47. package/addon/routes/operations/scheduler/index.js +1 -1
  48. package/addon/routes/settings/tracking-page.js +31 -0
  49. package/addon/routes.js +1 -0
  50. package/addon/services/location.js +69 -21
  51. package/addon/services/map-settings.js +28 -0
  52. package/addon/services/order-allocation.js +1 -1
  53. package/addon/styles/fleetops-engine.css +1391 -0
  54. package/addon/templates/settings/map.hbs +46 -0
  55. package/addon/templates/settings/tracking-page.hbs +318 -0
  56. package/addon/utils/identity-cell-resource.js +2 -56
  57. package/addon/utils/map-default-view.js +132 -0
  58. package/addon/utils/placeholder-images.js +4 -69
  59. package/addon/utils/resource-descriptors/assets.js +2 -57
  60. package/addon/utils/resource-descriptors/helpers.js +23 -122
  61. package/addon/utils/resource-descriptors/operations.js +2 -61
  62. package/addon/utils/resource-descriptors/people.js +3 -142
  63. package/addon/utils/resource-descriptors/shared.js +18 -0
  64. package/addon/utils/tracking-live-source.js +123 -0
  65. package/addon/utils/tracking-page-theme.js +123 -0
  66. package/app/components/admin/tracking-page-settings.js +1 -0
  67. package/app/components/tracking-page/full-view.js +1 -0
  68. package/app/components/tracking-page/locale-selector.js +1 -0
  69. package/app/components/tracking-page/map.js +1 -0
  70. package/app/components/tracking-page/order-list.js +1 -0
  71. package/app/components/tracking-page/public-view.js +1 -0
  72. package/app/components/tracking-page/settings-preview.js +1 -0
  73. package/app/components/tracking-page/verify-panel.js +1 -0
  74. package/app/components/tracking-page.js +1 -0
  75. package/app/components/widget/proof-of-delivery.js +1 -0
  76. package/app/controllers/settings/tracking-page.js +1 -0
  77. package/app/helpers/parcel-box-image.js +1 -0
  78. package/app/routes/settings/tracking-page.js +1 -0
  79. package/app/templates/settings/tracking-page.js +1 -0
  80. package/app/utils/map-default-view.js +1 -0
  81. package/app/utils/tracking-live-source.js +1 -0
  82. package/app/utils/tracking-page-theme.js +1 -0
  83. package/composer.json +2 -2
  84. package/extension.json +1 -1
  85. package/package.json +4 -4
  86. package/scripts/pest-bootstrap.php +4 -0
  87. package/server/config/fleetops.php +4 -0
  88. package/server/migrations/2026_10_08_000001_create_tracking_sessions_tables.php +51 -0
  89. package/server/migrations/2026_10_10_000001_add_trashed_index_to_device_events.php +40 -0
  90. package/server/migrations/2026_10_10_000002_add_trashed_index_to_positions.php +40 -0
  91. package/server/migrations/2026_10_12_000001_add_deleted_at_to_tracking_sessions_tables.php +32 -0
  92. package/server/resources/views/labels/default.php +2 -2
  93. package/server/resources/views/labels/entity-label.php +2 -2
  94. package/server/resources/views/labels/waypoint-label.php +2 -2
  95. package/server/src/Auth/Schemas/FleetOps.php +5 -0
  96. package/server/src/Console/Commands/ProcessOperationalAlerts.php +1 -0
  97. package/server/src/Console/Commands/PruneTelematicsData.php +101 -26
  98. package/server/src/Events/OrderChanged.php +257 -0
  99. package/server/src/Events/OrderDriverUnassigned.php +68 -0
  100. package/server/src/Exceptions/OrderEditLockedException.php +32 -0
  101. package/server/src/Expansions/CompanyExpansion.php +3 -2
  102. package/server/src/Expansions/UserExpansion.php +12 -10
  103. package/server/src/Http/Controllers/Api/v1/CustomerController.php +108 -18
  104. package/server/src/Http/Controllers/Api/v1/DriverController.php +95 -10
  105. package/server/src/Http/Controllers/Api/v1/EntityController.php +66 -0
  106. package/server/src/Http/Controllers/Api/v1/FleetController.php +10 -4
  107. package/server/src/Http/Controllers/Api/v1/OrderController.php +139 -36
  108. package/server/src/Http/Controllers/Api/v1/PayloadController.php +76 -8
  109. package/server/src/Http/Controllers/Api/v1/PlaceController.php +3 -3
  110. package/server/src/Http/Controllers/Api/v1/TrackingNumberController.php +6 -32
  111. package/server/src/Http/Controllers/Api/v1/VehicleController.php +5 -0
  112. package/server/src/Http/Controllers/Internal/v1/ContactController.php +3 -0
  113. package/server/src/Http/Controllers/Internal/v1/DriverController.php +10 -0
  114. package/server/src/Http/Controllers/Internal/v1/FleetController.php +16 -2
  115. package/server/src/Http/Controllers/Internal/v1/InspectionSubmissionController.php +13 -8
  116. package/server/src/Http/Controllers/Internal/v1/IssueController.php +2 -0
  117. package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +4 -2
  118. package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +93 -11
  119. package/server/src/Http/Controllers/Internal/v1/OrderController.php +84 -24
  120. package/server/src/Http/Controllers/Internal/v1/PositionController.php +22 -0
  121. package/server/src/Http/Controllers/Internal/v1/ProofController.php +55 -4
  122. package/server/src/Http/Controllers/Internal/v1/SettingController.php +303 -10
  123. package/server/src/Http/Controllers/Internal/v1/TrailerController.php +1 -0
  124. package/server/src/Http/Controllers/Internal/v1/VehicleController.php +1 -0
  125. package/server/src/Http/Controllers/Public/TrackingController.php +518 -0
  126. package/server/src/Http/Filter/ContactFilter.php +1 -1
  127. package/server/src/Http/Filter/InspectionFormFilter.php +23 -0
  128. package/server/src/Http/Filter/InspectionSubmissionFilter.php +23 -0
  129. package/server/src/Http/Filter/MaintenanceFilter.php +23 -0
  130. package/server/src/Http/Filter/OrderFilter.php +39 -4
  131. package/server/src/Http/Filter/ProofFilter.php +18 -0
  132. package/server/src/Http/Filter/RouteFilter.php +18 -0
  133. package/server/src/Http/Filter/TelematicFilter.php +23 -0
  134. package/server/src/Http/Filter/WarrantyFilter.php +23 -0
  135. package/server/src/Http/Requests/CancelOrderRequest.php +2 -1
  136. package/server/src/Http/Resources/v1/Concerns/ResolvesPublicRelationFields.php +14 -1
  137. package/server/src/Http/Resources/v1/Index/Customer.php +18 -0
  138. package/server/src/Http/Resources/v1/Index/Order.php +11 -2
  139. package/server/src/Http/Resources/v1/PublicOrderTracking.php +153 -0
  140. package/server/src/Http/Resources/v1/TrackingNumber.php +8 -34
  141. package/server/src/Http/Resources/v1/Zone.php +31 -23
  142. package/server/src/Jobs/FinalizeApiOrderCreation.php +3 -1
  143. package/server/src/Jobs/ProcessAllocationJob.php +16 -6
  144. package/server/src/Jobs/PublishTrackingUpdate.php +50 -0
  145. package/server/src/Listeners/HandleGeofenceEntered.php +31 -15
  146. package/server/src/Listeners/HandleOrderCanceled.php +9 -1
  147. package/server/src/Listeners/HandleUserRemovedFromCompany.php +2 -1
  148. package/server/src/Listeners/PublishTrackingUpdates.php +27 -0
  149. package/server/src/Mail/CustomerCredentialsMail.php +4 -2
  150. package/server/src/Models/AssetConnection.php +3 -0
  151. package/server/src/Models/Contact.php +3 -0
  152. package/server/src/Models/Device.php +28 -0
  153. package/server/src/Models/DeviceEvent.php +7 -0
  154. package/server/src/Models/Driver.php +20 -7
  155. package/server/src/Models/Entity.php +12 -4
  156. package/server/src/Models/Fleet.php +11 -32
  157. package/server/src/Models/FleetDriver.php +3 -0
  158. package/server/src/Models/FleetVehicle.php +3 -0
  159. package/server/src/Models/FuelReport.php +5 -13
  160. package/server/src/Models/Issue.php +4 -16
  161. package/server/src/Models/Order.php +200 -9
  162. package/server/src/Models/Payload.php +227 -35
  163. package/server/src/Models/Place.php +7 -1
  164. package/server/src/Models/ServiceArea.php +7 -0
  165. package/server/src/Models/ServiceRate.php +7 -17
  166. package/server/src/Models/TrackingNumber.php +101 -2
  167. package/server/src/Models/TrackingSession.php +33 -0
  168. package/server/src/Models/TrackingSessionGrant.php +22 -0
  169. package/server/src/Models/TrackingStatus.php +6 -0
  170. package/server/src/Models/Vehicle.php +21 -2
  171. package/server/src/Models/Vendor.php +7 -0
  172. package/server/src/Models/Waypoint.php +13 -4
  173. package/server/src/Notifications/OrderAssigned.php +2 -1
  174. package/server/src/Notifications/OrderCanceled.php +7 -1
  175. package/server/src/Notifications/OrderChanged.php +87 -0
  176. package/server/src/Notifications/OrderCompleted.php +2 -1
  177. package/server/src/Notifications/OrderDispatchFailed.php +2 -1
  178. package/server/src/Notifications/OrderDispatched.php +2 -1
  179. package/server/src/Notifications/OrderFailed.php +2 -1
  180. package/server/src/Notifications/OrderUnassigned.php +66 -0
  181. package/server/src/Notifications/WaypointCompleted.php +2 -1
  182. package/server/src/Observers/CompanyUserObserver.php +8 -7
  183. package/server/src/Observers/DriverObserver.php +6 -1
  184. package/server/src/Observers/OrderObserver.php +141 -1
  185. package/server/src/Observers/TrackingNumberObserver.php +18 -6
  186. package/server/src/Observers/UserObserver.php +2 -1
  187. package/server/src/Observers/VehicleObserver.php +8 -3
  188. package/server/src/Orchestration/Engines/RouteSequencingEngine.php +21 -3
  189. package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +38 -8
  190. package/server/src/Orchestration/OrchestrationEngineRegistry.php +61 -1
  191. package/server/src/Orchestration/Support/OrchestratorSettings.php +61 -0
  192. package/server/src/Orchestration/Support/RouteMetrics.php +165 -0
  193. package/server/src/Providers/EventServiceProvider.php +11 -0
  194. package/server/src/Providers/FleetOpsServiceProvider.php +13 -0
  195. package/server/src/Support/ApiCacheThrottle.php +76 -0
  196. package/server/src/Support/LiveOrderQuery.php +3 -1
  197. package/server/src/Support/OrderEdit.php +365 -0
  198. package/server/src/Support/OrderEditPolicy.php +292 -0
  199. package/server/src/Support/ProfileAccountManager.php +54 -1
  200. package/server/src/Support/ResolvesOrderServiceStops.php +5 -0
  201. package/server/src/Support/SocketChannels.php +346 -0
  202. package/server/src/Support/Telematics/TelematicService.php +7 -2
  203. package/server/src/Support/Telematics/Telemetry/Inbox.php +8 -1
  204. package/server/src/Support/TrackingChannel.php +55 -0
  205. package/server/src/Support/TrackingCode.php +242 -0
  206. package/server/src/Support/TrackingPage/TrackingAccess.php +356 -0
  207. package/server/src/Support/TrackingPage/TrackingPageConfig.php +264 -0
  208. package/server/src/Support/TrackingPage/TrackingRecipient.php +111 -0
  209. package/server/src/Support/TrackingPage/TrackingResolver.php +201 -0
  210. package/server/src/Support/TrackingPage/TrackingTarget.php +40 -0
  211. package/server/src/Support/TrackingPage/TrackingView.php +543 -0
  212. package/server/src/Support/TrackingPublisher.php +261 -0
  213. package/server/src/Support/TrackingScope.php +182 -0
  214. package/server/src/Support/TrackingUpdate.php +402 -0
  215. package/server/src/Support/Utils.php +15 -3
  216. package/server/src/Traits/HasTrackingNumber.php +2 -0
  217. package/server/src/routes.php +39 -7
  218. package/server/tests/ApiCustomerControllerContractsTest.php +54 -7
  219. package/server/tests/ApiDriverPasswordContractsTest.php +25 -21
  220. package/server/tests/ApiEntityControllerContractsTest.php +84 -0
  221. package/server/tests/ApiOrderControllerContractsTest.php +245 -0
  222. package/server/tests/ApiPayloadControllerContractsTest.php +121 -0
  223. package/server/tests/ApiPlaceControllerContractsTest.php +1 -1
  224. package/server/tests/ApiTrackingNumberControllerContractsTest.php +6 -9
  225. package/server/tests/CompactResourceSerializationTest.php +23 -59
  226. package/server/tests/ControllerFilterContractsTest.php +1 -1
  227. package/server/tests/CustomerContactIdentitySafetyTest.php +1 -1
  228. package/server/tests/EventContractsTest.php +26 -60
  229. package/server/tests/ExpansionContractsTest.php +15 -2
  230. package/server/tests/Feature/Http/Api/CustomerControllerHelperSeamsTest.php +29 -3
  231. package/server/tests/Feature/Http/Api/DriverControllerAuthFlowsTest.php +23 -0
  232. package/server/tests/Feature/Http/Api/OrderControllerNearbyFiltersTest.php +16 -16
  233. package/server/tests/Feature/Http/Api/OrderControllerQueryFiltersTest.php +41 -14
  234. package/server/tests/Feature/Http/Api/TrackingNumberControllerHelpersTest.php +57 -22
  235. package/server/tests/Feature/Http/Internal/DriverControllerCreateRecordTest.php +23 -9
  236. package/server/tests/Feature/Http/Internal/OrchestrationControllerContractsTest.php +171 -1
  237. package/server/tests/Feature/Http/Internal/OrderControllerContractsTest.php +110 -14
  238. package/server/tests/Feature/Http/Internal/OrderControllerHelpersTest.php +7 -5
  239. package/server/tests/Feature/Http/Internal/PositionControllerReplayChannelTest.php +135 -0
  240. package/server/tests/Feature/Http/Internal/ProofControllerContractsTest.php +3 -3
  241. package/server/tests/Feature/Http/Internal/ProofControllerRecentTest.php +170 -0
  242. package/server/tests/Feature/Http/Public/TrackingControllerTest.php +495 -0
  243. package/server/tests/IndexCustomerPhotoTest.php +151 -0
  244. package/server/tests/ModelAccessorContractsTest.php +4 -3
  245. package/server/tests/NotificationAndMailContractsTest.php +5 -8
  246. package/server/tests/ObserverContractsTest.php +72 -10
  247. package/server/tests/OrderActivityFlowRegressionTest.php +3 -2
  248. package/server/tests/OrderFilterExecutionTest.php +167 -2
  249. package/server/tests/ProcessAllocationJobContractsTest.php +20 -0
  250. package/server/tests/PublicOrderTrackingResourceTest.php +221 -0
  251. package/server/tests/QueueJobContractsTest.php +2 -1
  252. package/server/tests/RequestContractsTest.php +1 -1
  253. package/server/tests/RouteRegistrationExecutionTest.php +26 -0
  254. package/server/tests/RouteSequencingEngineTest.php +17 -0
  255. package/server/tests/SettingControllerContractsTest.php +110 -0
  256. package/server/tests/Support/TrackingPageDatabase.php +200 -0
  257. package/server/tests/TenantScopingTest.php +206 -0
  258. package/server/tests/TrackingPageSettingsTest.php +343 -0
  259. package/server/tests/Unit/Console/PruneTelematicsDataCommandTest.php +51 -0
  260. package/server/tests/Unit/Http/Filter/ContactFilterAddressTest.php +61 -0
  261. package/server/tests/Unit/Http/Resources/IndexOrderResourceTest.php +30 -0
  262. package/server/tests/Unit/Jobs/FinalizeApiOrderCreationDispatchGuardTest.php +266 -0
  263. package/server/tests/Unit/Listeners/HandleGeofenceEnteredTest.php +182 -22
  264. package/server/tests/Unit/Listeners/HandleUserRemovedFromCompanyTest.php +5 -0
  265. package/server/tests/Unit/Models/DriverAssignVehicleTest.php +81 -0
  266. package/server/tests/Unit/Models/FleetTest.php +4 -3
  267. package/server/tests/Unit/Models/OrderCancelReasonTest.php +143 -0
  268. package/server/tests/Unit/Models/OrderPayloadConfigAndDistanceTest.php +60 -0
  269. package/server/tests/Unit/Models/OrderPayloadRouteTest.php +4 -2
  270. package/server/tests/Unit/Models/PayloadTest.php +18 -4
  271. package/server/tests/Unit/Models/ServiceRatePersistenceAndServicabilityTest.php +2 -2
  272. package/server/tests/Unit/Models/TrackingNumberTest.php +67 -6
  273. package/server/tests/Unit/Models/VehicleTest.php +16 -2
  274. package/server/tests/Unit/Models/WaypointTest.php +4 -3
  275. package/server/tests/Unit/Notifications/OrderChangeNotificationsTest.php +59 -0
  276. package/server/tests/Unit/Notifications/TerminalOrderNotificationsTest.php +3 -3
  277. package/server/tests/Unit/Observers/DriverDeletionCleanupTest.php +158 -0
  278. package/server/tests/Unit/Observers/FleetOpsCompanyUserAndServiceAreaObserversTest.php +20 -0
  279. package/server/tests/Unit/Observers/ObserverListenerSeamsTest.php +3 -3
  280. package/server/tests/Unit/Observers/OrderAssignmentObserverTest.php +100 -0
  281. package/server/tests/Unit/Observers/OrderDeleteCascadeTest.php +213 -0
  282. package/server/tests/Unit/Observers/VehicleObserverDeleteTest.php +67 -0
  283. package/server/tests/Unit/Orchestration/EngineSelectionAndRouteMetricsTest.php +336 -0
  284. package/server/tests/Unit/Orchestration/Engines/VroomOrchestrationEngineLifecycleTest.php +8 -1
  285. package/server/tests/Unit/Support/ApiCacheDependenciesTest.php +347 -0
  286. package/server/tests/Unit/Support/OrderEditPolicyTest.php +156 -0
  287. package/server/tests/Unit/Support/OrderOperationsTest.php +514 -0
  288. package/server/tests/Unit/Support/OsrmProofAndIssueFilterTest.php +4 -3
  289. package/server/tests/Unit/Support/ProfileAccountManagerTest.php +141 -0
  290. package/server/tests/Unit/Support/QuerySeamsTest.php +5 -1
  291. package/server/tests/Unit/Support/SocketChannelsTest.php +396 -0
  292. package/server/tests/Unit/Support/TrackingChannelTest.php +232 -0
  293. package/server/tests/Unit/Support/TrackingCodeTest.php +186 -0
  294. package/server/tests/Unit/Support/TrackingPage/TrackingAccessTest.php +200 -0
  295. package/server/tests/Unit/Support/TrackingPage/TrackingRecipientTest.php +51 -0
  296. package/server/tests/Unit/Support/TrackingPage/TrackingResolverTest.php +181 -0
  297. package/server/tests/Unit/Support/TrackingPage/TrackingViewTest.php +479 -0
  298. package/server/tests/Unit/Support/TrackingPublisherTest.php +425 -0
  299. package/server/tests/Unit/Support/TrackingUpdateTest.php +363 -0
  300. package/server/tests/Unit/Support/UtilsAdditionalTest.php +9 -0
  301. package/server/tests/Unit/Support/UtilsGeoMatrixAndVendorTest.php +25 -0
  302. package/server/tests/VehicleResourceContractsTest.php +46 -0
  303. package/server/tests/VroomOrchestrationEngineTest.php +34 -1
  304. package/server/tests/ZoneGeofenceSettingsResourceTest.php +121 -0
  305. package/translations/ar-ae.yml +274 -0
  306. package/translations/bg-bg.yaml +274 -0
  307. package/translations/en-us.yaml +287 -0
  308. package/translations/es-pa.yaml +274 -0
  309. package/translations/fr-fr.yaml +274 -0
  310. package/translations/mn-mn.yaml +274 -0
  311. package/translations/pt-br.yaml +274 -0
  312. package/translations/ru-ru.yaml +276 -2
  313. package/translations/uk-ua.yaml +275 -1
  314. package/translations/vi-vn.yaml +274 -0
  315. package/addon/components/cell/contact-identity.hbs +0 -1
  316. package/addon/components/cell/customer-identity.hbs +0 -1
  317. package/addon/components/cell/driver-identity.hbs +0 -1
  318. package/addon/components/cell/fleet-identity.hbs +0 -1
  319. package/addon/components/cell/order-identity.hbs +0 -1
  320. package/addon/components/cell/place-identity.hbs +0 -1
  321. package/addon/components/cell/vehicle-identity.hbs +0 -1
  322. package/addon/components/cell/vendor-identity.hbs +0 -1
  323. package/addon/components/contact/pill.hbs +0 -24
  324. package/addon/components/contact/summary.hbs +0 -1
  325. package/addon/components/customer/pill.hbs +0 -24
  326. package/addon/components/customer/summary.hbs +0 -1
  327. package/addon/components/driver/pill.hbs +0 -24
  328. package/addon/components/driver/summary.hbs +0 -1
  329. package/addon/components/fleet/pill.hbs +0 -24
  330. package/addon/components/fleet/summary.hbs +0 -1
  331. package/addon/components/order/pill.hbs +0 -24
  332. package/addon/components/order/summary.hbs +0 -1
  333. package/addon/components/place/pill.hbs +0 -24
  334. package/addon/components/place/summary.hbs +0 -1
  335. package/addon/components/select-option/contact.hbs +0 -12
  336. package/addon/components/select-option/customer.hbs +0 -12
  337. package/addon/components/select-option/driver.hbs +0 -12
  338. package/addon/components/select-option/fleet.hbs +0 -12
  339. package/addon/components/select-option/order.hbs +0 -12
  340. package/addon/components/select-option/place.hbs +0 -12
  341. package/addon/components/select-option/vehicle.hbs +0 -12
  342. package/addon/components/select-option/vendor.hbs +0 -12
  343. package/addon/components/vehicle/pill.hbs +0 -24
  344. package/addon/components/vehicle/summary.hbs +0 -1
  345. package/addon/components/vendor/pill.hbs +0 -24
  346. package/addon/components/vendor/summary.hbs +0 -1
  347. package/app/components/cell/contact-identity.js +0 -1
  348. package/app/components/cell/customer-identity.js +0 -1
  349. package/app/components/cell/driver-identity.js +0 -1
  350. package/app/components/cell/fleet-identity.js +0 -1
  351. package/app/components/cell/order-identity.js +0 -1
  352. package/app/components/cell/place-identity.js +0 -1
  353. package/app/components/cell/vehicle-identity.js +0 -1
  354. package/app/components/cell/vendor-identity.js +0 -1
  355. package/app/components/contact/pill.js +0 -1
  356. package/app/components/contact/summary.js +0 -1
  357. package/app/components/customer/pill.js +0 -1
  358. package/app/components/customer/summary.js +0 -1
  359. package/app/components/driver/pill.js +0 -1
  360. package/app/components/driver/summary.js +0 -1
  361. package/app/components/fleet/pill.js +0 -1
  362. package/app/components/fleet/summary.js +0 -1
  363. package/app/components/order/pill.js +0 -1
  364. package/app/components/order/summary.js +0 -1
  365. package/app/components/place/pill.js +0 -1
  366. package/app/components/place/summary.js +0 -1
  367. package/app/components/select-option/contact.js +0 -1
  368. package/app/components/select-option/customer.js +0 -1
  369. package/app/components/select-option/driver.js +0 -1
  370. package/app/components/select-option/fleet.js +0 -1
  371. package/app/components/select-option/order.js +0 -1
  372. package/app/components/select-option/place.js +0 -1
  373. package/app/components/select-option/vehicle.js +0 -1
  374. package/app/components/select-option/vendor.js +0 -1
  375. package/app/components/vehicle/pill.js +0 -1
  376. package/app/components/vehicle/summary.js +0 -1
  377. package/app/components/vendor/pill.js +0 -1
  378. package/app/components/vendor/summary.js +0 -1
@@ -0,0 +1,212 @@
1
+ import Controller from '@ember/controller';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { action } from '@ember/object';
5
+ import { task, timeout } from 'ember-concurrency';
6
+ import trackingPageTheme, { contrastRatio, inkFor, normalizeHex, DEFAULT_ACCENT } from '../../utils/tracking-page-theme';
7
+
8
+ /**
9
+ * The locales a tracking page can be shown in, labelled in their own language.
10
+ */
11
+ export const TRACKING_PAGE_LOCALES = [
12
+ { code: 'en-us', label: 'English' },
13
+ { code: 'ar-ae', label: 'العربية' },
14
+ { code: 'bg-bg', label: 'Български' },
15
+ { code: 'es-pa', label: 'Español' },
16
+ { code: 'fr-fr', label: 'Français' },
17
+ { code: 'mn-mn', label: 'Монгол' },
18
+ { code: 'pt-br', label: 'Português' },
19
+ { code: 'ru-ru', label: 'Русский' },
20
+ { code: 'uk-ua', label: 'Українська' },
21
+ { code: 'vi-vn', label: 'Tiếng Việt' },
22
+ ];
23
+
24
+ /**
25
+ * Keys the server adds to the saved config when it reads it back. They are facts about
26
+ * the instance, not settings, so they are kept apart and never sent back on save.
27
+ */
28
+ const READ_ONLY_KEYS = ['slug_validation', 'accent_ink', 'accent_contrast', 'sms_available', 'customer_portal_installed', 'admin'];
29
+
30
+ /**
31
+ * Settings::TrackingPageController
32
+ *
33
+ * The company's customer tracking page: which pages are on and at what address, branding,
34
+ * how customers prove who they are, and what verified customers see.
35
+ */
36
+ export default class SettingsTrackingPageController extends Controller {
37
+ @service fetch;
38
+ @service notifications;
39
+ @service intl;
40
+ @service currentUser;
41
+
42
+ @tracked config = null;
43
+ @tracked slugValidation = null;
44
+ @tracked smsAvailable = false;
45
+ @tracked customerPortalInstalled = false;
46
+ @tracked loadFailed = false;
47
+
48
+ /**
49
+ * Take the settings as the server returns them.
50
+ */
51
+ load(settings) {
52
+ if (!settings) {
53
+ this.loadFailed = true;
54
+ return;
55
+ }
56
+
57
+ const config = { ...settings };
58
+ READ_ONLY_KEYS.forEach((key) => delete config[key]);
59
+
60
+ this.config = config;
61
+ this.slugValidation = settings.slug_validation ?? null;
62
+ this.smsAvailable = settings.sms_available === true;
63
+ this.customerPortalInstalled = settings.customer_portal_installed === true;
64
+ this.loadFailed = false;
65
+ }
66
+
67
+ get accent() {
68
+ return normalizeHex(this.config?.branding?.accent) ?? DEFAULT_ACCENT;
69
+ }
70
+
71
+ get accentInk() {
72
+ return inkFor(this.accent);
73
+ }
74
+
75
+ get accentContrast() {
76
+ return contrastRatio(this.accent, this.accentInk);
77
+ }
78
+
79
+ get accentReadable() {
80
+ return this.accentContrast >= 4.5;
81
+ }
82
+
83
+ get previewLightStyle() {
84
+ return trackingPageTheme(this.config?.branding, false);
85
+ }
86
+
87
+ get previewDarkStyle() {
88
+ return trackingPageTheme(this.config?.branding, true);
89
+ }
90
+
91
+ get companyName() {
92
+ return this.currentUser.companyName ?? '';
93
+ }
94
+
95
+ get displayName() {
96
+ return this.config?.branding?.display_name || this.companyName;
97
+ }
98
+
99
+ get orgPageBase() {
100
+ return `${window.location.origin}/~/t/`;
101
+ }
102
+
103
+ get orgPageUrl() {
104
+ return `${window.location.origin}/~/t/${encodeURIComponent(this.config?.org_page?.slug ?? '')}`;
105
+ }
106
+
107
+ get genericPageUrl() {
108
+ return `${window.location.origin}/~/track`;
109
+ }
110
+
111
+ get slugIsValid() {
112
+ return this.slugValidation?.valid === true;
113
+ }
114
+
115
+ get localeOptions() {
116
+ const enabled = this.config?.branding?.locales ?? [];
117
+ const defaultLocale = this.config?.branding?.default_locale;
118
+
119
+ return TRACKING_PAGE_LOCALES.map((locale) => ({
120
+ ...locale,
121
+ enabled: enabled.includes(locale.code),
122
+ isDefault: locale.code === defaultLocale,
123
+ }));
124
+ }
125
+
126
+ get linkTargetOptions() {
127
+ return ['auto', 'org', 'generic'].map((value) => ({ value, label: this.intl.t(`tracking-page.settings.links-target-${value}`) }));
128
+ }
129
+
130
+ get themeOptions() {
131
+ return ['system', 'light'].map((value) => ({ value, label: this.intl.t(`tracking-page.settings.theme-${value}`) }));
132
+ }
133
+
134
+ get driverContactOptions() {
135
+ return ['company', 'driver'].map((value) => ({ value, label: this.intl.t(`tracking-page.settings.driver-contact-${value}`) }));
136
+ }
137
+
138
+ /**
139
+ * Set one value by its dotted path, replacing the config so the form and preview update.
140
+ */
141
+ @action update(path, value) {
142
+ const config = JSON.parse(JSON.stringify(this.config));
143
+ const keys = path.split('.');
144
+ const last = keys.pop();
145
+ let target = config;
146
+ for (const key of keys) {
147
+ target = target[key];
148
+ }
149
+
150
+ target[last] = value;
151
+ this.config = config;
152
+ }
153
+
154
+ @action updateFromEvent(path, event) {
155
+ this.update(path, event.target.value);
156
+ }
157
+
158
+ @action updateNumber(path, event) {
159
+ this.update(path, parseInt(event.target.value, 10));
160
+ }
161
+
162
+ @action selectOption(path, option) {
163
+ this.update(path, option?.value ?? option);
164
+ }
165
+
166
+ @action updateSlug(event) {
167
+ const slug = event.target.value.toLowerCase().replace(/\s+/g, '-');
168
+ this.update('org_page.slug', slug);
169
+ this.validateSlug.perform(slug);
170
+ }
171
+
172
+ @action toggleLocale(code) {
173
+ const locales = this.config.branding.locales ?? [];
174
+ if (code === this.config.branding.default_locale) {
175
+ return;
176
+ }
177
+
178
+ this.update('branding.locales', locales.includes(code) ? locales.filter((locale) => locale !== code) : [...locales, code]);
179
+ }
180
+
181
+ @action setDefaultLocale(option) {
182
+ const code = option?.value ?? option;
183
+ const locales = this.config.branding.locales ?? [];
184
+ this.update('branding.default_locale', code);
185
+ if (!locales.includes(code)) {
186
+ this.update('branding.locales', [...locales, code]);
187
+ }
188
+ }
189
+
190
+ get defaultLocaleOptions() {
191
+ return TRACKING_PAGE_LOCALES.map((locale) => ({ value: locale.code, label: locale.label }));
192
+ }
193
+
194
+ @task({ restartable: true }) *validateSlug(slug) {
195
+ yield timeout(350);
196
+ try {
197
+ this.slugValidation = yield this.fetch.post('fleet-ops/settings/tracking-page-settings/validate-slug', { slug });
198
+ } catch (error) {
199
+ this.notifications.serverError(error);
200
+ }
201
+ }
202
+
203
+ @task *saveSettings() {
204
+ try {
205
+ const settings = yield this.fetch.post('fleet-ops/settings/tracking-page-settings', { trackingPage: this.config });
206
+ this.load(settings);
207
+ this.notifications.success(this.intl.t('tracking-page.settings.saved'));
208
+ } catch (error) {
209
+ this.notifications.serverError(error);
210
+ }
211
+ }
212
+ }
@@ -117,12 +117,34 @@ export default {
117
117
  icon: 'satellite-dish',
118
118
  component: new ExtensionComponent('@fleetbase/fleetops-engine', 'admin/telematics-settings'),
119
119
  }),
120
+ new MenuItem({
121
+ title: 'Tracking Page',
122
+ icon: 'magnifying-glass-location',
123
+ component: new ExtensionComponent('@fleetbase/fleetops-engine', 'admin/tracking-page-settings'),
124
+ }),
120
125
  ],
121
126
  {
122
127
  slug: 'fleet-ops',
123
128
  }
124
129
  );
125
130
 
131
+ // Links printed or emailed without the public `~/` prefix (/track-order?order=...) land
132
+ // inside the console. Signed-out visitors are sent on to the public route after login;
133
+ // registering the page in the console too shows it to signed-in staff instead of an
134
+ // empty console page.
135
+ for (const slug of ['track', 'track-order']) {
136
+ menuService.registerMenuItem(
137
+ 'console',
138
+ new MenuItem({
139
+ title: 'Track Order',
140
+ slug,
141
+ section: null,
142
+ view: null,
143
+ component: new ExtensionComponent('@fleetbase/fleetops-engine', 'tracking-page'),
144
+ })
145
+ );
146
+ }
147
+
126
148
  // Register track order button
127
149
  menuService.registerMenuItem(
128
150
  'auth:login',
@@ -135,7 +157,39 @@ export default {
135
157
  // btn-auth (ember-ui): the sign-in page's neutral button, matching the
136
158
  // console's "Continue with ..." provider buttons, hover included.
137
159
  wrapperClass: 'btn-block btn-auth',
138
- component: new ExtensionComponent('@fleetbase/fleetops-engine', 'order-tracking-lookup'),
160
+ component: new ExtensionComponent('@fleetbase/fleetops-engine', 'tracking-page'),
161
+ onClick: (menuItem) => {
162
+ universe.transitionMenuItem('virtual', menuItem);
163
+ },
164
+ })
165
+ );
166
+
167
+ // The customer tracking page: /~/track/{number} is the shared page.
168
+ menuService.registerMenuItem(
169
+ 'auth:login',
170
+ new MenuItem({
171
+ title: 'Track',
172
+ route: 'virtual',
173
+ slug: 'track',
174
+ type: 'link',
175
+ wrapperClass: 'hidden',
176
+ component: new ExtensionComponent('@fleetbase/fleetops-engine', 'tracking-page'),
177
+ onClick: (menuItem) => {
178
+ universe.transitionMenuItem('virtual', menuItem);
179
+ },
180
+ })
181
+ );
182
+
183
+ // A company's own tracking page: /~/t/{slug}/{number}.
184
+ menuService.registerMenuItem(
185
+ 'auth:login',
186
+ new MenuItem({
187
+ title: 'Company tracking',
188
+ route: 'virtual',
189
+ slug: 't',
190
+ type: 'link',
191
+ wrapperClass: 'hidden',
192
+ component: new ExtensionComponent('@fleetbase/fleetops-engine', 'tracking-page'),
139
193
  onClick: (menuItem) => {
140
194
  universe.transitionMenuItem('virtual', menuItem);
141
195
  },
@@ -413,6 +467,16 @@ export default {
413
467
  order: 80,
414
468
  default: true,
415
469
  }),
470
+ new Widget({
471
+ id: 'fleet-ops-proof-of-delivery-widget',
472
+ name: 'Proof of Delivery',
473
+ description: 'The latest proof of delivery photos, each linking to its order.',
474
+ icon: 'camera',
475
+ component: new ExtensionComponent('@fleetbase/fleetops-engine', 'widget/proof-of-delivery'),
476
+ grid_options: { w: 4, h: 9, minW: 3, minH: 6 },
477
+ category: 'Operations',
478
+ default: false,
479
+ }),
416
480
  new Widget({
417
481
  id: 'fleet-ops-geofence-violations-widget',
418
482
  name: 'Geofence Violations',
@@ -0,0 +1,16 @@
1
+ import { helper } from '@ember/component/helper';
2
+
3
+ // Each URL is written out in full so a production build's fingerprinting
4
+ // (broccoli-asset-rev) rewrites it to the hashed file name. An interpolated
5
+ // path such as `boxes/${size}.png` is never rewritten, so it misses the
6
+ // fingerprinted file and the server answers with the console's index.html.
7
+ const PARCEL_BOX_IMAGES = {
8
+ small: '/engines-dist/images/boxes/small.png',
9
+ medium: '/engines-dist/images/boxes/medium.png',
10
+ large: '/engines-dist/images/boxes/large.png',
11
+ 'x-large': '/engines-dist/images/boxes/x-large.png',
12
+ };
13
+
14
+ export default helper(function parcelBoxImage([size]) {
15
+ return PARCEL_BOX_IMAGES[size] ?? PARCEL_BOX_IMAGES.medium;
16
+ });
@@ -1,6 +1,5 @@
1
1
  import Route from '@ember/routing/route';
2
2
  import { inject as service } from '@ember/service';
3
- import { action } from '@ember/object';
4
3
 
5
4
  export default class OperationsOrdersIndexNewRoute extends Route {
6
5
  @service notifications;
@@ -9,9 +8,11 @@ export default class OperationsOrdersIndexNewRoute extends Route {
9
8
  @service intl;
10
9
  @service sidebar;
11
10
 
12
- @action willTransition() {
13
- if (this.controller) {
14
- this.controller.reset();
11
+ // Reset the draft only when leaving the route. A refresh of this route (e.g. after saving
12
+ // a place or customer from a modal) also transitions, and must keep what was entered.
13
+ resetController(controller, isExiting) {
14
+ if (isExiting) {
15
+ controller.reset();
15
16
  }
16
17
  }
17
18
 
@@ -61,7 +61,7 @@ export default class OperationsSchedulerIndexRoute extends Route {
61
61
  }
62
62
 
63
63
  resetController(controller) {
64
- // Close all socket channels when the dispatcher navigates away
64
+ // Close the board's own socket channels when the dispatcher navigates away
65
65
  // to prevent memory leaks and stale event handlers.
66
66
  controller.unsubscribeFromRealTimeUpdates();
67
67
  }
@@ -0,0 +1,31 @@
1
+ import Route from '@ember/routing/route';
2
+ import { inject as service } from '@ember/service';
3
+
4
+ export default class SettingsTrackingPageRoute extends Route {
5
+ @service notifications;
6
+ @service hostRouter;
7
+ @service abilities;
8
+ @service intl;
9
+ @service fetch;
10
+
11
+ beforeModel() {
12
+ if (this.abilities.cannot('fleet-ops view tracking-page-settings')) {
13
+ this.notifications.warning(this.intl.t('common.unauthorized-access'));
14
+ return this.hostRouter.transitionTo('console.fleet-ops');
15
+ }
16
+ }
17
+
18
+ async model() {
19
+ try {
20
+ return await this.fetch.get('fleet-ops/settings/tracking-page-settings');
21
+ } catch (error) {
22
+ this.notifications.serverError(error);
23
+ return null;
24
+ }
25
+ }
26
+
27
+ setupController(controller, model) {
28
+ super.setupController(controller, model);
29
+ controller.load(model);
30
+ }
31
+ }
package/addon/routes.js CHANGED
@@ -323,6 +323,7 @@ export default buildRoutes(function () {
323
323
  this.route('map');
324
324
  this.route('orchestrator');
325
325
  this.route('scheduling');
326
+ this.route('tracking-page');
326
327
  this.route('telematics');
327
328
  this.route('payments', function () {
328
329
  this.route('index', { path: '/' });
@@ -4,7 +4,7 @@ import { isBlank } from '@ember/utils';
4
4
  import { isArray } from '@ember/array';
5
5
  import { later } from '@ember/runloop';
6
6
  import { debug } from '@ember/debug';
7
- import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
7
+ import { isLatitude, isLongitude, isZoom } from '../utils/map-default-view';
8
8
 
9
9
  /**
10
10
  * Service for managing and retrieving user location data.
@@ -46,17 +46,30 @@ export default class LocationService extends Service {
46
46
  */
47
47
  @service fetch;
48
48
 
49
+ /**
50
+ * Company map settings, which carry the default map view.
51
+ * @type {MapSettingsService}
52
+ */
53
+ @service mapSettings;
54
+
49
55
  /**
50
56
  * Current latitude of the user.
51
57
  * @type {number}
52
58
  */
53
- @tracked latitude = this.DEFAULT_LATITUDE;
59
+ @tracked latitude = LocationService.DEFAULT_LATITUDE;
54
60
 
55
61
  /**
56
62
  * Current longitude of the user.
57
63
  * @type {number}
58
64
  */
59
- @tracked longitude = this.DEFAULT_LONGITUDE;
65
+ @tracked longitude = LocationService.DEFAULT_LONGITUDE;
66
+
67
+ /**
68
+ * Zoom suggested by the source of the location (a company default view or
69
+ * a country centre), or null to let the map use its own default.
70
+ * @type {number|null}
71
+ */
72
+ @tracked zoom = null;
60
73
 
61
74
  /**
62
75
  * Flag indicating whether the user's location has been located.
@@ -73,7 +86,7 @@ export default class LocationService extends Service {
73
86
  if (typeof this.latitude === 'number' && !isNaN(this.latitude) && this.latitude >= -90 && this.latitude <= 90) {
74
87
  return this.latitude;
75
88
  }
76
- return this.constructor.DEFAULT_LATITUDE;
89
+ return LocationService.DEFAULT_LATITUDE;
77
90
  }
78
91
 
79
92
  /**
@@ -85,14 +98,23 @@ export default class LocationService extends Service {
85
98
  if (typeof this.longitude === 'number' && !isNaN(this.longitude) && this.longitude >= -180 && this.longitude <= 180) {
86
99
  return this.longitude;
87
100
  }
88
- return this.constructor.DEFAULT_LONGITUDE;
101
+ return LocationService.DEFAULT_LONGITUDE;
102
+ }
103
+
104
+ /**
105
+ * Retrieves the zoom suggested by the current location source, or null.
106
+ * @returns {number|null}
107
+ */
108
+ getZoom() {
109
+ return isZoom(this.zoom) ? this.zoom : null;
89
110
  }
90
111
 
91
112
  /**
92
- * Attempts to fetch the user's location from various sources including cached data,
93
- * navigator geolocation, or WHOIS data. It first tries to get the cached coordinates.
94
- * If not available or outdated, it tries the browser's geolocation API.
95
- * As a fallback, it uses WHOIS data associated with the user's account.
113
+ * Resolves where maps should open. A company-configured default centre
114
+ * (Settings > Map) wins outright. Otherwise it tries the active order
115
+ * destinations, then the browser's geolocation API, then the IP lookup,
116
+ * then the centre of the company's country, then the hardcoded default.
117
+ * See utils/map-default-view for the full precedence.
96
118
  *
97
119
  * @returns {Promise<Object>} A promise that resolves to an object containing latitude and longitude.
98
120
  */
@@ -102,6 +124,14 @@ export default class LocationService extends Service {
102
124
  return { latitude: this.latitude, longitude: this.longitude };
103
125
  }
104
126
 
127
+ // The company's chosen starting point beats any guess about the user.
128
+ await this.mapSettings.load();
129
+ const defaultCenter = this.mapSettings.defaultMapCenter;
130
+ if (defaultCenter) {
131
+ this.updateLocation(defaultCenter);
132
+ return { latitude: defaultCenter.latitude, longitude: defaultCenter.longitude };
133
+ }
134
+
105
135
  try {
106
136
  const coordinates = await this.fetch.cachedGet('fleet-ops/live/coordinates', {}, { expirationInterval: 1, expirationIntervalUnit: 'hour' });
107
137
 
@@ -184,33 +214,51 @@ export default class LocationService extends Service {
184
214
  }
185
215
  }
186
216
 
217
+ /**
218
+ * Discards the resolved location and resolves it again, e.g. after the
219
+ * company's default map view changed. Listeners of `user.located` (the
220
+ * live map) move to the new location.
221
+ *
222
+ * @returns {Promise<Object>} The newly resolved coordinates.
223
+ */
224
+ async relocate() {
225
+ this.located = false;
226
+ return this.getUserLocation();
227
+ }
228
+
187
229
  /**
188
230
  * Retrieves the user's location based on WHOIS data associated with their account.
189
- * Defaults to predefined coordinates if WHOIS data is not available.
231
+ * When the IP lookup failed it falls back to the centre of the company's
232
+ * country, and only then to the predefined coordinates.
190
233
  *
191
234
  * @returns {Object} An object containing latitude and longitude from WHOIS data or default values.
192
235
  */
193
236
  getUserLocationFromWhois() {
194
- const whois = this.currentUser.getOption('whois', {});
195
- const coordinates = {
196
- latitude: getWithDefault(whois, 'latitude', this.DEFAULT_LATITUDE),
197
- longitude: getWithDefault(whois, 'longitude', this.DEFAULT_LONGITUDE),
198
- };
199
-
200
- this.updateLocation(coordinates);
201
- return coordinates;
237
+ const whois = this.currentUser.getOption('whois', {}) ?? {};
238
+ const latitude = Number(whois.latitude);
239
+ const longitude = Number(whois.longitude);
240
+ // The IP lookup's fallback reports null coordinates, which Number() turns into Null Island.
241
+ const hasWhoisCoordinates = whois.latitude != null && whois.longitude != null && isLatitude(latitude) && isLongitude(longitude);
242
+
243
+ const location = hasWhoisCoordinates
244
+ ? { latitude, longitude }
245
+ : (this.mapSettings.companyCountryCenter ?? { latitude: LocationService.DEFAULT_LATITUDE, longitude: LocationService.DEFAULT_LONGITUDE });
246
+
247
+ this.updateLocation(location);
248
+ return { latitude: location.latitude, longitude: location.longitude };
202
249
  }
203
250
 
204
251
  /**
205
252
  * Updates the service's tracked properties with the new location data.
206
253
  * Triggers an event to notify other parts of the application that the user's location has been updated.
207
254
  *
208
- * @param {Object} coordinates - An object containing the latitude and longitude to be set.
255
+ * @param {Object} coordinates - An object containing the latitude and longitude to be set, and optionally a suggested zoom.
209
256
  */
210
- updateLocation({ latitude, longitude }) {
257
+ updateLocation({ latitude, longitude, zoom = null }) {
211
258
  this.latitude = latitude;
212
259
  this.longitude = longitude;
260
+ this.zoom = isZoom(zoom) ? zoom : null;
213
261
  this.located = true;
214
- this.universe.trigger('user.located', { latitude, longitude });
262
+ this.universe.trigger('user.located', { latitude, longitude, zoom: this.zoom });
215
263
  }
216
264
  }
@@ -2,6 +2,7 @@ import Service from '@ember/service';
2
2
  import { tracked } from '@glimmer/tracking';
3
3
  import { inject as service } from '@ember/service';
4
4
  import { getLeafletTileUrl } from '../utils/leaflet-tile-url';
5
+ import { defaultMapCenter, companyCountryCenter } from '../utils/map-default-view';
5
6
 
6
7
  const DEFAULT_SETTINGS = {
7
8
  mapProvider: 'leaflet',
@@ -12,6 +13,11 @@ const DEFAULT_SETTINGS = {
12
13
  googleMapsMapType: 'roadmap',
13
14
  showGoogleMapsTrafficLayer: false,
14
15
  showGoogleMapsTransitLayer: false,
16
+ defaultMapLatitude: null,
17
+ defaultMapLongitude: null,
18
+ defaultMapZoom: null,
19
+ fitMapToVehicles: false,
20
+ companyMapCenter: null,
15
21
  };
16
22
 
17
23
  export default class MapSettingsService extends Service {
@@ -47,6 +53,28 @@ export default class MapSettingsService extends Service {
47
53
  return Boolean(this.settings.showGoogleMapsTransitLayer);
48
54
  }
49
55
 
56
+ /**
57
+ * The company's configured default centre for the live map, or null.
58
+ *
59
+ * @return {{latitude: Number, longitude: Number, zoom: Number}|null}
60
+ */
61
+ get defaultMapCenter() {
62
+ return defaultMapCenter(this.settings);
63
+ }
64
+
65
+ /**
66
+ * The centre of the company's country, used when nothing better is known.
67
+ *
68
+ * @return {{latitude: Number, longitude: Number, zoom: Number}|null}
69
+ */
70
+ get companyCountryCenter() {
71
+ return companyCountryCenter(this.settings);
72
+ }
73
+
74
+ get fitMapToVehicles() {
75
+ return Boolean(this.settings.fitMapToVehicles);
76
+ }
77
+
50
78
  get isGoogleMaps() {
51
79
  return this.mapProvider === 'google';
52
80
  }
@@ -35,7 +35,7 @@ export default class OrderAllocationService extends Service {
35
35
  @task *loadSettings() {
36
36
  try {
37
37
  const settings = yield this.fetch.get('fleet-ops/settings/orchestrator-settings');
38
- this.activeEngineId = settings.orchestrator_engine ?? 'greedy';
38
+ this.activeEngineId = settings.allocation_engine ?? 'greedy';
39
39
  return settings;
40
40
  } catch (error) {
41
41
  this.notifications.serverError(error);