@fleetbase/fleetops-engine 0.3.2 → 0.3.4

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 (137) hide show
  1. package/addon/components/admin/visibility-controls.js +1 -0
  2. package/addon/components/contact-form-panel.hbs +28 -6
  3. package/addon/components/driver-form-panel.hbs +10 -0
  4. package/addon/components/driver-form-panel.js +51 -0
  5. package/addon/components/driver-panel/details.hbs +1 -5
  6. package/addon/components/driver-panel.hbs +21 -3
  7. package/addon/components/fleet-form-panel.hbs +60 -6
  8. package/addon/components/fleet-panel/details.hbs +1 -1
  9. package/addon/components/fuel-report-form-panel.hbs +84 -8
  10. package/addon/components/fuel-report-form-panel.js +6 -0
  11. package/addon/components/fuel-report-panel/details.hbs +4 -0
  12. package/addon/components/issue-form-panel.hbs +99 -11
  13. package/addon/components/issue-form-panel.js +5 -13
  14. package/addon/components/layout/fleet-ops-sidebar.js +10 -1
  15. package/addon/components/live-map-drawer/driver-listing.hbs +6 -0
  16. package/addon/components/live-map-drawer/driver-listing.js +240 -0
  17. package/addon/components/live-map-drawer/place-listing.hbs +6 -0
  18. package/addon/components/live-map-drawer/place-listing.js +204 -0
  19. package/addon/components/live-map-drawer/vehicle-listing.hbs +6 -0
  20. package/addon/components/live-map-drawer/vehicle-listing.js +216 -0
  21. package/addon/components/live-map-drawer.hbs +17 -0
  22. package/addon/components/live-map-drawer.js +104 -0
  23. package/addon/components/live-map.hbs +5 -1
  24. package/addon/components/live-map.js +107 -15
  25. package/addon/components/map-container/toolbar.hbs +6 -0
  26. package/addon/components/modals/driver-assign-vehicle.hbs +2 -11
  27. package/addon/components/modals/driver-assign-vendor.hbs +1 -9
  28. package/addon/components/modals/fuel-report-details.hbs +4 -0
  29. package/addon/components/modals/order-event.hbs +1 -1
  30. package/addon/components/order/schedule-card.hbs +35 -7
  31. package/addon/components/order/schedule-card.js +163 -6
  32. package/addon/components/place-form-panel.hbs +14 -7
  33. package/addon/components/place-form-panel.js +71 -0
  34. package/addon/components/place-panel/details.hbs +11 -21
  35. package/addon/components/vehicle-form-panel.hbs +67 -7
  36. package/addon/components/vehicle-form-panel.js +37 -0
  37. package/addon/components/vehicle-panel/details.hbs +9 -5
  38. package/addon/components/vehicle-panel.hbs +18 -4
  39. package/addon/components/vendor-form-panel/create-form.hbs +72 -11
  40. package/addon/components/vendor-form-panel/edit-form.hbs +1 -1
  41. package/addon/components/vendor-form-panel.hbs +70 -30
  42. package/addon/components/vendor-form-panel.js +4 -40
  43. package/addon/components/vendor-panel/details.hbs +2 -2
  44. package/addon/components/vendor-panel.hbs +16 -2
  45. package/addon/controllers/management/contacts/index.js +42 -3
  46. package/addon/controllers/management/fleets/index.js +12 -23
  47. package/addon/controllers/management/fuel-reports/index/new.js +1 -1
  48. package/addon/controllers/management/fuel-reports/index.js +73 -20
  49. package/addon/controllers/management/issues/index/new.js +2 -2
  50. package/addon/controllers/management/issues/index.js +65 -45
  51. package/addon/controllers/management/places/index.js +59 -18
  52. package/addon/controllers/management/vehicles/index.js +67 -8
  53. package/addon/controllers/management/vendors/index.js +63 -8
  54. package/addon/controllers/operations/orders/index.js +70 -15
  55. package/addon/controllers/operations/scheduler/index.js +45 -30
  56. package/addon/routes/management/contacts/index.js +8 -0
  57. package/addon/routes/management/fleets/index.js +8 -2
  58. package/addon/routes/management/fuel-reports/index.js +6 -0
  59. package/addon/routes/management/issues/index.js +9 -1
  60. package/addon/routes/management/places/index.js +11 -1
  61. package/addon/routes/management/vehicles/index.js +3 -3
  62. package/addon/routes/management/vendors/index.js +8 -0
  63. package/addon/routes/operations/scheduler/index.js +26 -1
  64. package/addon/styles/fleetops-engine.css +28 -0
  65. package/addon/templates/operations/orders/index.hbs +2 -2
  66. package/addon/templates/operations/scheduler/index.hbs +33 -9
  67. package/addon/utils/create-full-calendar-event-from-order.js +8 -0
  68. package/addon/utils/get-issue-categories.js +30 -0
  69. package/addon/utils/get-issue-types.js +3 -0
  70. package/addon/utils/get-vendor-status-options.js +3 -0
  71. package/addon/utils/get-vendor-type-options.js +41 -0
  72. package/app/components/live-map-drawer/driver-listing.js +1 -0
  73. package/app/components/live-map-drawer/place-listing.js +1 -0
  74. package/app/components/live-map-drawer/vehicle-listing.js +1 -0
  75. package/app/components/live-map-drawer.js +1 -0
  76. package/app/utils/create-full-calendar-event-from-order.js +1 -0
  77. package/app/utils/get-issue-categories.js +1 -0
  78. package/app/utils/get-issue-types.js +1 -0
  79. package/app/utils/get-vendor-categories.js +1 -0
  80. package/app/utils/get-vendor-status-options.js +1 -0
  81. package/app/utils/get-vendor-type-options.js +1 -0
  82. package/app/utils/get-vendor-types.js +1 -0
  83. package/composer.json +1 -1
  84. package/extension.json +1 -1
  85. package/package.json +4 -4
  86. package/server/migrations/2023_11_09_041807_add_status_column_to_fuel_reports_table.php +32 -0
  87. package/server/migrations/2023_11_15_062814_add_comments_column_and_resolved_at_column_to_vehicle_device_events_table.php +33 -0
  88. package/server/src/Http/Controllers/Api/v1/DriverController.php +2 -2
  89. package/server/src/Http/Controllers/Api/v1/VehicleController.php +2 -2
  90. package/server/src/Http/Controllers/Internal/v1/DriverController.php +5 -13
  91. package/server/src/Http/Controllers/Internal/v1/OrderController.php +1 -3
  92. package/server/src/Http/Filter/ContactFilter.php +10 -0
  93. package/server/src/Http/Filter/FleetFilter.php +8 -6
  94. package/server/src/Http/Filter/FuelReportFilter.php +51 -0
  95. package/server/src/Http/Filter/IssueFilter.php +61 -5
  96. package/server/src/Http/Filter/PlaceFilter.php +48 -6
  97. package/server/src/Http/Filter/VehicleFilter.php +21 -6
  98. package/server/src/Http/Filter/VendorFilter.php +11 -8
  99. package/server/src/Http/Middleware/TransformLocationMiddleware.php +1 -1
  100. package/server/src/Http/Resources/Internal/v1/IntegratedVendorFacilitator.php +17 -18
  101. package/server/src/Http/Resources/v1/Contact.php +16 -19
  102. package/server/src/Http/Resources/v1/CurrentJob.php +13 -16
  103. package/server/src/Http/Resources/v1/Driver.php +59 -57
  104. package/server/src/Http/Resources/v1/Entity.php +30 -33
  105. package/server/src/Http/Resources/v1/FuelReport.php +16 -14
  106. package/server/src/Http/Resources/v1/Order.php +1 -1
  107. package/server/src/Http/Resources/v1/Payload.php +21 -24
  108. package/server/src/Http/Resources/v1/Place.php +27 -30
  109. package/server/src/Http/Resources/v1/Proof.php +13 -16
  110. package/server/src/Http/Resources/v1/PurchaseRate.php +14 -17
  111. package/server/src/Http/Resources/v1/ServiceArea.php +13 -16
  112. package/server/src/Http/Resources/v1/ServiceQuote.php +15 -18
  113. package/server/src/Http/Resources/v1/ServiceRate.php +33 -36
  114. package/server/src/Http/Resources/v1/ServiceRateFee.php +14 -17
  115. package/server/src/Http/Resources/v1/ServiceRateParcelFee.php +9 -12
  116. package/server/src/Http/Resources/v1/TrackingNumber.php +18 -21
  117. package/server/src/Http/Resources/v1/TrackingStatus.php +18 -21
  118. package/server/src/Http/Resources/v1/Vehicle.php +31 -34
  119. package/server/src/Http/Resources/v1/VehicleDevice.php +23 -25
  120. package/server/src/Http/Resources/v1/VehicleWithoutDriver.php +38 -32
  121. package/server/src/Http/Resources/v1/Vendor.php +31 -26
  122. package/server/src/Http/Resources/v1/Zone.php +14 -17
  123. package/server/src/Models/Driver.php +7 -1
  124. package/server/src/Models/FuelReport.php +2 -1
  125. package/server/src/Models/IntegratedVendor.php +6 -1
  126. package/server/src/Models/Order.php +24 -2
  127. package/server/src/Models/Place.php +2 -2
  128. package/server/src/Models/VehicleDevice.php +1 -1
  129. package/server/src/Models/VehicleDeviceEvent.php +2 -1
  130. package/server/src/Models/Vendor.php +1 -1
  131. package/server/src/Observers/DriverObserver.php +15 -0
  132. package/server/src/Observers/FleetObserver.php +19 -0
  133. package/server/src/Providers/FleetOpsServiceProvider.php +1 -0
  134. package/addon/components/full-calendar/draggable.js +0 -1
  135. package/addon/components/full-calendar.js +0 -1
  136. package/app/components/full-calendar/draggable.js +0 -1
  137. package/app/components/full-calendar.js +0 -1
