@fleetbase/fleetops-engine 0.6.49 → 0.6.51
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.
- package/README.md +185 -67
- package/addon/components/contact/panel-header.hbs +11 -48
- package/addon/components/customer/create-order-form.hbs +2 -2
- package/addon/components/customer/details.hbs +1 -2
- package/addon/components/customer/form.hbs +62 -50
- package/addon/components/customer/form.js +27 -1
- package/addon/components/customer/order-form.hbs +2 -2
- package/addon/components/customer/orders.hbs +50 -2
- package/addon/components/customer/orders.js +67 -5
- package/addon/components/display-place.hbs +2 -2
- package/addon/components/driver/form.hbs +1 -1
- package/addon/components/home/getting-started-guidance.hbs +113 -0
- package/addon/components/home/getting-started-guidance.js +107 -0
- package/addon/components/issue/details/comments.hbs +3 -0
- package/addon/components/issue/details/comments.js +3 -0
- package/addon/components/issue/details/correspondence.hbs +9 -0
- package/addon/components/issue/details/correspondence.js +83 -0
- package/addon/components/issue/details/documents.hbs +69 -0
- package/addon/components/issue/details/documents.js +85 -0
- package/addon/components/issue/details.hbs +220 -59
- package/addon/components/issue/details.js +245 -0
- package/addon/components/issue/form.hbs +19 -1
- package/addon/components/issue/panel-header.hbs +43 -0
- package/addon/components/issue/panel-header.js +22 -0
- package/addon/components/issue/timeline.hbs +40 -0
- package/addon/components/issue/timeline.js +45 -0
- package/addon/components/leaflet-tracking-marker.js +3 -0
- package/addon/components/map/drawer/position-listing.js +3 -0
- package/addon/components/map/google-live-map.js +6 -2
- package/addon/components/map/leaflet-live-map.hbs +48 -14
- package/addon/components/map/leaflet-live-map.js +201 -20
- package/addon/components/map/order-list-overlay.hbs +4 -4
- package/addon/components/modals/convert-customer-to-vendor.hbs +30 -0
- package/addon/components/modals/convert-customer-to-vendor.js +55 -0
- package/addon/components/modals/issue-assign.hbs +20 -0
- package/addon/components/modals/issue-assign.js +49 -0
- package/addon/components/modals/issue-close.hbs +30 -0
- package/addon/components/modals/issue-close.js +73 -0
- package/addon/components/modals/issue-status.hbs +20 -0
- package/addon/components/modals/issue-status.js +43 -0
- package/addon/components/modals/order-change-destination.hbs +46 -0
- package/addon/components/modals/order-change-destination.js +106 -0
- package/addon/components/modals/reset-customer-credentials.js +12 -6
- package/addon/components/modals/stop-activity.hbs +28 -0
- package/addon/components/modals/stop-activity.js +52 -0
- package/addon/components/modals/update-order-activity.hbs +78 -2
- package/addon/components/modals/update-order-activity.js +197 -5
- package/addon/components/orchestrator/resource-panel.hbs +0 -10
- package/addon/components/orchestrator/resource-panel.js +2 -4
- package/addon/components/order/activity-list.hbs +2 -2
- package/addon/components/order/activity-timeline.hbs +31 -29
- package/addon/components/order/details/activity.hbs +3 -3
- package/addon/components/order/details/activity.js +13 -2
- package/addon/components/order/details/documents.js +2 -0
- package/addon/components/order/details/proof.hbs +40 -38
- package/addon/components/order/details/proof.js +31 -4
- package/addon/components/order/details/purchase-rate.hbs +2 -2
- package/addon/components/order/details/route.hbs +11 -3
- package/addon/components/order/details/route.js +91 -14
- package/addon/components/order/details/tracking.hbs +101 -72
- package/addon/components/order/details/tracking.js +149 -2
- package/addon/components/order/details.hbs +5 -5
- package/addon/components/order/details.js +19 -1
- package/addon/components/order/form/details.hbs +3 -3
- package/addon/components/order/form/documents.js +11 -4
- package/addon/components/order/form/route.hbs +108 -104
- package/addon/components/order/form/route.js +37 -1
- package/addon/components/order/form/service-rate.hbs +2 -2
- package/addon/components/order/header.hbs +1 -1
- package/addon/components/order-config-manager/activity-flow.hbs +4 -1
- package/addon/components/order-config-manager/activity-flow.js +178 -12
- package/addon/components/place/address.js +1 -1
- package/addon/components/route-list.hbs +17 -29
- package/addon/components/route-list.js +42 -10
- package/addon/components/service-rate/details.hbs +42 -1
- package/addon/components/service-rate/form.hbs +119 -1
- package/addon/components/service-rate/form.js +59 -0
- package/addon/components/vehicle/form.js +1 -1
- package/addon/components/vehicle/pill.hbs +1 -1
- package/addon/components/vendor/personnel-manager.hbs +166 -0
- package/addon/components/vendor/personnel-manager.js +143 -0
- package/addon/components/widget/live-fleet.hbs +1 -0
- package/addon/components/widget/live-fleet.js +2 -7
- package/addon/components/widget/revenue-trend.hbs +1 -1
- package/addon/components/widget/revenue-trend.js +75 -2
- package/addon/controllers/management/contacts/customers/details.js +31 -13
- package/addon/controllers/management/contacts/customers.js +16 -5
- package/addon/controllers/management/contacts/index/details.js +31 -13
- package/addon/controllers/management/contacts/index.js +7 -0
- package/addon/controllers/management/issues/index/details.js +52 -6
- package/addon/controllers/management/vehicles/index/new.js +1 -1
- package/addon/controllers/management/vendors/index/details.js +4 -0
- package/addon/controllers/operations/orders/index/details.js +15 -7
- package/addon/controllers/operations/orders/index.js +15 -1
- package/addon/extension.js +19 -12
- package/addon/helpers/format-duration.js +1 -38
- package/addon/helpers/place-address-html.js +2 -2
- package/addon/initializers/load-leaflet-assets.js +5 -6
- package/addon/initializers/patch-ember-leaflet-tooltip-layer.js +51 -0
- package/addon/routes/management/issues/index/details.js +1 -1
- package/addon/routes/operations/service-rates/index.js +1 -1
- package/addon/routes.js +1 -0
- package/addon/services/contact-actions.js +231 -1
- package/addon/services/geofence.js +163 -19
- package/addon/services/getting-started.js +44 -0
- package/addon/services/issue-actions.js +71 -0
- package/addon/services/leaflet-contextmenu-manager.js +27 -0
- package/addon/services/leaflet-map-manager.js +2 -0
- package/addon/services/map-adapter/leaflet.js +19 -0
- package/addon/services/service-areas.js +3 -0
- package/addon/services/vehicle-actions.js +1 -1
- package/addon/styles/fleetops-engine.css +1127 -1
- package/addon/templates/management/contacts/customers/details.hbs +1 -1
- package/addon/templates/management/contacts/index/details.hbs +1 -1
- package/addon/templates/management/contacts.hbs +2 -2
- package/addon/templates/management/issues/index/details/index.hbs +3 -1
- package/addon/templates/management/issues/index/details.hbs +3 -2
- package/addon/templates/management/vendors/index/details/personnel.hbs +1 -2
- package/addon/templates/operations/orders/index/details/index.hbs +2 -2
- package/addon/templates/operations/orders/index.hbs +1 -1
- package/addon/templates/operations/service-rates/index/edit.hbs +1 -0
- package/addon/templates/operations/service-rates/index/new.hbs +1 -0
- package/addon/templates/settings/payments/onboard.hbs +8 -8
- package/addon/utils/fleet-ops-options.js +2 -1
- package/addon/utils/leaflet-draw-namespace-guard.js +22 -0
- package/addon/utils/leaflet-plugin-loader.js +219 -0
- package/addon/utils/normalize-order-config-flow.js +41 -0
- package/addon/utils/place-address-html.js +3 -2
- package/addon/utils/route-visualization.js +54 -7
- package/addon/utils/setup-customer-portal.js +4 -64
- package/app/components/home/getting-started-guidance.js +1 -0
- package/app/components/issue/details/comments.js +1 -0
- package/app/components/issue/details/correspondence.js +1 -0
- package/app/components/issue/details/documents.js +1 -0
- package/app/components/issue/panel-header.js +1 -0
- package/app/components/modals/convert-customer-to-vendor.js +1 -0
- package/app/components/modals/issue-assign.js +1 -0
- package/app/components/modals/issue-close.js +1 -0
- package/app/components/modals/issue-status.js +1 -0
- package/app/components/modals/order-change-destination.js +1 -0
- package/app/components/modals/stop-activity.js +1 -0
- package/app/components/vendor/personnel-manager.js +1 -0
- package/app/helpers/format-duration.js +1 -1
- package/app/services/getting-started.js +1 -0
- package/app/utils/leaflet-draw-namespace-guard.js +1 -0
- package/app/utils/leaflet-plugin-loader.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +5 -5
- package/server/migrations/2026_05_21_000001_add_geographic_rules_to_service_rate_fees_table.php +37 -0
- package/server/migrations/2026_05_25_000001_add_endpoint_tracking_refs_to_payloads_table.php +50 -0
- package/server/migrations/2026_05_27_000001_default_driver_vehicle_statuses_to_available.php +48 -0
- package/server/migrations/2026_05_31_000001_add_portal_fields_to_vendor_personnels_table.php +30 -0
- package/server/migrations/2026_06_03_000000_ensure_tags_column_on_issues_table.php +31 -0
- package/server/migrations/2026_06_03_000001_add_order_uuid_to_issues_table.php +25 -0
- package/server/migrations/2026_06_04_000001_backfill_order_transaction_subjects.php +39 -0
- package/server/migrations/2026_06_04_000002_backfill_order_transaction_directions.php +24 -0
- package/server/resources/views/labels/default.php +57 -49
- package/server/resources/views/labels/waypoint-label.php +27 -20
- package/server/resources/views/mail/customer-credentials.blade.php +16 -13
- package/server/seeders/Testing/ConnectivitySeeder.php +1 -0
- package/server/seeders/Testing/FleetSeeder.php +22 -22
- package/server/seeders/Testing/OrdersSeeder.php +6 -22
- package/server/seeders/Testing/VroomOrchestrationSeeder.php +21 -21
- package/server/src/Console/Commands/AuditCustomerUserConflicts.php +75 -0
- package/server/src/Exceptions/CustomerUserConflictException.php +13 -0
- package/server/src/Expansions/UserFilterExpansion.php +28 -0
- package/server/src/Http/Controllers/Api/v1/ContactController.php +17 -2
- package/server/src/Http/Controllers/Api/v1/CustomerController.php +876 -0
- package/server/src/Http/Controllers/Api/v1/DriverController.php +1 -1
- package/server/src/Http/Controllers/Api/v1/IssueController.php +2 -0
- package/server/src/Http/Controllers/Api/v1/OrderConfigController.php +54 -0
- package/server/src/Http/Controllers/Api/v1/OrderController.php +109 -80
- package/server/src/Http/Controllers/Api/v1/PlaceController.php +10 -58
- package/server/src/Http/Controllers/Api/v1/ServiceAreaController.php +2 -2
- package/server/src/Http/Controllers/Api/v1/VehicleController.php +20 -3
- package/server/src/Http/Controllers/Internal/v1/ContactController.php +154 -0
- package/server/src/Http/Controllers/Internal/v1/CustomerController.php +116 -6
- package/server/src/Http/Controllers/Internal/v1/GettingStartedController.php +17 -0
- package/server/src/Http/Controllers/Internal/v1/IssueController.php +251 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +101 -66
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +530 -52
- package/server/src/Http/Controllers/Internal/v1/PlaceController.php +10 -68
- package/server/src/Http/Controllers/Internal/v1/ServiceQuoteController.php +1 -1
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +2 -2
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +54 -1
- package/server/src/Http/Controllers/Internal/v1/VendorController.php +89 -0
- package/server/src/Http/Middleware/AuthenticateCustomerToken.php +34 -0
- package/server/src/Http/Requests/CreateCustomerOrderRequest.php +63 -0
- package/server/src/Http/Requests/CreateCustomerRequest.php +48 -0
- package/server/src/Http/Requests/CreateDriverRequest.php +1 -1
- package/server/src/Http/Requests/CreateIssueRequest.php +4 -0
- package/server/src/Http/Requests/CreateVehicleRequest.php +25 -1
- package/server/src/Http/Requests/Internal/CreateDriverRequest.php +1 -1
- package/server/src/Http/Requests/UpdateIssueRequest.php +4 -0
- package/server/src/Http/Requests/VerifyCreateCustomerRequest.php +29 -0
- package/server/src/Http/Resources/Internal/v1/OrderConfig.php +41 -0
- package/server/src/Http/Resources/v1/Customer.php +79 -0
- package/server/src/Http/Resources/v1/Index/Order.php +12 -9
- package/server/src/Http/Resources/v1/Issue.php +25 -0
- package/server/src/Http/Resources/v1/Order.php +20 -18
- package/server/src/Http/Resources/v1/OrderConfig.php +74 -0
- package/server/src/Http/Resources/v1/Payload.php +23 -20
- package/server/src/Http/Resources/v1/ServiceArea.php +33 -19
- package/server/src/Http/Resources/v1/ServiceRateFee.php +7 -0
- package/server/src/Listeners/HandleOrderDispatched.php +2 -2
- package/server/src/Mail/CustomerCredentialsMail.php +5 -6
- package/server/src/Models/Contact.php +122 -66
- package/server/src/Models/Customer.php +64 -0
- package/server/src/Models/Driver.php +12 -3
- package/server/src/Models/Entity.php +2 -2
- package/server/src/Models/Issue.php +47 -6
- package/server/src/Models/Order.php +62 -10
- package/server/src/Models/Payload.php +17 -1
- package/server/src/Models/ServiceArea.php +1 -1
- package/server/src/Models/ServiceRate.php +273 -1
- package/server/src/Models/ServiceRateFee.php +39 -9
- package/server/src/Models/TrackingNumber.php +8 -2
- package/server/src/Models/Vehicle.php +18 -2
- package/server/src/Models/VendorPersonnel.php +10 -1
- package/server/src/Models/Waypoint.php +2 -2
- package/server/src/Models/Zone.php +1 -1
- package/server/src/Notifications/LateDeparture.php +2 -2
- package/server/src/Notifications/ProlongedStoppage.php +2 -2
- package/server/src/Notifications/RouteDeviation.php +2 -2
- package/server/src/Observers/ContactObserver.php +2 -0
- package/server/src/Observers/PurchaseRateObserver.php +20 -0
- package/server/src/Observers/ServiceRateObserver.php +6 -6
- package/server/src/Observers/ZoneObserver.php +56 -0
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +1 -1
- package/server/src/Providers/FleetOpsServiceProvider.php +2 -0
- package/server/src/Support/Analytics/AbstractAnalytics.php +6 -6
- package/server/src/Support/Analytics/FuelEfficiency.php +2 -2
- package/server/src/Support/Analytics/OrdersByStatus.php +1 -1
- package/server/src/Support/Analytics/RevenueTrend.php +0 -1
- package/server/src/Support/Analytics/TopDrivers.php +10 -2
- package/server/src/Support/CustomerAuth.php +98 -0
- package/server/src/Support/GettingStarted.php +144 -0
- package/server/src/Support/LabelPdf.php +52 -0
- package/server/src/Support/Metrics/AbstractMetric.php +4 -4
- package/server/src/Support/PlaceSearch.php +282 -0
- package/server/src/Support/ResolvesOrderServiceStops.php +522 -0
- package/server/src/Tracking/TrackingContextBuilder.php +41 -38
- package/server/src/Tracking/TrackingIntelligenceService.php +109 -9
- package/server/src/Tracking/TrackingStop.php +13 -11
- package/server/src/routes.php +76 -10
- package/server/tests/AnalyticsRoutesTest.php +8 -0
- package/server/tests/CapacityAllocationEngineTest.php +10 -10
- package/server/tests/CustomerContactIdentitySafetyTest.php +95 -0
- package/server/tests/CustomerEndpointTest.php +199 -0
- package/server/tests/DriverVehicleStatusDefaultTest.php +39 -0
- package/server/tests/GettingStartedStatusTest.php +21 -0
- package/server/tests/LabelPdfRenderingTest.php +23 -0
- package/server/tests/LiveControllerViewportTest.php +60 -0
- package/server/tests/MetricsRegistryTest.php +4 -8
- package/server/tests/OrchestrationPayloadBuilderTest.php +2 -2
- package/server/tests/OrderActivityFlowRegressionTest.php +116 -0
- package/server/tests/OrderConfigEndpointTest.php +86 -0
- package/server/tests/OrderFileAttachmentTest.php +20 -0
- package/server/tests/ServiceAreaZoneApiShapeTest.php +78 -0
- package/server/tests/VehicleDriverAssignmentTest.php +18 -0
- package/translations/ar-ae.yml +9 -0
- package/translations/bg-bg.yaml +9 -0
- package/translations/en-us.yaml +12 -0
- package/translations/es-pa.yaml +9 -0
- package/translations/fr-fr.yaml +9 -0
- package/translations/mn-mn.yaml +9 -0
- package/translations/pt-br.yaml +9 -0
- package/translations/ru-ru.yaml +9 -0
- package/translations/vi-vn.yaml +9 -0
- package/server/migrations/2026_05_13_000001_repair_customer_contact_user_types.php +0 -86
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<Layout::Resource::Panel
|
|
2
2
|
@resource={{@model}}
|
|
3
3
|
@controller={{this}}
|
|
4
|
-
@headerComponent={{component "contact/panel-header" resource=@model}}
|
|
4
|
+
@headerComponent={{component "contact/panel-header" resource=@model actionButtons=this.actionButtons}}
|
|
5
5
|
@headerTitle={{or @model.name}}
|
|
6
6
|
@actionButtons={{this.actionButtons}}
|
|
7
7
|
@onPressCancel={{transition-to "management.contacts.customers"}}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<Layout::Resource::Panel
|
|
2
2
|
@resource={{@model}}
|
|
3
3
|
@controller={{this}}
|
|
4
|
-
@headerComponent={{component "contact/panel-header" resource=@model}}
|
|
4
|
+
@headerComponent={{component "contact/panel-header" resource=@model actionButtons=this.actionButtons}}
|
|
5
5
|
@headerTitle={{or @model.name}}
|
|
6
6
|
@actionButtons={{this.actionButtons}}
|
|
7
7
|
@onPressCancel={{transition-to "management.contacts.index"}}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<TabNavigation @tabs={{this.tabs}} @size="lg" @tablistClass="next-view-section-subheader-fixed-height pl-2">
|
|
1
|
+
<TabNavigation @tabs={{this.tabs}} @size="lg" @containerClass="tab-navigation-fill" @tablistClass="next-view-section-subheader-fixed-height pl-2">
|
|
2
2
|
<:actions>
|
|
3
3
|
<div class="flex flex-row items-center space-x-1 pr-4">
|
|
4
4
|
<Layout::Resource::TabularActions
|
|
@@ -16,4 +16,4 @@
|
|
|
16
16
|
<:default>
|
|
17
17
|
{{outlet}}
|
|
18
18
|
</:default>
|
|
19
|
-
</TabNavigation>
|
|
19
|
+
</TabNavigation>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<Layout::Resource::Panel
|
|
2
2
|
@resource={{@model}}
|
|
3
3
|
@controller={{this}}
|
|
4
|
-
@
|
|
4
|
+
@headerComponent={{component "issue/panel-header" resource=@model}}
|
|
5
5
|
@actionButtons={{this.actionButtons}}
|
|
6
6
|
@onPressCancel={{transition-to "management.issues.index"}}
|
|
7
7
|
@onOverlayReady={{fn (mut this.overlay)}}
|
|
8
8
|
@headerClass="no-bottom-border"
|
|
9
9
|
@bodyClass="no-scroll"
|
|
10
|
+
@width="800px"
|
|
10
11
|
>
|
|
11
12
|
<TabNavigation @tabs={{this.tabs}} @contentClass="scrollable" @tablistClass="pl-2">
|
|
12
13
|
{{outlet}}
|
|
13
14
|
</TabNavigation>
|
|
14
|
-
</Layout::Resource::Panel>
|
|
15
|
+
</Layout::Resource::Panel>
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
{{
|
|
2
|
-
{{outlet}}
|
|
1
|
+
<Vendor::PersonnelManager @vendor={{@model}} />
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
<Order::Details @resource={{@model}} @onActivityChanged={{perform this.parent.refresh}} @isLoadingActivity={{this.parent.refresh.isRunning}} />
|
|
2
|
-
<Spacer @height="300px" />
|
|
1
|
+
<Order::Details @resource={{@model}} @onActivityChanged={{perform this.parent.refresh}} @proofReloadToken={{this.parent.proofReloadToken}} @isLoadingActivity={{this.parent.refresh.isRunning}} />
|
|
2
|
+
<Spacer @height="300px" />
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
@bulkSearchValue={{this.bulk_query}}
|
|
37
37
|
@onClearBulkSearch={{fn (mut this.bulk_query)}}
|
|
38
38
|
@onSubmitBulkSearch={{fn (mut this.bulk_query)}}
|
|
39
|
-
@bulkSearchPlaceholder={{t "
|
|
39
|
+
@bulkSearchPlaceholder={{t "order.prompts.order-bulk-search"}}
|
|
40
40
|
@data={{@model}}
|
|
41
41
|
@columns={{this.columns}}
|
|
42
42
|
@page={{this.page}}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
@saveTask={{this.save}}
|
|
7
7
|
@onPressCancel={{transition-to "operations.service-rates.index"}}
|
|
8
8
|
@onOverlayReady={{fn (mut this.overlay)}}
|
|
9
|
+
@maxResizeWidth={{1000}}
|
|
9
10
|
>
|
|
10
11
|
<ServiceRate::Form @resource={{this.serviceRate}} @controller={{this}} />
|
|
11
12
|
<Spacer @height="200px" />
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<Layout::Section::Header @title={{t "
|
|
1
|
+
<Layout::Section::Header @title={{t "settings.payments.onboard.header-title"}} />
|
|
2
2
|
|
|
3
3
|
<Layout::Section::Body class="overflow-y-scroll-i h-full">
|
|
4
4
|
<div class="container">
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
>
|
|
14
14
|
<h2 id="title" class="text-base">
|
|
15
15
|
{{#if this.onboardCompleted}}
|
|
16
|
-
{{t "
|
|
16
|
+
{{t "settings.payments.onboard.title-completed"}}
|
|
17
17
|
{{else}}
|
|
18
|
-
{{t "
|
|
18
|
+
{{t "settings.payments.onboard.title-incomplete"}}
|
|
19
19
|
{{/if}}
|
|
20
20
|
</h2>
|
|
21
21
|
<span id="subtitle">
|
|
22
22
|
{{#if this.onboardCompleted}}
|
|
23
|
-
{{t "
|
|
23
|
+
{{t "settings.payments.onboard.subtitle-completed"}}
|
|
24
24
|
{{else}}
|
|
25
|
-
{{t "
|
|
25
|
+
{{t "settings.payments.onboard.subtitle-incomplete"}}
|
|
26
26
|
{{/if}}
|
|
27
27
|
</span>
|
|
28
28
|
<div class="mt-4 mb-1">
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
@icon="check"
|
|
32
32
|
@type="primary"
|
|
33
33
|
@size="lg"
|
|
34
|
-
@text={{t "
|
|
34
|
+
@text={{t "settings.payments.onboard.button-continue"}}
|
|
35
35
|
@onClick={{transition-to "settings.payments.index"}}
|
|
36
36
|
@disabled={{this.onboardInProgress}}
|
|
37
37
|
/>
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
@icon="play"
|
|
41
41
|
@type="primary"
|
|
42
42
|
@size="lg"
|
|
43
|
-
@text={{if this.onboardInProgress (t "
|
|
43
|
+
@text={{if this.onboardInProgress (t "settings.payments.onboard.button-in-progress") (t "settings.payments.onboard.button-start")}}
|
|
44
44
|
@onClick={{perform this.startOnboard}}
|
|
45
45
|
@isLoading={{this.startOnboard.isRunning}}
|
|
46
46
|
@disabled={{this.onboardInProgress}}
|
|
@@ -59,4 +59,4 @@
|
|
|
59
59
|
</div>
|
|
60
60
|
</div>
|
|
61
61
|
</div>
|
|
62
|
-
</Layout::Section::Body>
|
|
62
|
+
</Layout::Section::Body>
|
|
@@ -15,7 +15,7 @@ export const driverTypes = [
|
|
|
15
15
|
];
|
|
16
16
|
|
|
17
17
|
export const driverStatuses = [
|
|
18
|
-
{ label: '
|
|
18
|
+
{ label: 'Available', value: 'available', description: 'Driver is available for assignments' },
|
|
19
19
|
{ label: 'Inactive', value: 'inactive', description: 'Driver is not currently active' },
|
|
20
20
|
{ label: 'On Duty', value: 'on_duty', description: 'Driver is working and available' },
|
|
21
21
|
{ label: 'Off Duty', value: 'off_duty', description: 'Driver is not working' },
|
|
@@ -382,6 +382,7 @@ export const podOptions = [
|
|
|
382
382
|
export const serviceRateCalculationMethods = [
|
|
383
383
|
{ label: 'Per Meter', value: 'per_meter', description: 'Calculate cost based on the number of meters traveled.' },
|
|
384
384
|
{ label: 'Fixed Rate', value: 'fixed_meter', description: 'Charge a fixed rate per meter regardless of distance.' },
|
|
385
|
+
{ label: 'Multi-zone Distance', value: 'multi_zone_distance', description: 'Calculate cost by splitting route distance across priced service areas and zones.' },
|
|
385
386
|
{ label: 'Parcel Rate', value: 'parcel', description: 'Charge a dynamic rate based on parcel/payload weight and dimensions.' },
|
|
386
387
|
{ label: 'Per Drop-off', value: 'per_drop', description: 'Cost applied per drop-off point.' },
|
|
387
388
|
{ label: 'Algorithm', value: 'algo', description: 'Cost calculated dynamically using algorithmic logic.' },
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function ensureLeafletDrawEditNamespace(leaflet = null) {
|
|
2
|
+
const leaflets = [];
|
|
3
|
+
|
|
4
|
+
if (leaflet) {
|
|
5
|
+
leaflets.push(leaflet);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (typeof window !== 'undefined') {
|
|
9
|
+
leaflets.push(window.leaflet, window.L);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const guarded = [];
|
|
13
|
+
for (const L of leaflets) {
|
|
14
|
+
if (!L || guarded.includes(L)) continue;
|
|
15
|
+
L.Edit = L.Edit || {};
|
|
16
|
+
guarded.push(L);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return guarded;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default ensureLeafletDrawEditNamespace;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { debug } from '@ember/debug';
|
|
2
|
+
import ensureLeafletDrawEditNamespace from './leaflet-draw-namespace-guard';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_BASE_PATH = 'engines-dist/leaflet';
|
|
5
|
+
const DEFAULT_SCRIPTS = ['leaflet.contextmenu.js', 'leaflet.draw-src.js'];
|
|
6
|
+
const DEFAULT_STYLESHEETS = ['leaflet.contextmenu.css', 'leaflet.draw.css'];
|
|
7
|
+
const SCRIPT_FLAG = 'fleetopsLeafletPluginLoaded';
|
|
8
|
+
const STYLESHEET_FLAG = 'fleetopsLeafletPluginStylesheet';
|
|
9
|
+
|
|
10
|
+
let pluginReadyPromise = null;
|
|
11
|
+
|
|
12
|
+
function normalizePath(path = '') {
|
|
13
|
+
return `/${path.replace(/^\/+/, '')}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function assetPath(basePath, assetName) {
|
|
17
|
+
return normalizePath(`${basePath ? `${basePath}/` : ''}${assetName}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function findAssetElement(tagName, srcAttribute, src) {
|
|
21
|
+
return Array.from(document.getElementsByTagName(tagName)).find((element) => {
|
|
22
|
+
const currentSrc = element.getAttribute(srcAttribute);
|
|
23
|
+
if (currentSrc === src) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
return new URL(element[srcAttribute], window.location.origin).pathname === src;
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function normalizeLeafletGlobal() {
|
|
36
|
+
if (typeof window === 'undefined') {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const leaflet = window.L || window.leaflet;
|
|
41
|
+
if (!leaflet) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
window.L = leaflet;
|
|
46
|
+
window.leaflet = leaflet;
|
|
47
|
+
ensureLeafletDrawEditNamespace(leaflet);
|
|
48
|
+
return leaflet;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function hasLeafletDrawPlugins(leaflet = normalizeLeafletGlobal()) {
|
|
52
|
+
return Boolean(leaflet?.Edit?.Marker && leaflet?.Edit?.Poly && leaflet?.Control?.Draw);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function hasLeafletContextmenuPlugin(leaflet = normalizeLeafletGlobal()) {
|
|
56
|
+
return Boolean(leaflet?.Map?.ContextMenu);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function hasLeafletPluginsReady() {
|
|
60
|
+
const leaflet = normalizeLeafletGlobal();
|
|
61
|
+
return Boolean(leaflet && hasLeafletDrawPlugins(leaflet) && hasLeafletContextmenuPlugin(leaflet));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function waitForLeafletGlobal({ timeoutMs = 8000 } = {}) {
|
|
65
|
+
const leaflet = normalizeLeafletGlobal();
|
|
66
|
+
if (leaflet) {
|
|
67
|
+
return Promise.resolve(leaflet);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return new Promise((resolve, reject) => {
|
|
71
|
+
const startedAt = Date.now();
|
|
72
|
+
const interval = setInterval(() => {
|
|
73
|
+
const leaflet = normalizeLeafletGlobal();
|
|
74
|
+
if (leaflet) {
|
|
75
|
+
clearInterval(interval);
|
|
76
|
+
resolve(leaflet);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (timeoutMs != null && Date.now() - startedAt >= timeoutMs) {
|
|
81
|
+
clearInterval(interval);
|
|
82
|
+
reject(new Error('[FleetOps Leaflet] Leaflet global is not available'));
|
|
83
|
+
}
|
|
84
|
+
}, 50);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function appendStylesheet(href) {
|
|
89
|
+
if (typeof document === 'undefined') {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const existing = findAssetElement('link', 'href', href);
|
|
94
|
+
if (existing) {
|
|
95
|
+
existing.dataset[STYLESHEET_FLAG] = 'true';
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const link = document.createElement('link');
|
|
100
|
+
link.rel = 'stylesheet';
|
|
101
|
+
link.href = href;
|
|
102
|
+
link.dataset[STYLESHEET_FLAG] = 'true';
|
|
103
|
+
document.head.appendChild(link);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function loadScript(src, { timeoutMs = 8000, isReady = null } = {}) {
|
|
107
|
+
if (typeof document === 'undefined') {
|
|
108
|
+
return Promise.reject(new Error('[FleetOps Leaflet] document is not available'));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const existing = findAssetElement('script', 'src', src);
|
|
112
|
+
if (existing?.dataset[SCRIPT_FLAG] === 'true' || isReady?.()) {
|
|
113
|
+
if (existing) {
|
|
114
|
+
existing.dataset[SCRIPT_FLAG] = 'true';
|
|
115
|
+
}
|
|
116
|
+
return Promise.resolve(existing);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
const script = existing ?? document.createElement('script');
|
|
121
|
+
let timeoutId;
|
|
122
|
+
|
|
123
|
+
const cleanup = () => {
|
|
124
|
+
script.removeEventListener('load', onLoad);
|
|
125
|
+
script.removeEventListener('error', onError);
|
|
126
|
+
if (timeoutId) {
|
|
127
|
+
clearTimeout(timeoutId);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const onLoad = () => {
|
|
132
|
+
cleanup();
|
|
133
|
+
script.dataset[SCRIPT_FLAG] = 'true';
|
|
134
|
+
normalizeLeafletGlobal();
|
|
135
|
+
resolve(script);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const onError = () => {
|
|
139
|
+
cleanup();
|
|
140
|
+
reject(new Error(`[FleetOps Leaflet] Failed to load ${src}`));
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
script.addEventListener('load', onLoad);
|
|
144
|
+
script.addEventListener('error', onError);
|
|
145
|
+
|
|
146
|
+
if (timeoutMs != null) {
|
|
147
|
+
timeoutId = setTimeout(() => {
|
|
148
|
+
cleanup();
|
|
149
|
+
reject(new Error(`[FleetOps Leaflet] Timed out loading ${src}`));
|
|
150
|
+
}, timeoutMs);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!existing) {
|
|
154
|
+
script.src = src;
|
|
155
|
+
script.async = false;
|
|
156
|
+
script.dataset.fleetopsLeafletPlugin = 'true';
|
|
157
|
+
document.body.appendChild(script);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function resetLeafletPluginLoaderForTesting() {
|
|
163
|
+
pluginReadyPromise = null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function pluginReadyCheck(script) {
|
|
167
|
+
if (script.includes('contextmenu')) {
|
|
168
|
+
return () => hasLeafletContextmenuPlugin();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (script.includes('draw')) {
|
|
172
|
+
return () => hasLeafletDrawPlugins();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export default function ensureLeafletPluginsReady(options = {}) {
|
|
179
|
+
const { basePath = DEFAULT_BASE_PATH, scripts = DEFAULT_SCRIPTS, stylesheets = DEFAULT_STYLESHEETS, timeoutMs = 8000, force = false } = options;
|
|
180
|
+
|
|
181
|
+
if (!force && hasLeafletPluginsReady()) {
|
|
182
|
+
window.fleetopsLeafletPluginsLoaded = true;
|
|
183
|
+
return Promise.resolve(normalizeLeafletGlobal());
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (!force && pluginReadyPromise) {
|
|
187
|
+
return pluginReadyPromise;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
window.fleetopsLeafletPluginsLoaded = false;
|
|
191
|
+
stylesheets.forEach((stylesheet) => appendStylesheet(assetPath(basePath, stylesheet)));
|
|
192
|
+
|
|
193
|
+
pluginReadyPromise = waitForLeafletGlobal({ timeoutMs })
|
|
194
|
+
.then(() =>
|
|
195
|
+
scripts.reduce((promise, script) => {
|
|
196
|
+
return promise.then(() => {
|
|
197
|
+
normalizeLeafletGlobal();
|
|
198
|
+
return loadScript(assetPath(basePath, script), { timeoutMs, isReady: pluginReadyCheck(script) });
|
|
199
|
+
});
|
|
200
|
+
}, Promise.resolve())
|
|
201
|
+
)
|
|
202
|
+
.then(() => {
|
|
203
|
+
const readyLeaflet = normalizeLeafletGlobal();
|
|
204
|
+
if (!hasLeafletPluginsReady()) {
|
|
205
|
+
throw new Error('[FleetOps Leaflet] Leaflet plugins loaded but required Draw/contextmenu APIs are missing');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
window.fleetopsLeafletPluginsLoaded = true;
|
|
209
|
+
return readyLeaflet;
|
|
210
|
+
})
|
|
211
|
+
.catch((error) => {
|
|
212
|
+
window.fleetopsLeafletPluginsLoaded = false;
|
|
213
|
+
pluginReadyPromise = null;
|
|
214
|
+
debug(error.message);
|
|
215
|
+
throw error;
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
return pluginReadyPromise;
|
|
219
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { isArray } from '@ember/array';
|
|
2
|
+
|
|
3
|
+
export function getOrderConfigFlowRootCode(flow = {}) {
|
|
4
|
+
if (flow.created) {
|
|
5
|
+
return 'created';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return Object.keys(flow)[0];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function normalizeOrderConfigFlow(flow = {}) {
|
|
12
|
+
if (isArray(flow)) {
|
|
13
|
+
return flow.reduce((normalized, activity, index) => {
|
|
14
|
+
if (!activity || typeof activity !== 'object') {
|
|
15
|
+
return normalized;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const code = activity.code ?? activity.key;
|
|
19
|
+
if (!code) {
|
|
20
|
+
return normalized;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const nextActivity = flow.slice(index + 1).find((candidate) => candidate && typeof candidate === 'object' && (candidate.code ?? candidate.key));
|
|
24
|
+
|
|
25
|
+
normalized[code] = {
|
|
26
|
+
...activity,
|
|
27
|
+
code,
|
|
28
|
+
key: activity.key ?? code,
|
|
29
|
+
activities: isArray(activity.activities) ? activity.activities : nextActivity ? [nextActivity.code ?? nextActivity.key] : [],
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return normalized;
|
|
33
|
+
}, {});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (flow && typeof flow === 'object') {
|
|
37
|
+
return flow;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
@@ -11,17 +11,18 @@ function line(content, className = '') {
|
|
|
11
11
|
return `<div${classAttribute}>${escapeHtml(content)}</div>`;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export default function placeAddressHtml(place) {
|
|
14
|
+
export default function placeAddressHtml(place, options = {}) {
|
|
15
15
|
if (!place) {
|
|
16
16
|
return htmlSafe('');
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
const { showTitle = true } = options;
|
|
19
20
|
const name = place.name === place.street1 ? null : place.name;
|
|
20
21
|
const cityStatePostalCode = [place.city, place.province, place.postal_code].filter((value) => !isBlank(value)).join(', ');
|
|
21
22
|
const lines = [];
|
|
22
23
|
|
|
23
24
|
if (name) {
|
|
24
|
-
lines.push(line(name, 'font-semibold'));
|
|
25
|
+
if (showTitle) lines.push(line(name, 'font-semibold'));
|
|
25
26
|
lines.push(line(place.street1));
|
|
26
27
|
} else if (place.street1) {
|
|
27
28
|
lines.push(line(place.street1, 'font-semibold'));
|
|
@@ -8,6 +8,18 @@ export function waypointToPlace(waypoint) {
|
|
|
8
8
|
return waypoint.place ?? waypoint;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
export function endpointTrackingNumberUuid(payload, role) {
|
|
12
|
+
if (!payload || !role) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return payload[`${role}_tracking_number_uuid`] ?? null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function waypointTrackingNumberUuid(waypoint) {
|
|
20
|
+
return waypoint?.tracking_number_uuid ?? waypoint?.tracking_number?.uuid ?? waypoint?.trackingNumber?.uuid ?? null;
|
|
21
|
+
}
|
|
22
|
+
|
|
11
23
|
export function buildPlaceAddressTooltip(title, place) {
|
|
12
24
|
if (!place) {
|
|
13
25
|
return title;
|
|
@@ -38,30 +50,65 @@ export function buildRoutePointsFromPayload(payload) {
|
|
|
38
50
|
const waypoints = payload.waypoints ?? [];
|
|
39
51
|
|
|
40
52
|
if (hasValidCoordinates(payload.pickup)) {
|
|
41
|
-
points.push({ role: 'pickup', place: payload.pickup });
|
|
53
|
+
points.push({ role: 'pickup', place: payload.pickup, trackingNumberUuid: endpointTrackingNumberUuid(payload, 'pickup') });
|
|
42
54
|
}
|
|
43
55
|
|
|
44
56
|
waypoints.forEach((waypoint, index) => {
|
|
45
57
|
const place = waypointToPlace(waypoint);
|
|
46
58
|
|
|
47
59
|
if (hasValidCoordinates(place)) {
|
|
48
|
-
points.push({ role: 'waypoint', place, stopNumber: index + 1 });
|
|
60
|
+
points.push({ role: 'waypoint', place, stopNumber: index + 1, trackingNumberUuid: waypointTrackingNumberUuid(waypoint) });
|
|
49
61
|
}
|
|
50
62
|
});
|
|
51
63
|
|
|
52
64
|
if (hasValidCoordinates(payload.dropoff)) {
|
|
53
|
-
points.push({ role: 'dropoff', place: payload.dropoff });
|
|
65
|
+
points.push({ role: 'dropoff', place: payload.dropoff, trackingNumberUuid: endpointTrackingNumberUuid(payload, 'dropoff') });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (hasValidCoordinates(payload.return)) {
|
|
69
|
+
points.push({ role: 'return', place: payload.return, trackingNumberUuid: endpointTrackingNumberUuid(payload, 'return') });
|
|
54
70
|
}
|
|
55
71
|
|
|
56
72
|
return points;
|
|
57
73
|
}
|
|
58
74
|
|
|
75
|
+
export function buildServiceStopsFromPayload(payload) {
|
|
76
|
+
if (!payload) {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const stops = [];
|
|
81
|
+
const waypoints = payload.waypoints ?? [];
|
|
82
|
+
|
|
83
|
+
if (payload.pickup) {
|
|
84
|
+
stops.push({ role: 'pickup', place: payload.pickup, trackingNumberUuid: endpointTrackingNumberUuid(payload, 'pickup') });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
waypoints.forEach((waypoint, index) => {
|
|
88
|
+
const place = waypointToPlace(waypoint);
|
|
89
|
+
|
|
90
|
+
if (place) {
|
|
91
|
+
stops.push({ role: 'waypoint', place, stopNumber: index + 1, trackingNumberUuid: waypointTrackingNumberUuid(waypoint) });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
if (payload.dropoff) {
|
|
96
|
+
stops.push({ role: 'dropoff', place: payload.dropoff, trackingNumberUuid: endpointTrackingNumberUuid(payload, 'dropoff') });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (payload.return) {
|
|
100
|
+
stops.push({ role: 'return', place: payload.return, trackingNumberUuid: endpointTrackingNumberUuid(payload, 'return') });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return stops;
|
|
104
|
+
}
|
|
105
|
+
|
|
59
106
|
export function describeRoutePoint(routePoint, routeColor) {
|
|
60
107
|
const role = routePoint?.role;
|
|
61
108
|
const stopNumber = routePoint?.stopNumber ?? 1;
|
|
62
|
-
const label = role === 'pickup' ? 'P' : role === 'dropoff' ? 'D' : String(stopNumber);
|
|
63
|
-
const markerColor = role === 'pickup' ? '#22C55E' : role === 'dropoff' ? '#EF4444' : routeColor;
|
|
64
|
-
const title = role === 'pickup' ? 'Pickup' : role === 'dropoff' ? 'Dropoff' : `Stop ${stopNumber}`;
|
|
109
|
+
const label = role === 'pickup' ? 'P' : role === 'dropoff' ? 'D' : role === 'return' ? 'R' : String(stopNumber);
|
|
110
|
+
const markerColor = role === 'pickup' ? '#22C55E' : role === 'dropoff' ? '#EF4444' : role === 'return' ? '#F97316' : routeColor;
|
|
111
|
+
const title = role === 'pickup' ? 'Pickup' : role === 'dropoff' ? 'Dropoff' : role === 'return' ? 'Return' : `Stop ${stopNumber}`;
|
|
65
112
|
|
|
66
113
|
return {
|
|
67
114
|
label,
|
|
@@ -74,7 +121,7 @@ export function buildRoutePointMarkerPresentation(routePoint, routeColor, option
|
|
|
74
121
|
const role = routePoint?.role;
|
|
75
122
|
const place = routePoint?.place;
|
|
76
123
|
const { label, markerColor, title } = describeRoutePoint(routePoint, routeColor);
|
|
77
|
-
const zIndexOffset = role === 'pickup' ? 2200 : role === 'dropoff' ? 2100 : 1800;
|
|
124
|
+
const zIndexOffset = role === 'pickup' ? 2200 : role === 'dropoff' ? 2100 : role === 'return' ? 2000 : 1800;
|
|
78
125
|
|
|
79
126
|
return {
|
|
80
127
|
waypointLabel: label,
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import CustomerOrdersComponent from '../components/customer/orders';
|
|
2
1
|
import CustomerAdminSettingsComponent from '../components/customer/admin-settings';
|
|
3
|
-
import { MenuItem } from '@fleetbase/ember-core/contracts';
|
|
4
|
-
import { setOwner } from '@ember/application';
|
|
5
|
-
import { debug } from '@ember/debug';
|
|
6
2
|
|
|
7
|
-
export default function setupCustomerPortal(
|
|
3
|
+
export default function setupCustomerPortal(_fleetopsEngine, universe) {
|
|
8
4
|
const extensionManager = universe.getService('universe/extension-manager');
|
|
9
5
|
const isCustomerPortalInstalled = extensionManager.isInstalled('@fleetbase/customer-portal-engine');
|
|
10
6
|
if (!isCustomerPortalInstalled) return;
|
|
@@ -13,81 +9,25 @@ export default function setupCustomerPortal(fleetopsEngine, universe) {
|
|
|
13
9
|
if (extensionManager.isEngineLoaded('@fleetbase/customer-portal-engine')) {
|
|
14
10
|
const customerPortalEngine = extensionManager.getEngineInstance('@fleetbase/customer-portal-engine');
|
|
15
11
|
if (customerPortalEngine) {
|
|
16
|
-
return setup(customerPortalEngine,
|
|
12
|
+
return setup(customerPortalEngine, universe);
|
|
17
13
|
}
|
|
18
14
|
}
|
|
19
15
|
|
|
20
16
|
// Otherwise, wait for customer portal engine to load to run setup
|
|
21
17
|
universe.onEngineLoaded('@fleetbase/customer-portal-engine', (customerPortalEngine) => {
|
|
22
|
-
setup(customerPortalEngine,
|
|
18
|
+
setup(customerPortalEngine, universe);
|
|
23
19
|
});
|
|
24
20
|
}
|
|
25
21
|
|
|
26
|
-
function setup(customerPortalEngine,
|
|
22
|
+
function setup(customerPortalEngine, universe) {
|
|
27
23
|
// If setup already completed don't run again
|
|
28
24
|
if (customerPortalEngine?._fleetopsSetupCompleted === true) return;
|
|
29
25
|
|
|
30
|
-
// Alias FleetOps services into Customer Portal before rendering
|
|
31
|
-
createServiceAlias(fleetopsEngine, customerPortalEngine, [
|
|
32
|
-
'leaflet-map-manager',
|
|
33
|
-
'location',
|
|
34
|
-
'movement-tracker',
|
|
35
|
-
'leaflet-routing-control',
|
|
36
|
-
'order-config-actions',
|
|
37
|
-
'order-creation',
|
|
38
|
-
'order-validation',
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
const menuService = universe.getService('universe/menu-service');
|
|
42
26
|
const registryService = universe.getService('universe/registry-service');
|
|
43
27
|
|
|
44
|
-
// Register customer orders from Fleet-Ops
|
|
45
|
-
menuService.registerMenuItem(
|
|
46
|
-
'customer-portal:sidebar',
|
|
47
|
-
new MenuItem({
|
|
48
|
-
title: 'Orders',
|
|
49
|
-
route: 'customer-portal.portal.virtual',
|
|
50
|
-
icon: 'boxes-packing',
|
|
51
|
-
component: createEngineBoundComponent(customerPortalEngine, CustomerOrdersComponent),
|
|
52
|
-
})
|
|
53
|
-
);
|
|
54
|
-
|
|
55
28
|
// Register registries
|
|
56
29
|
registryService.register('customer-portal:admin-settings', '@fleetbase/customer-portal-engine', CustomerAdminSettingsComponent);
|
|
57
30
|
|
|
58
31
|
// Flag fleetops setup complete
|
|
59
32
|
customerPortalEngine._fleetopsSetupCompleted = true;
|
|
60
33
|
}
|
|
61
|
-
|
|
62
|
-
function createServiceAlias(sourceOwner, destOwner, serviceNames) {
|
|
63
|
-
serviceNames.forEach((name) => {
|
|
64
|
-
const key = `service:${name}`;
|
|
65
|
-
if (destOwner.hasRegistration?.(key)) return;
|
|
66
|
-
|
|
67
|
-
// alias the fully-wired instance
|
|
68
|
-
const instance = sourceOwner.lookup?.(key);
|
|
69
|
-
if (instance) {
|
|
70
|
-
destOwner.register(key, instance, { instantiate: false });
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Faillback: only use factories for simple/stateless services
|
|
75
|
-
const factory = sourceOwner.resolveRegistration?.(key);
|
|
76
|
-
if (factory) {
|
|
77
|
-
destOwner.register(key, factory);
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
debug(`[alias] missing ${key} on source; not aliased`);
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function createEngineBoundComponent(engineInstance, ComponentClass) {
|
|
86
|
-
return class EngineBoundComponent extends ComponentClass {
|
|
87
|
-
constructor(...args) {
|
|
88
|
-
super(...args);
|
|
89
|
-
// Ensure DI resolution happens within the engine
|
|
90
|
-
setOwner(this, engineInstance);
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/components/home/getting-started-guidance';
|