@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,564 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { action } from '@ember/object';
5
+ import { htmlSafe } from '@ember/template';
6
+ import { task, timeout } from 'ember-concurrency';
7
+ import trackingPageTheme from '../utils/tracking-page-theme';
8
+ import TrackingLiveSource from '../utils/tracking-live-source';
9
+
10
+ /**
11
+ * The FleetOps API is mounted at the application root, so its public routes live under `public`.
12
+ * `rawError` makes a failed request reject with its JSON body, whose `code` or `error` drives the page.
13
+ */
14
+ const REQUEST_OPTIONS = { namespace: 'public', rawError: true };
15
+
16
+ /** How many neutral misses in a row before the page suggests a short break. */
17
+ const GENTLE_LIMIT_AFTER = 4;
18
+
19
+ /** The code length the server issues. */
20
+ export const CODE_LENGTH = 6;
21
+
22
+ /**
23
+ * The customer tracking page.
24
+ *
25
+ * Registered in the `auth:login` registry as `t`, `track` and `track-order`, so the
26
+ * console's public `virtual` routes serve it outside the console, signed in or not:
27
+ * `/~/track/{number}` on the shared page and `/~/t/{slug}/{number}` on a company's own.
28
+ * The older `?order=` (or `?number=`) and `?org=` query links still open.
29
+ *
30
+ * A tracking number alone shows a coarse status. A one-time code to the customer's own
31
+ * contact details unlocks their stops on this device; a signed-in customer, or staff of
32
+ * the owning company, sees them straight away. Live updates poll the same endpoint.
33
+ */
34
+ export default class TrackingPageComponent extends Component {
35
+ @service fetch;
36
+ @service intl;
37
+ @service urlSearchParams;
38
+ @service session;
39
+
40
+ @tracked screen = 'loading';
41
+ @tracked page = null;
42
+ @tracked data = null;
43
+ @tracked trackingInput = '';
44
+ @tracked lookupError = null;
45
+ @tracked misses = 0;
46
+ @tracked liveState = 'live';
47
+ @tracked toast = null;
48
+ @tracked orders = null;
49
+ @tracked prefersDark = false;
50
+
51
+ /* verification */
52
+ @tracked verifyStep = 'choose';
53
+ @tracked channel = null;
54
+ @tracked masked = null;
55
+ @tracked code = '';
56
+ @tracked attemptsLeft = 3;
57
+ @tracked cooldown = 0;
58
+ @tracked lockLeft = 0;
59
+ @tracked verifyMessage = null;
60
+
61
+ live = null;
62
+ ticker = null;
63
+
64
+ constructor() {
65
+ super(...arguments);
66
+ const fromPath = parseTrackingPath(window.location.pathname);
67
+ this.org = fromPath.org || this.urlSearchParams.get('org') || null;
68
+ this.trackingInput = fromPath.number || this.urlSearchParams.get('order') || this.urlSearchParams.get('number') || '';
69
+ this.watchColorScheme();
70
+ this.ticker = setInterval(() => this.tick(), 1000);
71
+ this.boot.perform();
72
+ }
73
+
74
+ willDestroy() {
75
+ super.willDestroy(...arguments);
76
+ clearInterval(this.ticker);
77
+ this.live?.stop();
78
+ this.colorScheme?.removeEventListener?.('change', this.onColorScheme);
79
+ }
80
+
81
+ /* ── Derived state ─────────────────────────────────────────────── */
82
+
83
+ get company() {
84
+ return this.data?.company ?? this.page?.company ?? {};
85
+ }
86
+
87
+ get monogram() {
88
+ let monogram = '';
89
+ for (const word of String(this.company.name ?? '').split(/\s+/)) {
90
+ if (word && monogram.length < 2) {
91
+ monogram += word[0].toUpperCase();
92
+ }
93
+ }
94
+
95
+ return monogram;
96
+ }
97
+
98
+ get dark() {
99
+ return this.company.theme !== 'light' && this.prefersDark;
100
+ }
101
+
102
+ get themeStyle() {
103
+ return htmlSafe(trackingPageTheme(this.company, this.dark));
104
+ }
105
+
106
+ get locale() {
107
+ return this.intl.primaryLocale ?? 'en-us';
108
+ }
109
+
110
+ get number() {
111
+ return (this.data?.tracking_number ?? this.trackingInput ?? '').trim();
112
+ }
113
+
114
+ get isFull() {
115
+ return this.data?.level >= 1;
116
+ }
117
+
118
+ get rateLimited() {
119
+ return this.misses >= GENTLE_LIMIT_AFTER;
120
+ }
121
+
122
+ get channels() {
123
+ return this.data?.verify?.channels ?? [];
124
+ }
125
+
126
+ get hasChannels() {
127
+ return this.channels.length > 0;
128
+ }
129
+
130
+ get signInUrl() {
131
+ return `/customer-portal/auth/login?redirect=${encodeURIComponent(window.location.pathname + window.location.search)}`;
132
+ }
133
+
134
+ get signedIn() {
135
+ return this.session.isAuthenticated === true;
136
+ }
137
+
138
+ get cooldownText() {
139
+ return formatCountdown(this.cooldown);
140
+ }
141
+
142
+ get lockText() {
143
+ return formatCountdown(this.lockLeft);
144
+ }
145
+
146
+ get codeBoxes() {
147
+ const digits = this.code.split('');
148
+ return Array.from({ length: CODE_LENGTH }, (_, index) => ({
149
+ digit: digits[index] ?? '',
150
+ active: (this.verifyStep === 'sent' || this.verifyStep === 'wrong') && index === Math.min(digits.length, CODE_LENGTH - 1),
151
+ }));
152
+ }
153
+
154
+ get selectedChannel() {
155
+ return this.channel ?? this.channels[0]?.type ?? null;
156
+ }
157
+
158
+ get otherChannel() {
159
+ return this.channels.find((channel) => channel.type !== this.selectedChannel) ?? null;
160
+ }
161
+
162
+ /* ── Loading ───────────────────────────────────────────────────── */
163
+
164
+ @task *boot() {
165
+ try {
166
+ this.page = yield this.fetch.get('track/config', this.query(), REQUEST_OPTIONS);
167
+ this.applyLocale(this.page?.company);
168
+ } catch {
169
+ this.screen = 'unavailable';
170
+ return;
171
+ }
172
+
173
+ if (this.trackingInput) {
174
+ yield this.lookup.perform(this.trackingInput, { quiet: true });
175
+ } else {
176
+ this.screen = 'lookup';
177
+ }
178
+
179
+ if (this.signedIn && !this.data) {
180
+ this.loadOrders.perform();
181
+ }
182
+ }
183
+
184
+ @task({ restartable: true }) *lookup(number, { quiet = false } = {}) {
185
+ this.lookupError = null;
186
+ const value = String(number ?? '').trim();
187
+ if (!value) {
188
+ this.lookupError = 'neutral';
189
+ return;
190
+ }
191
+
192
+ try {
193
+ const data = yield this.fetch.get(`track/${encodeURIComponent(value)}`, this.query(), REQUEST_OPTIONS);
194
+ this.misses = 0;
195
+ this.show(data);
196
+ this.replaceUrl(data.tracking_number);
197
+ } catch (error) {
198
+ this.misses += 1;
199
+ this.lookupError = this.rateLimited ? 'rate' : 'neutral';
200
+ this.screen = 'lookup';
201
+ if (quiet) {
202
+ this.misses = Math.max(0, this.misses - 1);
203
+ }
204
+ return error;
205
+ }
206
+ }
207
+
208
+ @task *refresh() {
209
+ return yield this.fetch.get(`track/${encodeURIComponent(this.number)}`, this.query(), REQUEST_OPTIONS);
210
+ }
211
+
212
+ @task *loadOrders() {
213
+ try {
214
+ const response = yield this.fetch.get('track/account/orders', {}, REQUEST_OPTIONS);
215
+ this.orders = response?.orders ?? [];
216
+ if (!this.data) {
217
+ this.screen = 'list';
218
+ }
219
+ } catch {
220
+ this.orders = null;
221
+ }
222
+ }
223
+
224
+ show(data) {
225
+ const before = this.data;
226
+ this.data = data;
227
+ this.applyLocale(data?.company);
228
+ this.screen = data?.level >= 1 ? 'track' : 'public';
229
+
230
+ if (before && before.stage !== data.stage && data.level >= 1) {
231
+ this.notify(this.intl.t(`tracking-page.page.stage-toast-${data.stage}`), '');
232
+ }
233
+
234
+ if (!this.isFull) {
235
+ this.live?.stop();
236
+ } else if (!this.live?.running) {
237
+ this.startLive();
238
+ }
239
+ }
240
+
241
+ startLive() {
242
+ this.live?.stop();
243
+
244
+ this.live = new TrackingLiveSource(() => this.refresh.perform(), { isActive: () => this.data?.stage === 'in_transit' });
245
+ this.live.start(this.onLiveUpdate, this.onLiveState);
246
+ }
247
+
248
+ onLiveUpdate = (data) => {
249
+ this.show(data);
250
+ };
251
+
252
+ onLiveState = (state) => {
253
+ this.liveState = state;
254
+ };
255
+
256
+ /* ── Lookup ────────────────────────────────────────────────────── */
257
+
258
+ @action updateTracking(event) {
259
+ this.trackingInput = event.target.value;
260
+ }
261
+
262
+ @action submitLookup(event) {
263
+ event?.preventDefault?.();
264
+ if (this.rateLimited) {
265
+ return;
266
+ }
267
+
268
+ this.lookup.perform(this.trackingInput);
269
+ }
270
+
271
+ @action lookupAnother() {
272
+ this.live?.stop();
273
+ this.data = null;
274
+ this.trackingInput = '';
275
+ this.lookupError = null;
276
+ this.replaceUrl(null);
277
+ this.screen = 'lookup';
278
+ }
279
+
280
+ @action openOrder(order) {
281
+ this.trackingInput = order.tracking_number;
282
+ this.lookup.perform(order.tracking_number);
283
+ }
284
+
285
+ @action backToOrders() {
286
+ this.live?.stop();
287
+ this.data = null;
288
+ this.replaceUrl(null);
289
+ this.screen = 'list';
290
+ }
291
+
292
+ /* ── Verification ──────────────────────────────────────────────── */
293
+
294
+ @action startVerify() {
295
+ this.verifyStep = this.hasChannels ? 'choose' : 'none';
296
+ this.channel = this.channels[0]?.type ?? null;
297
+ this.code = '';
298
+ this.verifyMessage = null;
299
+ this.screen = 'verify';
300
+ }
301
+
302
+ @action cancelVerify() {
303
+ this.screen = 'public';
304
+ }
305
+
306
+ @action pickChannel(type) {
307
+ this.channel = type;
308
+ }
309
+
310
+ @action switchChannel() {
311
+ if (this.otherChannel) {
312
+ this.channel = this.otherChannel.type;
313
+ this.sendCode.perform();
314
+ }
315
+ }
316
+
317
+ @task({ drop: true }) *sendCode() {
318
+ this.verifyStep = 'sending';
319
+ this.code = '';
320
+ this.verifyMessage = null;
321
+
322
+ try {
323
+ const response = yield this.fetch.post(`track/${encodeURIComponent(this.number)}/codes${this.queryString()}`, { channel: this.selectedChannel }, REQUEST_OPTIONS);
324
+ this.masked = response.masked;
325
+ this.cooldown = response.resend_after ?? 30;
326
+ this.attemptsLeft = 3;
327
+ this.verifyStep = 'sent';
328
+ } catch (error) {
329
+ this.handleVerifyError(error);
330
+ }
331
+ }
332
+
333
+ @action resend() {
334
+ if (this.cooldown === 0) {
335
+ this.sendCode.perform();
336
+ }
337
+ }
338
+
339
+ @action updateCode(event) {
340
+ if (['locked', 'sending', 'success'].includes(this.verifyStep)) {
341
+ return;
342
+ }
343
+
344
+ this.code = String(event.target.value ?? '')
345
+ .replace(/\D/g, '')
346
+ .slice(0, CODE_LENGTH);
347
+ if (this.verifyStep === 'wrong') {
348
+ this.verifyStep = 'sent';
349
+ }
350
+
351
+ if (this.code.length === CODE_LENGTH) {
352
+ this.verifyCode.perform(this.code);
353
+ }
354
+ }
355
+
356
+ @task({ drop: true }) *verifyCode(code) {
357
+ try {
358
+ const data = yield this.fetch.post(`track/${encodeURIComponent(this.number)}/codes/verify${this.queryString()}`, { code }, REQUEST_OPTIONS);
359
+ this.verifyStep = 'success';
360
+ yield timeout(700);
361
+ this.show(data);
362
+ this.notify(this.intl.t('tracking-page.page.verified-toast'), this.intl.t('tracking-page.page.verified-toast-help'));
363
+ } catch (error) {
364
+ this.code = '';
365
+ this.handleVerifyError(error);
366
+ }
367
+ }
368
+
369
+ handleVerifyError(error) {
370
+ const code = error?.error ?? error?.code;
371
+ if (code === 'invalid') {
372
+ this.attemptsLeft = error.attempts_left ?? 0;
373
+ this.verifyStep = 'wrong';
374
+ } else if (code === 'paused') {
375
+ this.lockLeft = error.retry_after ?? 300;
376
+ this.verifyStep = 'locked';
377
+ } else if (code === 'cooldown') {
378
+ this.cooldown = error.retry_after ?? 30;
379
+ this.verifyStep = 'sent';
380
+ } else if (code === 'expired') {
381
+ this.verifyStep = 'renew';
382
+ this.verifyMessage = 'expired';
383
+ } else if (code === 'limited') {
384
+ this.verifyStep = 'renew';
385
+ this.verifyMessage = 'limited';
386
+ } else {
387
+ this.verifyStep = this.hasChannels ? 'choose' : 'none';
388
+ this.verifyMessage = 'failed';
389
+ }
390
+ }
391
+
392
+ @task *signOut() {
393
+ try {
394
+ yield this.fetch.delete(`track/session${this.queryString()}`, {}, REQUEST_OPTIONS);
395
+ } catch {
396
+ // Signed out locally either way: the next lookup shows what the server allows.
397
+ }
398
+
399
+ this.live?.stop();
400
+ this.notify(this.intl.t('tracking-page.page.signed-out-toast'), '');
401
+ yield this.lookup.perform(this.number);
402
+ }
403
+
404
+ /* ── Full view actions ─────────────────────────────────────────── */
405
+
406
+ @task *saveInstructions(text) {
407
+ try {
408
+ const data = yield this.fetch.put(`track/${encodeURIComponent(this.number)}/instructions${this.queryString()}`, { text }, REQUEST_OPTIONS);
409
+ this.show(data);
410
+ this.notify(this.intl.t('tracking-page.page.instructions-saved'), '');
411
+ } catch {
412
+ this.notify(this.intl.t('tracking-page.page.action-failed'), '');
413
+ }
414
+ }
415
+
416
+ @task *reportProblem(message) {
417
+ try {
418
+ yield this.fetch.post(`track/${encodeURIComponent(this.number)}/report${this.queryString()}`, { message }, REQUEST_OPTIONS);
419
+ this.notify(this.intl.t('tracking-page.page.report-sent'), this.intl.t('tracking-page.page.report-sent-help', { name: this.company.name }));
420
+ return true;
421
+ } catch {
422
+ this.notify(this.intl.t('tracking-page.page.action-failed'), '');
423
+ return false;
424
+ }
425
+ }
426
+
427
+ @task *loadProof(id) {
428
+ return yield this.fetch.get(`track/${encodeURIComponent(this.number)}/proofs/${encodeURIComponent(id)}`, this.query(), REQUEST_OPTIONS);
429
+ }
430
+
431
+ @action share() {
432
+ const url = `${window.location.origin}${trackingPath(this.org, this.number)}`;
433
+ try {
434
+ if (navigator.share) {
435
+ navigator.share({ url }).catch(() => {});
436
+ } else {
437
+ navigator.clipboard?.writeText(url);
438
+ }
439
+ } catch {
440
+ // Copying is a convenience; the address bar still has the link.
441
+ }
442
+
443
+ this.notify(this.intl.t('tracking-page.page.share-copied'), this.intl.t('tracking-page.page.share-copied-help'));
444
+ }
445
+
446
+ /* ── Page chrome ───────────────────────────────────────────────── */
447
+
448
+ @action dismissToast() {
449
+ this.toast = null;
450
+ }
451
+
452
+ notify(title, text) {
453
+ this.toast = { title, text, id: Date.now() };
454
+ const id = this.toast.id;
455
+ setTimeout(() => {
456
+ if (this.toast?.id === id && !this.isDestroyed) {
457
+ this.toast = null;
458
+ }
459
+ }, 4500);
460
+ }
461
+
462
+ tick() {
463
+ if (this.cooldown > 0) {
464
+ this.cooldown -= 1;
465
+ }
466
+
467
+ if (this.verifyStep === 'locked') {
468
+ if (this.lockLeft > 1) {
469
+ this.lockLeft -= 1;
470
+ } else {
471
+ this.lockLeft = 0;
472
+ this.verifyStep = 'renew';
473
+ this.verifyMessage = 'unlocked';
474
+ }
475
+ }
476
+ }
477
+
478
+ applyLocale(company) {
479
+ const preferred = this.urlSearchParams.get('lang') || company?.default_locale;
480
+ if (!this.localeApplied && preferred && company?.locales?.includes(preferred)) {
481
+ this.localeApplied = true;
482
+ this.intl.setLocale([preferred]);
483
+ }
484
+ }
485
+
486
+ watchColorScheme() {
487
+ if (typeof window === 'undefined' || !window.matchMedia) {
488
+ return;
489
+ }
490
+
491
+ this.colorScheme = window.matchMedia('(prefers-color-scheme: dark)');
492
+ this.prefersDark = this.colorScheme.matches;
493
+ this.onColorScheme = (event) => {
494
+ this.prefersDark = event.matches;
495
+ };
496
+ this.colorScheme.addEventListener?.('change', this.onColorScheme);
497
+ }
498
+
499
+ /**
500
+ * Keep the address bar on the page's own link, so a reload or a copied link opens the
501
+ * same order. The console router never sees it: the page stays on the same route.
502
+ */
503
+ replaceUrl(number) {
504
+ try {
505
+ window.history.replaceState(window.history.state, '', trackingPath(this.org, number));
506
+ } catch {
507
+ // The address bar is a convenience; the page already shows the order.
508
+ }
509
+ }
510
+
511
+ query() {
512
+ return this.org ? { org: this.org } : {};
513
+ }
514
+
515
+ queryString() {
516
+ return this.org ? `?org=${encodeURIComponent(this.org)}` : '';
517
+ }
518
+ }
519
+
520
+ /**
521
+ * The page's link: `/~/t/{slug}/{number}` on a company's own page, `/~/track/{number}`
522
+ * on the shared one; without a number, the page's lookup screen.
523
+ */
524
+ export function trackingPath(org, number) {
525
+ const base = org ? `/~/t/${encodeURIComponent(org)}` : '/~/track';
526
+
527
+ return number ? `${base}/${encodeURIComponent(number)}` : base;
528
+ }
529
+
530
+ /**
531
+ * The company slug and tracking number in a page link's path, when it carries them.
532
+ */
533
+ export function parseTrackingPath(pathname) {
534
+ const segments = String(pathname ?? '')
535
+ .split('/')
536
+ .filter(Boolean)
537
+ .map((segment) => {
538
+ try {
539
+ return decodeURIComponent(segment);
540
+ } catch {
541
+ return segment;
542
+ }
543
+ });
544
+ const start = segments.indexOf('~');
545
+ const [page, ...rest] = start === -1 ? [] : segments.slice(start + 1);
546
+
547
+ if (page === 't') {
548
+ return { org: rest[0] || null, number: rest[1] || null };
549
+ }
550
+
551
+ if (page === 'track' || page === 'track-order') {
552
+ return { org: null, number: rest[0] || null };
553
+ }
554
+
555
+ return { org: null, number: null };
556
+ }
557
+
558
+ export function formatCountdown(seconds) {
559
+ const value = Math.max(0, Math.floor(seconds ?? 0));
560
+ const minutes = Math.floor(value / 60);
561
+ const rest = value % 60;
562
+
563
+ return `${minutes}:${rest < 10 ? '0' : ''}${rest}`;
564
+ }
@@ -389,7 +389,7 @@
389
389
 