@@ -0,0 +1,216 @@
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 { isBlank } from '@ember/utils';
6
+ import { later } from '@ember/runloop';
7
+ import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
8
+
9
+ /**
10
+ * Represents a live map drawer vehicle listing component.
11
+ * This component is responsible for displaying and interacting with a list of vehicles on a live map.
12
+ *
13
+ * @extends Component
14
+ */
15
+ export default class LiveMapDrawerVehicleListingComponent extends Component {
16
+ /**
17
+ * Service for managing context panels within the application.
18
+ * @service
19
+ */
20
+ @service contextPanel;
21
+
22
+ /**
23
+ * Service for triggering notifications.
24
+ * @service
25
+ */
26
+ @service notifications;
27
+
28
+ /**
29
+ * Service for CRUD operations.
30
+ * @service
31
+ */
32
+ @service crud;
33
+
34
+ /**
35
+ * The list of vehicles to display, tracked for reactivity.
36
+ * @tracked
37
+ */
38
+ @tracked vehicles = [];
39
+
40
+ /**
41
+ * The internal list of vehicles used for searching, tracked for reactivity.
42
+ * @tracked
43
+ */
44
+ @tracked _vehicles = [];
45
+
46
+ /**
47
+ * The current search query, tracked for reactivity.
48
+ * @tracked
49
+ */
50
+ @tracked query = '';
51
+
52
+ /**
53
+ * The table component reference, tracked for reactivity.
54
+ * @tracked
55
+ */
56
+ @tracked table = null;
57
+
58
+ /**
59
+ * The configuration for table columns including details like label, valuePath, and cellComponent,
60
+ * tracked for reactivity.
61
+ * @tracked
62
+ */
63
+ @tracked columns = [
64
+ {
65
+ label: 'Vehicle',
66
+ valuePath: 'display_name',
67
+ photoPath: 'avatar_url',
68
+ width: '100px',
69
+ cellComponent: 'table/cell/vehicle-name',
70
+ onClick: this.focus,
71
+ showOnlineIndicator: true,
72
+ },
73
+ {
74
+ label: 'Location',
75
+ valuePath: 'location',
76
+ width: '80px',
77
+ cellComponent: 'table/cell/point',
78
+ onClick: this.locate,
79
+ },
80
+ {
81
+ label: 'Status',
82
+ valuePath: 'status',
83
+ cellComponent: 'table/cell/status',
84
+ width: '60px',
85
+ },
86
+ {
87
+ label: 'Last Seen',
88
+ valuePath: 'updatedAgo',
89
+ width: '60px',
90
+ },
91
+ {
92
+ label: '',
93
+ cellComponent: 'table/cell/dropdown',
94
+ ddButtonText: false,
95
+ ddButtonIcon: 'ellipsis-h',
96
+ ddButtonIconPrefix: 'fas',
97
+ ddMenuLabel: 'Actions',
98
+ cellClassNames: 'overflow-visible',
99
+ wrapperClass: 'flex items-center justify-end mx-2',
100
+ width: '90px',
101
+ actions: [
102
+ {
103
+ label: 'View vehicle details...',
104
+ fn: this.focus,
105
+ },
106
+ {
107
+ label: 'Edit vehicle...',
108
+ fn: (vehicle) => {
109
+ return this.focus(vehicle, 'editing');
110
+ },
111
+ },
112
+ {
113
+ label: 'Locate vehicle...',
114
+ fn: this.locate,
115
+ },
116
+ {
117
+ label: 'Delete vehicle...',
118
+ fn: this.delete,
119
+ },
120
+ ],
121
+ sortable: false,
122
+ filterable: false,
123
+ resizable: false,
124
+ searchable: false,
125
+ },
126
+ ];
127
+
128
+ /**
129
+ * Initializes the component with vehicles passed in from `this.args` and sets up the live map reference.
130
+ */
131
+ constructor() {
132
+ super(...arguments);
133
+ this.vehicles = getWithDefault(this.args, 'vehicles', []);
134
+ this._vehicles = [...this.vehicles];
135
+ this.liveMap = this.args.liveMap;
136
+ }
137
+
138
+ /**
139
+ * Filters the vehicles list based on a query.
140
+ *
141
+ * @param {string} query - The query string to filter the vehicles list.
142
+ */
143
+ search(query) {
144
+ if (typeof query !== 'string' && !isBlank(query)) {
145
+ return;
146
+ }
147
+
148
+ this.vehicles = [
149
+ ...this._vehicles.filter((vehicle) => {
150
+ return typeof vehicle.displayName === 'string' && vehicle.displayName.toLowerCase().includes(query.toLowerCase());
151
+ }),
152
+ ];
153
+ }
154
+
155
+ /**
156
+ * Action to perform a search based on the input event's value.
157
+ *
158
+ * @param {Event} event - The input event containing the search value.
159
+ */
160
+ @action performSearch({ target: { value } }) {
161
+ this.search(value);
162
+ }
163
+
164
+ /**
165
+ * Action to focus on a vehicle in the live map and context panel.
166
+ *
167
+ * @param {object} vehicle - The vehicle object to focus on.
168
+ * @param {string} intent - The intent for focusing, default is 'viewing'.
169
+ */
170
+ @action focus(vehicle, intent = 'viewing') {
171
+ if (this.liveMap) {
172
+ this.liveMap.focusLayerByRecord(vehicle, 16, {
173
+ onAfterFocusWithRecord: () => {
174
+ later(
175
+ this,
176
+ () => {
177
+ this.contextPanel.focus(vehicle, intent);
178
+ },
179
+ 600 * 2
180
+ );
181
+ },
182
+ });
183
+ } else {
184
+ this.contextPanel.focus(vehicle, intent);
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Action to locate a vehicle on the live map.
190
+ *
191
+ * @param {object} vehicle - The vehicle object to locate.
192
+ */
193
+ @action locate(vehicle) {
194
+ if (this.liveMap) {
195
+ this.liveMap.focusLayerByRecord(vehicle, 18);
196
+ } else {
197
+ this.notifications.warning('Unable to locate vehicle.');
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Action to delete a vehicle from the list and perform cleanup.
203
+ *
204
+ * @param {object} vehicle - The vehicle object to delete.
205
+ * @param {object} options - Additional options for the delete operation.
206
+ */
207
+ @action delete(vehicle, options = {}) {
208
+ this.crud.delete(vehicle, {
209
+ onSuccess: () => {
210
+ this._vehicles.removeObject(vehicle);
211
+ this.vehicles.removeObject(vehicle);
212
+ },
213
+ ...options,
214
+ });
215
+ }
216
+ }
@@ -0,0 +1,17 @@
1
+ <Drawer @onResizeEnd={{@onResizeEnd}} @onResizeStart={{@onResizeStart}} @isMinimized={{@isMinimized}} @isOpen={{@isOpen}} @notchEnabled={{true}} @onLoad={{this.setDrawerContext}}>
2
+ <div class="ui-tabs pt-4">
3
+ <nav>
4
+ {{#each this.tabs as |tab|}}
5
+ <a href="javascript:;" class="ui-tab {{if (eq this.tab.slug tab.slug) 'active' }}" {{on "click" (fn this.onTabChanged tab.slug)}}>
6
+ <FaIcon @icon={{tab.icon}} class="mr-1" />
7
+ <span>{{tab.title}}</span>
8
+ </a>
9
+ {{/each}}
10
+ </nav>
11
+ </div>
12
+ <div class="tab-content tab-{{this.tab.slug}}">
13
+ {{#if this.drawer}}
14
+ {{component this.tab.component drivers=@drivers vehicles=@vehicles places=@places drawer=this.drawer liveMap=@liveMap tabOptions=this.tab options=this.tab.componentParams}}
15
+ {{/if}}
16
+ </div>
17
+ </Drawer>
@@ -0,0 +1,104 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { action } from '@ember/object';
4
+ import { inject as service } from '@ember/service';
5
+ import { isArray } from '@ember/array';
6
+ import contextComponentCallback from '../utils/context-component-callback';
7
+ import applyContextComponentArguments from '../utils/apply-context-component-arguments';
8
+ import LiveMapDrawerVehicleListingComponent from './live-map-drawer/vehicle-listing';
9
+ import LiveMapDrawerDriverListingComponent from './live-map-drawer/driver-listing';
10
+ import LiveMapDrawerPlaceListingComponent from './live-map-drawer/place-listing';
11
+
12
+ export default class LiveMapDrawerComponent extends Component {
13
+ /**
14
+ * Universe service for managing global data and settings.
15
+ *
16
+ * @type {Service}
17
+ */
18
+ @service universe;
19
+
20
+ /**
21
+ * The current active tab.
22
+ *
23
+ * @type {Object}
24
+ * @tracked
25
+ */
26
+ @tracked tab;
27
+
28
+ /**
29
+ * The drawer component context api.
30
+ *
31
+ * @type {Object}
32
+ * @tracked
33
+ */
34
+ @tracked drawer;
35
+
36
+ /**
37
+ * Returns the array of tabs available for the drawer.
38
+ *
39
+ * @type {Array}
40
+ */
41
+ get tabs() {
42
+ const registeredTabs = this.universe.getMenuItemsFromRegistry('component:live-map-drawer');
43
+ const defaultTabs = [
44
+ this.universe._createMenuItem('Vehicles', null, { icon: 'car', component: LiveMapDrawerVehicleListingComponent }),
45
+ this.universe._createMenuItem('Drivers', null, { icon: 'id-card', component: LiveMapDrawerDriverListingComponent }),
46
+ this.universe._createMenuItem('Places', null, { icon: 'building', component: LiveMapDrawerPlaceListingComponent }),
47
+ ];
48
+
49
+ if (isArray(registeredTabs)) {
50
+ return [...defaultTabs, ...registeredTabs];
51
+ }
52
+
53
+ return defaultTabs;
54
+ }
55
+
56
+ /**
57
+ * Initializes the vehicle panel component.
58
+ */
59
+ constructor() {
60
+ super(...arguments);
61
+ this.tab = this.getTabUsingSlug(this.args.tab);
62
+ applyContextComponentArguments(this);
63
+ }
64
+
65
+ /**
66
+ * Sets the drawer component context api.
67
+ *
68
+ * @param {Object} drawerApi
69
+ * @memberof LiveMapDrawerComponent
70
+ */
71
+ @action setDrawerContext(drawerApi) {
72
+ this.drawer = drawerApi;
73
+
74
+ if (typeof this.args.onDrawerReady === 'function') {
75
+ this.args.onDrawerReady(...arguments);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Handles changing the active tab.
81
+ *
82
+ * @method
83
+ * @param {String} tab - The new tab to switch to.
84
+ * @action
85
+ */
86
+ @action onTabChanged(tab) {
87
+ this.tab = this.getTabUsingSlug(tab);
88
+ contextComponentCallback(this, 'onTabChanged', tab);
89
+ }
90
+
91
+ /**
92
+ * Finds and returns a tab based on its slug.
93
+ *
94
+ * @param {String} tabSlug - The slug of the tab.
95
+ * @returns {Object|null} The found tab or null.
96
+ */
97
+ getTabUsingSlug(tabSlug) {
98
+ if (tabSlug) {
99
+ return this.tabs.find(({ slug }) => slug === tabSlug);
100
+ }
101
+
102
+ return this.tabs[0];
103
+ }
104
+ }
@@ -84,4 +84,8 @@
84
84
 
85
85
  {{yield layers}}
86
86
  </LeafletMap>
87
- </div>
87
+ </div>
88
+
89
+ {{#if this.isDataLoaded}}
90
+ <LiveMapDrawer @tab={{@drawerTab}} @onTabChanged={{@onDrawerTabChanged}} @onResizeEnd={{@onDrawerResizeEnd}} @onResizeStart={{@onDrawerResizeStart}} @isMinimized={{@isDrawerMinimized}} @isOpen={{@isDrawerOpen}} @vehicles={{this.vehicles}} @drivers={{this.drivers}} @places={{this.places}} @liveMap={{this}} @onDrawerReady={{this.setDrawerContext}} />
91
+ {{/if}}
@@ -152,6 +152,13 @@ export default class LiveMapComponent extends Component {
152
152
  */
153
153
  @tracked isReady = false;
154
154
 
155
+ /**
156
+ * Indicates if all the data requested has completed loading.
157
+ * @type {boolean}
158
+ * @memberof LiveMapComponent
159
+ */
160
+ @tracked isDataLoaded = false;
161
+
155
162
  /**
156
163
  * Controls for visibility.
157
164
  * @type {Object}
@@ -188,6 +195,13 @@ export default class LiveMapComponent extends Component {
188
195
  */
189
196
  @tracked leafletMap;
190
197
 
198
+ /**
199
+ * The Drawer component context API.
200
+ * @type {Object}
201
+ * @memberof LiveMapComponent
202
+ */
203
+ @tracked drawer;
204
+
191
205
  /**
192
206
  * The map's zoom level.
193
207
  * @type {number}
@@ -288,21 +302,63 @@ export default class LiveMapComponent extends Component {
288
302
  // set initial coordinates
289
303
  this.setInitialCoordinates();
290
304
 
291
- // load required live data
292
- this.fetchLiveData('routes');
293
- this.fetchLiveData('vehicles', {
294
- onLoaded: (vehicles) => {
295
- this.watchMovingObjects('vehicles', vehicles);
296
- },
297
- });
298
- this.fetchLiveData('drivers', {
299
- onLoaded: (drivers) => {
300
- this.watchMovingObjects('drivers', drivers);
301
- },
302
- });
303
- this.fetchLiveData('places');
304
- this.listen();
305
- this.ready();
305
+ // load data and complete setup
306
+ this.completeSetup([
307
+ this.fetchLiveData('routes'),
308
+ this.fetchLiveData('vehicles', {
309
+ onLoaded: (vehicles) => {
310
+ this.watchMovingObjects('vehicles', vehicles);
311
+ },
312
+ }),
313
+ this.fetchLiveData('drivers', {
314
+ onLoaded: (drivers) => {
315
+ this.watchMovingObjects('drivers', drivers);
316
+ },
317
+ }),
318
+ this.fetchLiveData('places'),
319
+ ]);
320
+ }
321
+
322
+ /**
323
+ * Completes the setup of the component by processing an array of live data promises.
324
+ * It waits for all the provided promises to settle and then sets a flag indicating
325
+ * that data fetching is complete. It ensures that any final listening and readiness
326
+ * processes are invoked at the end of the setup process.
327
+ *
328
+ * @param {Promise[]} liveDataPromises - An array of promises that fetch live data.
329
+ * @returns {Promise} A promise that resolves when all data-fetching promises have settled.
330
+ */
331
+ completeSetup(liveDataPromises) {
332
+ return allSettled(liveDataPromises)
333
+ .then(() => {
334
+ this.isDataLoaded = true;
335
+ })
336
+ .finally(() => {
337
+ this.listen();
338
+ this.ready();
339
+ });
340
+ }
341
+
342
+ /**
343
+ * Reloads the live map data.
344
+ *
345
+ * @memberof LiveMapComponent
346
+ */
347
+ reload() {
348
+ this.completeSetup([
349
+ this.fetchLiveData('routes'),
350
+ this.fetchLiveData('vehicles', {
351
+ onLoaded: (vehicles) => {
352
+ this.watchMovingObjects('vehicles', vehicles);
353
+ },
354
+ }),
355
+ this.fetchLiveData('drivers', {
356
+ onLoaded: (drivers) => {
357
+ this.watchMovingObjects('drivers', drivers);
358
+ },
359
+ }),
360
+ this.fetchLiveData('places'),
361
+ ]);
306
362
  }
307
363
 
308
364
  /**
@@ -463,6 +519,11 @@ export default class LiveMapComponent extends Component {
463
519
 
464
520
  return data;
465
521
  })
522
+ .catch((error) => {
523
+ if (typeof options.onFailure === 'function') {
524
+ options.onFailure(error);
525
+ }
526
+ })
466
527
  .finally(() => {
467
528
  this.isLoading = false;
468
529
  });
@@ -838,6 +899,20 @@ export default class LiveMapComponent extends Component {
838
899
  return null;
839
900
  }
840
901
 
902
+ /**
903
+ * Sets the drawer component context api.
904
+ *
905
+ * @param {Object} drawerApi
906
+ * @memberof LiveMapComponent
907
+ */
908
+ @action setDrawerContext(drawerApi) {
909
+ this.drawer = drawerApi;
910
+
911
+ if (typeof this.args.onDrawerReady === 'function') {
912
+ this.args.onDrawerReady(...arguments);
913
+ }
914
+ }
915
+
841
916
  /**
842
917
  * Handle the 'drawstop' event.
843
918
  *
@@ -1012,6 +1087,23 @@ export default class LiveMapComponent extends Component {
1012
1087
  this.createVehicleContextMenu(vehicle, target);
1013
1088
  }
1014
1089
 
1090
+ /**
1091
+ * Handle the addition of a place marker.
1092
+ *
1093
+ * @param {PlaceModel} place - The place object.
1094
+ * @param {Event} event - The event object associated with the addition.
1095
+ * @memberof LiveMapComponent
1096
+ */
1097
+ @action onPlaceAdded(place, event) {
1098
+ const { target } = event;
1099
+
1100
+ set(target, 'record_id', place.id);
1101
+ set(target, 'record_type', 'place');
1102
+
1103
+ // set the marker instance to the vehicle model
1104
+ set(place, '_marker', target);
1105
+ }
1106
+
1015
1107
  /**
1016
1108
  * Handle the click event of a vehicle marker.
1017
1109
  *
@@ -58,5 +58,11 @@
58
58
  <MapContainer::Toolbar::VisibilityControlPanel @dd={{dd}} @liveMap={{@liveMap}} @map={{@map}} />
59
59
  </dd.Content>
60
60
  </BasicDropdown>
61
+ <button type="button" id="map-toolbar-live-map-drawer-button" class="toolbar-button is-action mb-0i" {{on "click" (fn this.onAction "onPressLiveMapDrawerToggle")}}>
62
+ <FaIcon @icon="binoculars" />
63
+ <Attach::Tooltip @class="clean" @animation="scale" @placement="right">
64
+ <InputInfo @text="Scope" @iconClass="hidden" class="py-1 px-2 bg-gray-900 -mt-1" />
65
+ </Attach::Tooltip>
66
+ </button>
61
67
  </div>
62
68
  </MapContainer::ToolbarContainer>
@@ -2,19 +2,10 @@
2
2
  <div class="modal-body-container">
3
3
  <div class="grid grid-cols-1 gap-2 text-xs dark:text-gray-100">
4
4
  <InputGroup @name="Select Vehicle" @value={{@options.driver.vehicle_uuid}}>
5
- <ModelSelect
6
- @modelName="vehicle"
7
- @selectedModel={{@options.driver.vehicle_uuid}}
8
- @placeholder="Select Vehicle to Assign"
9
- @triggerClass="form-select form-input"
10
- @infiniteScroll={{false}}
11
- @renderInPlace={{true}}
12
- @onChange={{fn (mut @options.driver.vehicle_uuid)}} as |model|
13
- >
14
- {{model.name}}
5
+ <ModelSelect @modelName="vehicle" @selectedModel={{@options.driver.vehicle_uuid}} @placeholder="Select Vehicle to Assign" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{fn (mut @options.driver.vehicle)}} @onChangeId={{fn (mut @options.driver.vehicle_uuid)}} as |model|>
6
+ {{model.display_name}}
15
7
  </ModelSelect>
16
8
  </InputGroup>
17
9
  </div>
18
10
  </div>
19
- {{yield}}
20
11
  </Modal::Default>
@@ -2,15 +2,7 @@
2
2
  <div class="modal-body-container">
3
3
  <div class="grid grid-cols-1 gap-2 text-xs dark:text-gray-100">
4
4
  <InputGroup @name="Select Vendor" @value={{@options.driver.vendor_uuid}}>
5
- <ModelSelect
6
- @modelName="vendor"
7
- @selectedModel={{@options.driver.vendor_uuid}}
8
- @placeholder="Select Vendor"
9
- @triggerClass="form-select form-input"
10
- @infiniteScroll={{false}}
11
- @renderInPlace={{true}}
12
- @onChange={{fn (mut @options.driver.vendor_uuid)}} as |model|
13
- >
5
+ <ModelSelect @modelName="vendor" @selectedModel={{@options.driver.vendor_uuid}} @placeholder="Select Vendor" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{fn (mut @options.driver.vendor)}} @onChangeId={{fn (mut @options.driver.vendor_uuid)}} as |model|>
14
6
  {{model.name}}
15
7
  </ModelSelect>
16
8
  </InputGroup>
@@ -1,6 +1,10 @@
1
1
  <Modal::Default @modalIsOpened={{@modalIsOpened}} @options={{@options}} @confirm={{@onConfirm}} @decline={{@onDecline}}>
2
2
  <div class="modal-body-container">
3
3
  <div class="grid grid-cols-2 flex-col md:flex-row gap-2 mb-6">
4
+ <div class="field-info-container">
5
+ <div class="field-name">ID</div>
6
+ <div class="field-value">{{n-a @options.fuelReport.public_id}}</div>
7
+ </div>
4
8
  <div class="field-info-container">
5
9
  <div class="field-name">Driver</div>
6
10
  <div class="field-value">{{n-a @options.fuelReport.driver_name}}</div>
@@ -13,6 +13,6 @@
13
13
  </div>
14
14
  </div>
15
15
 
16
- <ScheduleCard class="border border-night-905" @itemClass="bg-green-600" @contentClass="bg-transparent-i py-3" @titleClass="hidden-i" @order={{@options.order}} />
16
+ <Order::ScheduleCard class="border border-night-905" @itemClass="bg-green-600" @contentClass="bg-transparent-i py-3" @titleClass="hidden-i" @order={{@options.order}} />
17
17
  </div>
18
18
  </Modal::Default>
@@ -1,4 +1,4 @@
1
- <div class="order-schedule-card border border-gray-200 dark:border-gray-700" {{did-insert this.setupComponent}} ...attributes>
1
+ <div class="order-schedule-card border border-gray-200 dark:border-gray-700" ...attributes>
2
2
  <a href="javascript:;" class="{{@titleClass}} card-title border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900" {{on "click" (fn this.onTitleClick @order)}}>
3
3
  <span>{{@order.public_id}}</span>
4
4
  <div>
@@ -11,25 +11,53 @@
11
11
  <FaIcon @icon="calendar" class="mr-2" />
12
12
  <span class="font-semibold">Date scheduled</span>
13
13
  </div>
14
- <span>{{@order.scheduledAt}}</span>
14
+ <span class={{unless @order.scheduled_at "dark:text-gray-600 text-gray-400"}}>{{n-a @order.scheduledAt "Not Scheduled"}}</span>
15
15
  </div>
16
16
  <div class="flex items-center justify-between">
17
17
  <div>
18
18
  <FaIcon @icon="calendar" class="mr-2" />
19
19
  <span class="font-semibold">Date created</span>
20
20
  </div>
21
- <span>{{@order.createdAtWithTime}}</span>
21
+ <span>{{n-a @order.createdAtWithTime}}</span>
22
22
  </div>
23
23
  <div class="flex items-center justify-between">
24
- <div>
24
+ <div class="flex flex-row items-center">
25
25
  <FaIcon @icon="calendar" class="mr-2" />
26
26
  <span class="font-semibold">Driver Assigned</span>
27
+ <div class="ml-2">
28
+ <a href="javascript:;" class="text-blue-400 hover:opacity-75" {{on "click" this.startAssignDriver}}>
29
+ <FaIcon @icon="edit" @size="xs" />
30
+ </a>
31
+ </div>
32
+ </div>
33
+ <div>
34
+ {{#if this.isAssigningDriver}}
35
+ <ModelSelect @modelName="driver" @selectedModel={{@order.driver_assigned}} @placeholder="Select Driver" @triggerClass="form-select form-input form-input-sm w-48" @infiniteScroll={{false}} @renderInPlace={{true}} @allowClear={{true}} @disabled={{@model.isLoading}} @onChange={{this.assignDriver}} as |model|>
36
+ <div class="flex items-center">
37
+ <div class="w-5">
38
+ <FaIcon @icon="id-card-alt" @size="xs" />
39
+ </div>
40
+ <div class="flex-1 flex flex-row truncate text-xs">
41
+ <span class="uppercase mr-1.5 text-xs">{{model.name}}</span>
42
+ <span class="uppercase text-xs">{{model.phone}}</span>
43
+ </div>
44
+ </div>
45
+ </ModelSelect>
46
+ {{else}}
47
+ <a href="javascript:;" disabled={{not @order.driver_assigned}} class={{unless @order.driver_assigned "dark:text-gray-600 text-gray-400"}} {{on "click" (fn this.onClickDriver @order.driver_assigned)}}>{{n-a @order.driver_assigned.name "No Driver Assigned"}}</a>
48
+ {{/if}}
27
49
  </div>
28
- <span>{{@order.driver_assigned.name "None"}}</span>
29
50
  </div>
30
- <div class="z-20 relative">
31
- <RouteList @order={{@order}} />
51
+ <div class="flex items-center justify-between">
52
+ <div class="flex flex-row items-center">
53
+ <FaIcon @icon="calendar" class="mr-2" />
54
+ <span class="font-semibold">Vehicle Assigned</span>
55
+ </div>
56
+ <a href="javascript:;" disabled={{not @order.driver_assigned.vehicle}} class={{unless @order.driver_assigned.vehicle_uuid "dark:text-gray-600 text-gray-400"}} {{on "click" (fn this.onClickVehicle @order.driver_assigned.vehicle)}}>{{n-a @order.driver_assigned.vehicle_name "No Vehicle Assigned"}}</a>
32
57
  </div>
58
+ {{!-- <div class="z-20 relative">
59
+ <RouteList @order={{@order}} />
60
+ </div> --}}
33
61
  </div>
34
62
  {{yield}}
35
63
  </div>