390
390
  <InputGroup @name={{t "trailer.fields.purchased-at"}}>
391
391
  <DatePicker
392
- @value={{or (format-date-fns @resource.purchased_at "dd-MM-yyyy") null}}
392
+ @value={{or (format-date-fns @resource.purchased_at "yyyy-MM-dd") null}}
393
393
  @onChange={{fn (mut @resource.purchased_at)}}
394
394
  @placeholder={{t "trailer.placeholders.date"}}
395
395
  @disabled={{cannot-write @resource}}
@@ -400,7 +400,7 @@
400
400
  {{#if this.showLeaseExpiry}}
401
401
  <InputGroup @name={{t "trailer.fields.lease-expires-at"}} @helpText={{t "trailer.help.lease-expires-at"}}>
402
402
  <DatePicker
403
- @value={{or (format-date-fns @resource.lease_expires_at "dd-MM-yyyy") null}}
403
+ @value={{or (format-date-fns @resource.lease_expires_at "yyyy-MM-dd") null}}
404
404
  @onChange={{fn (mut @resource.lease_expires_at)}}
405
405
  @placeholder={{t "trailer.placeholders.date"}}
406
406
  @disabled={{cannot-write @resource}}
@@ -527,7 +527,7 @@
527
527
 
528
528
  <InputGroup @name="Purchase Date">
529
529
  <DatePicker
530
- @value={{or (format-date-fns @resource.purchased_at "dd-MM-yyyy") null}}
530
+ @value={{or (format-date-fns @resource.purchased_at "yyyy-MM-dd") null}}
531
531
  @onChange={{fn (mut @resource.purchased_at)}}
532
532
  @placeholder="DD-MM-YYYY"
533
533
  class="filter-date-input w-full flex-1"
@@ -536,7 +536,7 @@
536
536
 
537
537
  <InputGroup @name="Lease Expiry Date">
538
538
  <DatePicker
539
- @value={{or (format-date-fns @resource.lease_expires_at "dd-MM-yyyy") null}}
539
+ @value={{or (format-date-fns @resource.lease_expires_at "yyyy-MM-dd") null}}
540
540
  @onChange={{fn (mut @resource.lease_expires_at)}}
541
541
  @placeholder="DD-MM-YYYY"
542
542
  class="filter-date-input w-full flex-1"
@@ -555,7 +555,7 @@
555
555
 
556
556
  <InputGroup @name="First Payment Date">
557
557
  <DatePicker
558
- @value={{or (format-date-fns @resource.loan_first_payment "dd-MM-yyyy") null}}
558
+ @value={{or (format-date-fns @resource.loan_first_payment "yyyy-MM-dd") null}}
559
559
  @onChange={{fn (mut @resource.loan_first_payment)}}
560
560
  @placeholder="DD-MM-YYYY"
561
561
  class="filter-date-input w-full flex-1"
@@ -29,7 +29,7 @@
29
29
 
30
30
  <InputGroup @name="Start Date">
31
31
  <DatePicker
32
- @value={{@resource.start_date}}
32
+ @value={{format-date-fns @resource.start_date "yyyy-MM-dd"}}
33
33
  @onChange={{fn (mut @resource.start_date)}}
34
34
  @placeholder="Select Start Date"
35
35
  @disabled={{cannot-write @resource}}
@@ -39,7 +39,7 @@
39
39
 
40
40
  <InputGroup @name="End Date">
41
41
  <DatePicker
42
- @value={{@resource.end_date}}
42
+ @value={{format-date-fns @resource.end_date "yyyy-MM-dd"}}
43
43
  @onChange={{fn (mut @resource.end_date)}}
44
44
  @placeholder="Select End Date"
45
45
  @disabled={{cannot-write @resource}}