@fleetbase/fleetops-engine 0.3.1 → 0.3.3

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 (264) hide show
  1. package/addon/components/admin/visibility-controls.js +1 -0
  2. package/addon/components/contact-form-panel.hbs +82 -0
  3. package/addon/components/contact-form-panel.js +195 -0
  4. package/addon/components/contact-panel/details.hbs +36 -0
  5. package/addon/components/contact-panel/details.js +3 -0
  6. package/addon/components/contact-panel.hbs +52 -0
  7. package/addon/components/contact-panel.js +161 -0
  8. package/addon/components/driver-form-panel.hbs +39 -55
  9. package/addon/components/driver-form-panel.js +41 -0
  10. package/addon/components/driver-panel/details.hbs +2 -2
  11. package/addon/components/driver-panel.hbs +12 -10
  12. package/addon/components/driver-panel.js +13 -0
  13. package/addon/components/fleet-form-panel.hbs +28 -28
  14. package/addon/components/fleet-form-panel.js +150 -1
  15. package/addon/components/fleet-listing-panel.hbs +8 -0
  16. package/addon/components/fleet-listing-panel.js +34 -0
  17. package/addon/components/fleet-panel/details.hbs +30 -0
  18. package/addon/components/fleet-panel/driver-listing.hbs +72 -0
  19. package/addon/components/fleet-panel/driver-listing.js +149 -0
  20. package/addon/components/fleet-panel/vehicle-listing.hbs +72 -0
  21. package/addon/components/fleet-panel/vehicle-listing.js +149 -0
  22. package/addon/components/fleet-panel.hbs +12 -58
  23. package/addon/components/fleet-panel.js +148 -26
  24. package/addon/components/fleet-vehicle-listing.hbs +0 -1
  25. package/addon/components/fuel-report-form-panel.hbs +41 -0
  26. package/addon/components/fuel-report-form-panel.js +122 -0
  27. package/addon/components/fuel-report-panel/details.hbs +38 -0
  28. package/addon/components/fuel-report-panel.hbs +30 -0
  29. package/addon/components/fuel-report-panel.js +161 -0
  30. package/addon/components/issue-form-panel.hbs +85 -0
  31. package/addon/components/issue-form-panel.js +211 -0
  32. package/addon/components/issue-panel/details.hbs +48 -0
  33. package/addon/components/issue-panel.hbs +30 -0
  34. package/addon/components/issue-panel.js +160 -0
  35. package/addon/components/layout/fleet-ops-sidebar.hbs +2 -2
  36. package/addon/components/layout/fleet-ops-sidebar.js +2 -1
  37. package/addon/components/live-map-drawer/driver-listing.hbs +6 -0
  38. package/addon/components/live-map-drawer/driver-listing.js +240 -0
  39. package/addon/components/live-map-drawer/place-listing.hbs +6 -0
  40. package/addon/components/live-map-drawer/place-listing.js +204 -0
  41. package/addon/components/live-map-drawer/vehicle-listing.hbs +6 -0
  42. package/addon/components/live-map-drawer/vehicle-listing.js +216 -0
  43. package/addon/components/live-map-drawer.hbs +17 -0
  44. package/addon/components/live-map-drawer.js +104 -0
  45. package/addon/components/live-map.hbs +5 -1
  46. package/addon/components/live-map.js +109 -15
  47. package/addon/components/map-container/toolbar.hbs +15 -9
  48. package/addon/components/map-container/topbar.hbs +1 -1
  49. package/addon/components/modals/issue-details.hbs +38 -0
  50. package/addon/components/modals/issue-from.hbs +138 -0
  51. package/addon/components/modals/order-event.hbs +1 -1
  52. package/addon/components/order/schedule-card.hbs +4 -4
  53. package/addon/components/order/schedule-card.js +13 -6
  54. package/addon/components/place-form-panel.hbs +50 -0
  55. package/addon/components/place-form-panel.js +134 -0
  56. package/addon/components/place-panel/details.hbs +95 -0
  57. package/addon/components/place-panel.hbs +30 -0
  58. package/addon/components/place-panel.js +161 -0
  59. package/addon/components/vehicle-form-panel.hbs +35 -44
  60. package/addon/components/vehicle-form-panel.js +41 -0
  61. package/addon/components/vehicle-panel/details.hbs +8 -2
  62. package/addon/components/vehicle-panel.hbs +8 -6
  63. package/addon/components/vendor-form-panel/create-form.hbs +114 -0
  64. package/addon/components/vendor-form-panel/create-form.js +158 -0
  65. package/addon/components/vendor-form-panel/edit-form.hbs +98 -0
  66. package/addon/components/vendor-form-panel/edit-form.js +51 -0
  67. package/addon/components/vendor-form-panel.hbs +48 -0
  68. package/addon/components/vendor-form-panel.js +226 -0
  69. package/addon/components/vendor-panel/details.hbs +77 -0
  70. package/addon/components/vendor-panel/details.js +12 -0
  71. package/addon/components/vendor-panel.hbs +58 -0
  72. package/addon/components/vendor-panel.js +161 -0
  73. package/addon/controllers/management/contacts/index/details.js +55 -0
  74. package/addon/controllers/management/contacts/index/edit.js +111 -0
  75. package/addon/controllers/management/contacts/index/new.js +88 -0
  76. package/addon/controllers/management/contacts/index.js +23 -128
  77. package/addon/controllers/management/drivers/index/new.js +2 -2
  78. package/addon/controllers/management/drivers/index.js +18 -32
  79. package/addon/controllers/management/fleets/index/details.js +53 -0
  80. package/addon/controllers/management/fleets/index/edit.js +75 -41
  81. package/addon/controllers/management/fleets/index/new.js +42 -57
  82. package/addon/controllers/management/fleets/index.js +0 -1
  83. package/addon/controllers/management/fuel-reports/index/details.js +63 -0
  84. package/addon/controllers/management/fuel-reports/index/edit.js +111 -0
  85. package/addon/controllers/management/fuel-reports/index/new.js +95 -0
  86. package/addon/controllers/management/fuel-reports/index.js +57 -127
  87. package/addon/controllers/management/issues/index/details.js +54 -0
  88. package/addon/controllers/management/issues/index/edit.js +111 -0
  89. package/addon/controllers/management/issues/index/new.js +94 -0
  90. package/addon/controllers/management/issues/index.js +131 -26
  91. package/addon/controllers/management/places/index/details.js +55 -0
  92. package/addon/controllers/management/places/index/edit.js +111 -0
  93. package/addon/controllers/management/places/index/new.js +88 -0
  94. package/addon/controllers/management/places/index.js +21 -182
  95. package/addon/controllers/management/vehicles/index/new.js +2 -6
  96. package/addon/controllers/management/vendors/index/details.js +55 -0
  97. package/addon/controllers/management/vendors/index/edit.js +111 -0
  98. package/addon/controllers/management/vendors/index/new.js +88 -0
  99. package/addon/controllers/management/vendors/index.js +43 -247
  100. package/addon/controllers/operations/orders/index.js +29 -15
  101. package/addon/controllers/operations/scheduler/index.js +45 -30
  102. package/addon/routes/management/contacts/index/details.js +14 -0
  103. package/addon/routes/management/contacts/index/edit.js +10 -0
  104. package/addon/routes/management/contacts/index/new.js +3 -0
  105. package/addon/routes/management/contacts/index.js +1 -1
  106. package/addon/routes/management/fleets/index/details.js +1 -1
  107. package/addon/routes/management/fleets/index/edit.js +1 -1
  108. package/addon/routes/management/fleets/index.js +1 -1
  109. package/addon/routes/management/fuel-reports/index/details.js +14 -0
  110. package/addon/routes/management/fuel-reports/index/edit.js +10 -0
  111. package/addon/routes/management/fuel-reports/index/new.js +3 -0
  112. package/addon/routes/management/fuel-reports/index.js +3 -1
  113. package/addon/routes/management/issues/index/details.js +14 -0
  114. package/addon/routes/management/issues/index/edit.js +10 -0
  115. package/addon/routes/management/issues/index/new.js +3 -0
  116. package/addon/routes/management/issues/index.js +1 -1
  117. package/addon/routes/management/places/index/details.js +14 -0
  118. package/addon/routes/management/places/index/edit.js +10 -0
  119. package/addon/routes/management/places/index/new.js +3 -0
  120. package/addon/routes/management/places/index.js +6 -1
  121. package/addon/routes/management/vendors/index/details.js +15 -0
  122. package/addon/routes/management/vendors/index/edit.js +11 -0
  123. package/addon/routes/management/vendors/index/new.js +3 -0
  124. package/addon/routes/management/vendors/index.js +1 -0
  125. package/addon/routes/operations/scheduler/index.js +25 -0
  126. package/addon/routes.js +27 -7
  127. package/addon/services/context-panel.js +60 -0
  128. package/addon/styles/fleetops-engine.css +28 -0
  129. package/addon/templates/management/contacts/index/details.hbs +1 -0
  130. package/addon/templates/management/contacts/index/edit.hbs +1 -0
  131. package/addon/templates/management/contacts/index/new.hbs +1 -0
  132. package/addon/templates/management/contacts/index.hbs +22 -3
  133. package/addon/templates/management/drivers/index.hbs +29 -5
  134. package/addon/templates/management/fleets/index/details.hbs +1 -1
  135. package/addon/templates/management/fleets/index/edit.hbs +1 -1
  136. package/addon/templates/management/fleets/index/new.hbs +1 -1
  137. package/addon/templates/management/fuel-reports/index/details.hbs +1 -0
  138. package/addon/templates/management/fuel-reports/index/edit.hbs +1 -0
  139. package/addon/templates/management/fuel-reports/index/new.hbs +1 -0
  140. package/addon/templates/management/fuel-reports/index.hbs +25 -4
  141. package/addon/templates/management/issues/index/details.hbs +1 -0
  142. package/addon/templates/management/issues/index/edit.hbs +1 -0
  143. package/addon/templates/management/issues/index/new.hbs +1 -0
  144. package/addon/templates/management/issues/index.hbs +5 -3
  145. package/addon/templates/management/places/index/details.hbs +1 -0
  146. package/addon/templates/management/places/index/edit.hbs +1 -0
  147. package/addon/templates/management/places/index/new.hbs +1 -0
  148. package/addon/templates/management/vendors/index/details.hbs +1 -0
  149. package/addon/templates/management/vendors/index/edit.hbs +1 -0
  150. package/addon/templates/management/vendors/index/new.hbs +1 -0
  151. package/addon/templates/operations/orders/index.hbs +5 -5
  152. package/addon/templates/operations/scheduler/index.hbs +33 -9
  153. package/addon/utils/create-full-calendar-event-from-order.js +8 -0
  154. package/app/components/contact-form-panel.js +1 -0
  155. package/app/components/contact-panel/details.js +1 -0
  156. package/app/components/contact-panel.js +1 -0
  157. package/app/components/{full-calendar/draggable.js → fleet-listing-panel.js} +1 -1
  158. package/app/components/fleet-panel/details.js +1 -0
  159. package/app/components/fleet-panel/driver-listing.js +1 -0
  160. package/app/components/fleet-panel/vehicle-listing.js +1 -0
  161. package/app/components/fuel-report-form-panel.js +1 -0
  162. package/app/components/{full-calendar.js → fuel-report-panel.js} +1 -1
  163. package/app/components/issue-form-panel.js +1 -0
  164. package/app/components/issue-panel.js +1 -0
  165. package/app/components/live-map-drawer/driver-listing.js +1 -0
  166. package/app/components/live-map-drawer/place-listing.js +1 -0
  167. package/app/components/live-map-drawer/vehicle-listing.js +1 -0
  168. package/app/components/live-map-drawer.js +1 -0
  169. package/app/components/place-form-panel.js +1 -0
  170. package/app/components/place-panel.js +1 -0
  171. package/app/components/vendor-form-panel/create-form.js +1 -0
  172. package/app/components/vendor-form-panel/edit-form.js +1 -0
  173. package/app/components/vendor-form-panel.js +1 -0
  174. package/app/components/vendor-panel/details.js +1 -0
  175. package/app/components/vendor-panel.js +1 -0
  176. package/app/controllers/management/contacts/index/details.js +1 -0
  177. package/app/controllers/management/contacts/index/edit.js +1 -0
  178. package/app/controllers/management/contacts/index/new.js +1 -0
  179. package/app/controllers/management/fuel-reports/index/details.js +1 -0
  180. package/app/controllers/management/fuel-reports/index/edit.js +1 -0
  181. package/app/controllers/management/fuel-reports/index/new.js +1 -0
  182. package/app/controllers/management/issues/index/details.js +1 -0
  183. package/app/controllers/management/issues/index/edit.js +1 -0
  184. package/app/controllers/management/issues/index/new.js +1 -0
  185. package/app/controllers/management/places/index/details.js +1 -0
  186. package/app/controllers/management/places/index/edit.js +1 -0
  187. package/app/controllers/management/places/index/new.js +1 -0
  188. package/app/controllers/management/vendors/index/edit.js +1 -0
  189. package/app/controllers/management/vendors/index/new.js +1 -0
  190. package/app/routes/addon/routes/management/places/index/new.js +1 -0
  191. package/app/routes/management/contacts/index/details.js +1 -0
  192. package/app/routes/management/contacts/index/edit.js +1 -0
  193. package/app/routes/management/contacts/index/new.js +1 -0
  194. package/app/routes/management/fuel-reports/index/details.js +1 -0
  195. package/app/routes/management/fuel-reports/index/edit.js +1 -0
  196. package/app/routes/management/fuel-reports/index/new.js +1 -0
  197. package/app/routes/management/issues/index/details.js +1 -0
  198. package/app/routes/management/issues/index/edit.js +1 -0
  199. package/app/routes/management/issues/index/new.js +1 -0
  200. package/app/routes/management/places/index/details.js +1 -0
  201. package/app/routes/management/places/index/edit.js +1 -0
  202. package/app/routes/management/places/index/new.js +1 -0
  203. package/app/routes/management/vendors/index/details.js +1 -0
  204. package/app/routes/management/vendors/index/edit.js +1 -0
  205. package/app/routes/management/vendors/index/new.js +1 -0
  206. package/app/templates/addon/routes/management/places/index/new.js +1 -0
  207. package/app/templates/management/contacts/index/details.js +1 -0
  208. package/app/templates/management/contacts/index/edit.js +1 -0
  209. package/app/templates/management/contacts/index/new.js +1 -0
  210. package/app/templates/management/fuel-reports/index/details.js +1 -0
  211. package/app/templates/management/fuel-reports/index/edit.js +1 -0
  212. package/app/templates/management/fuel-reports/index/new.js +1 -0
  213. package/app/templates/management/issues/index/details.js +1 -0
  214. package/app/templates/management/issues/index/edit.js +1 -0
  215. package/app/templates/management/issues/index/new.js +1 -0
  216. package/app/templates/management/places/index/details.js +1 -0
  217. package/app/templates/management/places/index/edit.js +1 -0
  218. package/app/templates/management/places/index/new.js +1 -0
  219. package/app/templates/management/vendors/index/details.js +1 -0
  220. package/app/templates/management/vendors/index/edit.js +1 -0
  221. package/app/templates/management/vendors/index/new.js +1 -0
  222. package/app/utils/create-full-calendar-event-from-order.js +1 -0
  223. package/composer.json +1 -1
  224. package/config/environment.js +2 -1
  225. package/extension.json +1 -1
  226. package/package.json +5 -4
  227. package/server/migrations/2023_11_03_072503_refactor_issues_table_columns.php +42 -0
  228. package/server/migrations/2023_11_06_040645_refactor_fuel_reports_table.php +38 -0
  229. package/server/src/Casts/Point.php +15 -1
  230. package/server/src/Http/Controllers/Internal/v1/DriverController.php +33 -15
  231. package/server/src/Http/Filter/FleetFilter.php +7 -0
  232. package/server/src/Http/Filter/FuelReportFilter.php +58 -0
  233. package/server/src/Http/Filter/IssueFilter.php +69 -0
  234. package/server/src/Http/Filter/VehicleFilter.php +10 -0
  235. package/server/src/Http/Middleware/TransformLocationMiddleware.php +48 -0
  236. package/server/src/Http/Resources/v1/Driver.php +1 -0
  237. package/server/src/Http/Resources/v1/Fleet.php +20 -21
  238. package/server/src/Http/Resources/v1/FuelReport.php +37 -35
  239. package/server/src/Http/Resources/v1/Issue.php +77 -0
  240. package/server/src/Http/Resources/v1/ParentFleet.php +60 -0
  241. package/server/src/Http/Resources/v1/SubFleet.php +60 -0
  242. package/server/src/Http/Resources/v1/Vehicle.php +4 -2
  243. package/server/src/Integrations/Lalamove/Lalamove.php +6 -6
  244. package/server/src/Models/Contact.php +7 -0
  245. package/server/src/Models/Driver.php +1 -1
  246. package/server/src/Models/Fleet.php +35 -4
  247. package/server/src/Models/FuelReport.php +53 -3
  248. package/server/src/Models/Issue.php +106 -7
  249. package/server/src/Models/Order.php +22 -0
  250. package/server/src/Models/Vehicle.php +1 -1
  251. package/server/src/Models/VehicleDevice.php +4 -2
  252. package/server/src/Models/VehicleDeviceEvent.php +8 -4
  253. package/server/src/Notifications/OrderAssigned.php +0 -6
  254. package/server/src/Notifications/OrderCanceled.php +0 -6
  255. package/server/src/Notifications/OrderDispatchFailed.php +0 -6
  256. package/server/src/Notifications/OrderDispatched.php +0 -6
  257. package/server/src/Notifications/OrderPing.php +0 -6
  258. package/server/src/Notifications/OrderSplit.php +0 -6
  259. package/server/src/Observers/FleetObserver.php +19 -0
  260. package/server/src/Providers/FleetOpsServiceProvider.php +1 -0
  261. package/server/src/Providers/NotificationServiceProvider.php +1 -1
  262. package/server/src/routes.php +2 -2
  263. package/addon/components/full-calendar/draggable.js +0 -1
  264. package/addon/components/full-calendar.js +0 -1
@@ -0,0 +1,149 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { isBlank } from '@ember/utils';
5
+ import { action, set } from '@ember/object';
6
+ import { timeout } from 'ember-concurrency';
7
+ import { task } from 'ember-concurrency-decorators';
8
+ import contextComponentCallback from '../../utils/context-component-callback';
9
+
10
+ export default class FleetPanelDriverListingComponent extends Component {
11
+ /**
12
+ * Ember data store service.
13
+ *
14
+ * @type {Service}
15
+ */
16
+ @service store;
17
+
18
+ /**
19
+ * The fetch wrapper service.
20
+ *
21
+ * @type {Service}
22
+ */
23
+ @service fetch;
24
+
25
+ /**
26
+ * The universe service.
27
+ *
28
+ * @type {Service}
29
+ */
30
+ @service universe;
31
+
32
+ /**
33
+ * The selected drivers.
34
+ *
35
+ * @var {Array}
36
+ * @memberof FleetPanelDriverListingComponent
37
+ */
38
+ @tracked selected = [];
39
+
40
+ /**
41
+ * Determines if list of drivers should be selectable.
42
+ *
43
+ * @var {Boolean}
44
+ * @memberof FleetPanelDriverListingComponent
45
+ */
46
+ @tracked selectable = false;
47
+
48
+ /**
49
+ * The fleet managing drivers for.
50
+ *
51
+ * @var {FleetModel}
52
+ * @memberof FleetPanelDriverListingComponent
53
+ */
54
+ @tracked fleet = [];
55
+
56
+ /**
57
+ * Creates an instance of FleetPanelDriverListingComponent.
58
+ * @memberof FleetPanelDriverListingComponent
59
+ */
60
+ constructor() {
61
+ super(...arguments);
62
+ const { options = {} } = this.args;
63
+
64
+ this.fleet = this.args.fleet;
65
+ this.selectable = this.args.selectable === true || options.selectable === true;
66
+ this.search.perform({ limit: -1 });
67
+ }
68
+
69
+ /**
70
+ * Fetches fleet drivers based on the given parameters.
71
+ * @param {Object} params - Parameters to filter the drivers.
72
+ * @returns {Promise} Promise object representing the fetched drivers.
73
+ * @memberof FleetPanelDriverListringComponent
74
+ */
75
+ fetchFleetDrivers(params = {}) {
76
+ return this.store.query('driver', { fleet: this.fleet.id, ...params }).then((drivers) => {
77
+ set(this, 'drivers', drivers.toArray());
78
+ contextComponentCallback(this, 'onLoaded', drivers);
79
+
80
+ return drivers;
81
+ });
82
+ }
83
+
84
+ /**
85
+ * Searches for fleet drivers based on the given parameters.
86
+ * @task
87
+ * @param {Object} params - Search parameters.
88
+ * @memberof FleetPanelDriverListringComponent
89
+ */
90
+ @task({ restartable: true }) *search(params = {}) {
91
+ if (!isBlank(params.value)) {
92
+ yield timeout(300);
93
+ }
94
+
95
+ yield this.fetchFleetDrivers(params);
96
+ }
97
+
98
+ /**
99
+ * Handles input events to initiate search.
100
+ * @action
101
+ * @param {Object} event - The input event.
102
+ * @memberof FleetPanelDriverListringComponent
103
+ */
104
+ @action onInput({ target: { value } }) {
105
+ this.search.perform({ query: value });
106
+ }
107
+
108
+ /**
109
+ * Assigns a driver to the fleet.
110
+ * @action
111
+ * @param {DriverModel} driver - The driver to be added.
112
+ * @memberof FleetPanelDriverListringComponent
113
+ */
114
+ @action onAddDriver(driver) {
115
+ this.fetch.post('fleets/assign-driver', { driver: driver.id, fleet: this.fleet.id }).then(() => {
116
+ this.drivers.pushObject(driver);
117
+ this.universe.trigger('fleet.driver.assigned', this.fleet, driver);
118
+ });
119
+ }
120
+
121
+ /**
122
+ * Removes a driver from the fleet.
123
+ * @action
124
+ * @param {DriverModel} driver - The driver to be removed.
125
+ * @memberof FleetPanelDriverListringComponent
126
+ */
127
+ @action onRemoveDriver(driver) {
128
+ this.fetch.post('fleets/remove-driver', { driver: driver.id, fleet: this.fleet.id }).then(() => {
129
+ this.drivers.removeObject(driver);
130
+ this.universe.trigger('fleet.driver.unassigned', this.fleet, driver);
131
+ });
132
+ }
133
+
134
+ /**
135
+ * Selects or deselects a driver.
136
+ * @action
137
+ * @param {DriverModel} driver - The driver to be selected or deselected.
138
+ * @memberof FleetPanelDriverListringComponent
139
+ */
140
+ @action onSelect(driver) {
141
+ if (this.selected.includes(driver)) {
142
+ this.selected.removeObject(driver);
143
+ } else {
144
+ this.selected.pushObject(driver);
145
+ }
146
+
147
+ contextComponentCallback(this, 'onSelect', ...arguments);
148
+ }
149
+ }
@@ -0,0 +1,72 @@
1
+ <div class={{or @wrapperClass @options.wrapperClass}}>
2
+ <div class="fleet-vehicle-listing" ...attributes>
3
+ <div class="mb-3 flex items-center justify-between">
4
+ <div class="flex items-center">
5
+ <div class="fleet-vehicle-listing-search">
6
+ <Input @type="text" {{on "input" this.onInput}} placeholder="Search vehicle's in fleet" class="w-64 form-input form-input-sm" />
7
+ </div>
8
+ {{#if this.search.isRunning}}
9
+ <div class="mx-2">
10
+ <Spinner @iconClass="text-sky-500 fa-spin-800ms" />
11
+ </div>
12
+ {{/if}}
13
+ </div>
14
+ <div class="w-56">
15
+ <ModelSelect @modelName="vehicle" @selectedModel={{this.selectedVehicle}} @placeholder="Add vehicle to fleet" @triggerClass="form-select form-input form-select-sm form-input-sm" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{this.onAddVehicle}} as |model|>
16
+ {{model.displayName}}
17
+ </ModelSelect>
18
+ </div>
19
+ </div>
20
+ <div class="bg-white border border-gray-200 rounded shadow-sm dark:bg-gray-800 dark:border-gray-900 text-xs">
21
+ <div class="w-full">
22
+ <div class="grid grid-cols-12 text-xs p-3 font-bold text-gray-800 dark:text-gray-100 border-b border-gray-900 shadow">
23
+ {{#if this.selectable}}
24
+ <div></div>
25
+ {{/if}}
26
+ <div class="col-span-4 flex items-center">Vehicle</div>
27
+ <div class="col-span-7 flex items-center"></div>
28
+ </div>
29
+ </div>
30
+ <div class="h-48 overflow-y-scroll">
31
+ {{#if this.search.isRunning}}
32
+ <div class="flex items-center justify-center p-4 dark:text-gray-100">
33
+ <div class="mr-2">
34
+ <Spinner @iconClass="text-sky-500" />
35
+ </div>
36
+ <span>Loading fleet vehicles...</span>
37
+ </div>
38
+ {{/if}}
39
+ {{#each this.vehicles as |vehicle|}}
40
+ <div class="flex flex-row items-center justify-between text-xs py-2 px-3 text-gray-800 border-b border-gray-200 dark:border-gray-900 dark:text-gray-100">
41
+ <div class="flex flex-row items-center">
42
+ {{#if this.selectable}}
43
+ <div class="flex items-center mr-2">
44
+ <Checkbox @value={{includes vehicle this.selected}} @onToggle={{fn this.onSelect vehicle}} />
45
+ </div>
46
+ {{/if}}
47
+ <div class="flex items-center">
48
+ <div class="flex flex-row items-start">
49
+ <div class="mr-2">
50
+ <div class="relative">
51
+ <Image src={{vehicle.photo_url}} alt={{vehicle.name}} class="w-5 h-5 rounded-md" @fallbackSrc={{config "defaultValues.vehicleImage"}} />
52
+ <FaIcon @icon="circle" class="absolute right-0 top-0 -mr-1 -mt-1 {{if vehicle.online "text-green-500" "text-yellow-200"}}" />
53
+ </div>
54
+ </div>
55
+ <div>
56
+ <div class="font-semibold">{{vehicle.displayName}}</div>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ <div class="flex items-center justify-end">
62
+ <a href="javascript:;" class="text-danger text-opacity-75" {{on "click" (fn this.onRemoveVehicle vehicle)}}>
63
+ <FaIcon @icon="times" @prefix="fas" class="mr-1" />
64
+ <span>Remove</span>
65
+ </a>
66
+ </div>
67
+ </div>
68
+ {{/each}}
69
+ </div>
70
+ </div>
71
+ </div>
72
+ </div>
@@ -0,0 +1,149 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { isBlank } from '@ember/utils';
5
+ import { action, set } from '@ember/object';
6
+ import { timeout } from 'ember-concurrency';
7
+ import { task } from 'ember-concurrency-decorators';
8
+ import contextComponentCallback from '../../utils/context-component-callback';
9
+
10
+ export default class FleetPanelVehicleListingComponent extends Component {
11
+ /**
12
+ * Ember data store service.
13
+ *
14
+ * @type {Service}
15
+ */
16
+ @service store;
17
+
18
+ /**
19
+ * The fetch wrapper service.
20
+ *
21
+ * @type {Service}
22
+ */
23
+ @service fetch;
24
+
25
+ /**
26
+ * The universe service.
27
+ *
28
+ * @type {Service}
29
+ */
30
+ @service universe;
31
+
32
+ /**
33
+ * The selected vehicles.
34
+ *
35
+ * @var {Array}
36
+ * @memberof FleetPanelVehicleListingComponent
37
+ */
38
+ @tracked selected = [];
39
+
40
+ /**
41
+ * Determines if list of vehicles should be selectable.
42
+ *
43
+ * @var {Boolean}
44
+ * @memberof FleetPanelVehicleListingComponent
45
+ */
46
+ @tracked selectable = false;
47
+
48
+ /**
49
+ * The fleet managing vehicles for.
50
+ *
51
+ * @var {FleetModel}
52
+ * @memberof FleetPanelVehicleListingComponent
53
+ */
54
+ @tracked fleet = [];
55
+
56
+ /**
57
+ * Creates an instance of FleetPanelVehicleListingComponent.
58
+ * @memberof FleetPanelVehicleListingComponent
59
+ */
60
+ constructor() {
61
+ super(...arguments);
62
+ const { options = {} } = this.args;
63
+
64
+ this.fleet = this.args.fleet;
65
+ this.selectable = this.args.selectable === true || options.selectable === true;
66
+ this.search.perform({ limit: -1 });
67
+ }
68
+
69
+ /**
70
+ * Fetches fleet vehicles based on the given parameters.
71
+ * @param {Object} params - Parameters to filter the vehicles.
72
+ * @returns {Promise} Promise object representing the fetched vehicles.
73
+ * @memberof FleetPanelVehicleListringComponent
74
+ */
75
+ fetchFleetVehicles(params = {}) {
76
+ return this.store.query('vehicle', { fleet: this.fleet.id, ...params }).then((vehicles) => {
77
+ set(this, 'vehicles', vehicles.toArray());
78
+ contextComponentCallback(this, 'onLoaded', vehicles);
79
+
80
+ return vehicles;
81
+ });
82
+ }
83
+
84
+ /**
85
+ * Searches for fleet vehicles based on the given parameters.
86
+ * @task
87
+ * @param {Object} params - Search parameters.
88
+ * @memberof FleetPanelVehicleListringComponent
89
+ */
90
+ @task({ restartable: true }) *search(params = {}) {
91
+ if (!isBlank(params.value)) {
92
+ yield timeout(300);
93
+ }
94
+
95
+ yield this.fetchFleetVehicles(params);
96
+ }
97
+
98
+ /**
99
+ * Handles input events to initiate search.
100
+ * @action
101
+ * @param {Object} event - The input event.
102
+ * @memberof FleetPanelVehicleListringComponent
103
+ */
104
+ @action onInput({ target: { value } }) {
105
+ this.search.perform({ query: value });
106
+ }
107
+
108
+ /**
109
+ * Assigns a vehicle to the fleet.
110
+ * @action
111
+ * @param {VehicleModel} vehicle - The vehicle to be added.
112
+ * @memberof FleetPanelVehicleListringComponent
113
+ */
114
+ @action onAddVehicle(vehicle) {
115
+ this.fetch.post('fleets/assign-vehicle', { vehicle: vehicle.id, fleet: this.fleet.id }).then(() => {
116
+ this.vehicles.pushObject(vehicle);
117
+ this.universe.trigger('fleet.vehicle.assigned', this.fleet, vehicle);
118
+ });
119
+ }
120
+
121
+ /**
122
+ * Removes a vehicle from the fleet.
123
+ * @action
124
+ * @param {VehicleModel} vehicle - The vehicle to be removed.
125
+ * @memberof FleetPanelVehicleListringComponent
126
+ */
127
+ @action onRemoveVehicle(vehicle) {
128
+ this.fetch.post('fleets/remove-vehicle', { vehicle: vehicle.id, fleet: this.fleet.id }).then(() => {
129
+ this.vehicles.removeObject(vehicle);
130
+ this.universe.trigger('fleet.vehicle.unassigned', this.fleet, vehicle);
131
+ });
132
+ }
133
+
134
+ /**
135
+ * Selects or deselects a vehicle.
136
+ * @action
137
+ * @param {VehicleModel} vehicle - The vehicle to be selected or deselected.
138
+ * @memberof FleetPanelVehicleListringComponent
139
+ */
140
+ @action onSelect(vehicle) {
141
+ if (this.selected.includes(vehicle)) {
142
+ this.selected.removeObject(vehicle);
143
+ } else {
144
+ this.selected.pushObject(vehicle);
145
+ }
146
+
147
+ contextComponentCallback(this, 'onSelect', ...arguments);
148
+ }
149
+ }
@@ -1,70 +1,24 @@
1
- <Overlay @position="right" @noBackdrop={{true}} @fullHeight={{true}} @width="700">
2
- <Overlay::Header @title="Vehicle Details" @status={{@fleet.public_id}} @hideStatusDot={{true}}
3
- @createdAt={{@fleet.createdAt}} @onPressCancel={{@onPressCancel}}>
1
+ <Overlay @onLoad={{this.setOverlayContext}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizeble={{or this.isResizable @isResizable}} @width={{or this.width @width "600px"}}>
2
+ <Overlay::Header @title={{this.fleet.name}} @status={{this.fleet.public_id}} @disableBadgeHumanize={{true}} @hideStatusDot={{true}} @createdAt={{this.fleet.createdAt}}>
3
+ <Button @type="default" @icon="pen" @helpText="Edit fleet" @onClick={{this.onEdit}} @wrapperClass="mr-2" />
4
+ <Button @type="default" @icon="times" @helpText={{if this.fleet.id "Cancel edit fleet" "Cancel new fleet"}} @onClick={{this.onPressCancel}} />
4
5
  </Overlay::Header>
5
6
 
6
7
  <Overlay::Body class="no-padding" @increaseInnerBodyHeightBy={{1000}}>
7
8
  <div class="section-header-actions w-full overflow-x-scroll lg:overflow-x-auto">
8
9
  <div class="ui-tabs mt-4">
9
10
  <nav>
10
- <a href="javascript:;" class="ui-tab {{if (eq this.currentTab "details") 'active' }}" {{on "click" (fn this.changeTab "details" )}}>
11
- <FaIcon @icon="circle-info" class="mr-1" />
12
- <span>Details</span>
13
- </a>
14
- <a href="javascript:;" class="ui-tab {{if (eq this.currentTab "vehicles") 'active' }}" {{on "click" (fn this.changeTab "vehicles" )}}>
15
- <FaIcon @icon="satellite-dish" class="mr-1" />
16
- <span>Vehicles</span>
17
- </a>
18
- <a href="javascript:;" class="ui-tab {{if (eq this.currentTab "drivers") 'active' }}" {{on "click" (fn this.changeTab "drivers" )}}>
19
- <FaIcon @icon="hard-drive" class="mr-1" />
20
- <span>Drivers</span>
21
- </a>
11
+ {{#each this.tabs as |tab|}}
12
+ <a href="javascript:;" class="ui-tab {{if (eq this.tab.slug tab.slug) 'active' }}" {{on "click" (fn this.onTabChanged tab.slug)}}>
13
+ <FaIcon @icon={{tab.icon}} class="mr-1" />
14
+ <span>{{tab.title}}</span>
15
+ </a>
16
+ {{/each}}
22
17
  </nav>
23
18
  </div>
24
19
  </div>
25
- <div class="tab-content tab-{{this.currentTab}}">
26
- <div class="p-4">
27
- {{#if (eq this.currentTab "details")}}
28
- <div class="modal-body-container">
29
- <div class="grid grid-cols-2 flex-col md:flex-row gap-2 mb-6">
30
- <div class="field-info-container">
31
- <div class="field-name">Name</div>
32
- <div class="field-value">{{n-a @fleet.name}}</div>
33
- </div>
34
- <div class="field-info-container">
35
- <div class="field-name">Service Area</div>
36
- <div class="field-value">{{n-a @fleet.serviceArea.name}}</div>
37
- </div>
38
- <div class="field-info-container">
39
- <div class="field-name">Zone</div>
40
- <div class="field-value">{{n-a @fleet.zone.name}}</div>
41
- </div>
42
- <div class="field-info-container">
43
- <div class="field-name">Task</div>
44
- <div class="field-value">{{n-a @fleet.task}}</div>
45
- </div>
46
- <div class="field-info-container">
47
- <div class="field-name">Active Manpower</div>
48
- <div class="field-value">{{@fleet.drivers_online_count}} of {{@fleet.drivers_count}} Online</div>
49
- </div>
50
- <div class="field-info-container">
51
- <div class="field-name">Date Created</div>
52
- <div class="field-value">{{@fleet.createdAtShort}}</div>
53
- </div>
54
- </div>
55
- </div>
56
- {{/if}}
57
- {{#if (eq this.currentTab "vehicles")}}
58
- <div class="modal-body-container">
59
- <FleetVehicleListing @fleet={{@fleet}} @onAddVehicle={{this.addVehicle}} @onRemoveVehicle={{this.removeVehicle}} />
60
- </div>
61
- {{/if}}
62
- {{#if (eq this.currentTab "drivers")}}
63
- <div class="modal-body-container">
64
- <FleetDriverListing @fleet={{@fleet}} @onAddDriver={{this.addDriver}} @onRemoveDriver={{this.removeDriver}} />
65
- </div>
66
- {{/if}}
67
- </div>
20
+ <div class="tab-content tab-{{this.tab.slug}}">
21
+ {{component this.tab.component fleet=this.fleet tabOptions=this.tab options=this.tab.componentParams}}
68
22
  </div>
69
23
  </Overlay::Body>
70
24
  </Overlay>
@@ -2,51 +2,173 @@ import Component from '@glimmer/component';
2
2
  import { tracked } from '@glimmer/tracking';
3
3
  import { action } from '@ember/object';
4
4
  import { inject as service } from '@ember/service';
5
+ import { isArray } from '@ember/array';
6
+ import FleetPanelDetailComponent from './fleet-panel/details';
7
+ import FleetPanelDriverListingComponent from './fleet-panel/driver-listing';
8
+ import FleetPanelVehicleListingComponent from './fleet-panel/vehicle-listing';
9
+ import contextComponentCallback from '../utils/context-component-callback';
10
+ import applyContextComponentArguments from '../utils/apply-context-component-arguments';
5
11
 
6
12
  export default class FleetPanelComponent extends Component {
13
+ /**
14
+ * Service for fetching data.
15
+ *
16
+ * @type {Service}
17
+ */
7
18
  @service fetch;
19
+
20
+ /**
21
+ * Service for managing modals.
22
+ *
23
+ * @type {Service}
24
+ */
8
25
  @service modalsManager;
26
+
27
+ /**
28
+ * Universe service for managing global data and settings.
29
+ *
30
+ * @type {Service}
31
+ */
9
32
  @service universe;
33
+
34
+ /**
35
+ * Ember data store service.
36
+ *
37
+ * @type {Service}
38
+ */
10
39
  @service store;
11
- @service fetch;
12
- @tracked currentTab;
13
- @tracked fleet;
14
40
 
41
+ /**
42
+ * Service for managing routing within the host app.
43
+ *
44
+ * @type {Service}
45
+ */
46
+ @service hostRouter;
47
+
48
+ /**
49
+ * Service for managing the context panel.
50
+ *
51
+ * @type {Service}
52
+ */
53
+ @service contextPanel;
54
+
55
+ /**
56
+ * The current active tab.
57
+ *
58
+ * @type {Object}
59
+ * @tracked
60
+ */
61
+ @tracked tab;
62
+
63
+ /**
64
+ * The vehicle being displayed or edited.
65
+ *
66
+ * @type {VehicleModel}
67
+ * @tracked
68
+ */
69
+ @tracked vehicle;
70
+
71
+ /**
72
+ * Returns the array of tabs available for the panel.
73
+ *
74
+ * @type {Array}
75
+ */
76
+ get tabs() {
77
+ const registeredTabs = this.universe.getMenuItemsFromRegistry('component:fleet-panel');
78
+ const defaultTabs = [
79
+ this.universe._createMenuItem('Details', null, { icon: 'circle-info', component: FleetPanelDetailComponent }),
80
+ this.universe._createMenuItem('Vehicles', null, {
81
+ icon: 'car',
82
+ component: FleetPanelVehicleListingComponent,
83
+ componentParams: { wrapperClass: 'px-4 pt-6', selectable: true },
84
+ }),
85
+ this.universe._createMenuItem('Drivers', null, {
86
+ icon: 'id-card',
87
+ component: FleetPanelDriverListingComponent,
88
+ componentParams: { wrapperClass: 'px-4 pt-6', selectable: true },
89
+ }),
90
+ ];
91
+
92
+ if (isArray(registeredTabs)) {
93
+ return [...defaultTabs, ...registeredTabs];
94
+ }
95
+
96
+ return defaultTabs;
97
+ }
98
+
99
+ /**
100
+ * Initializes the vehicle panel component.
101
+ */
15
102
  constructor() {
16
103
  super(...arguments);
17
104
  this.fleet = this.args.fleet;
18
- this.changeTab(this.args.tab || 'details');
105
+ this.tab = this.getTabUsingSlug(this.args.tab);
106
+ applyContextComponentArguments(this);
19
107
  }
20
108
 
21
- @action async changeTab(tab) {
22
- this.currentTab = tab;
23
-
24
- if (typeof this.args.onTabChanged === 'function') {
25
- this.args.onTabChanged(tab);
26
- }
109
+ /**
110
+ * Sets the overlay context.
111
+ *
112
+ * @action
113
+ * @param {OverlayContextObject} overlayContext
114
+ */
115
+ @action setOverlayContext(overlayContext) {
116
+ this.context = overlayContext;
117
+ contextComponentCallback(this, 'onLoad', ...arguments);
27
118
  }
28
119
 
29
- @action addDriver(driver) {
30
- this.fetch.post('fleets/assign-driver', { driver: driver.id, fleet: this.fleet.id }).then(() => {
31
- this.universe.trigger('fleet.driver.assigned', this.fleet, driver);
32
- });
120
+ /**
121
+ * Handles changing the active tab.
122
+ *
123
+ * @method
124
+ * @param {String} tab - The new tab to switch to.
125
+ * @action
126
+ */
127
+ @action onTabChanged(tab) {
128
+ this.tab = this.getTabUsingSlug(tab);
129
+ contextComponentCallback(this, 'onTabChanged', tab);
33
130
  }
34
131
 
35
- @action removeDriver(driver) {
36
- this.fetch.post('fleets/remove-driver', { driver: driver.id, fleet: this.fleet.id }).then(() => {
37
- this.universe.trigger('fleet.driver.unassigned', this.fleet, driver);
38
- });
132
+ /**
133
+ * Handles edit action for the fleet.
134
+ *
135
+ * @method
136
+ * @action
137
+ */
138
+ @action onEdit() {
139
+ const isActionOverrided = contextComponentCallback(this, 'onEdit', this.fleet);
140
+
141
+ if (!isActionOverrided) {
142
+ this.contextPanel.focus(this.fleet, 'editing', {
143
+ onAfterSave: () => {
144
+ this.contextPanel.clear();
145
+ },
146
+ });
147
+ }
39
148
  }
40
149
 
41
- @action addVehicle(vehicle) {
42
- this.fetch.post('fleets/assign-vehicle', { vehicle: vehicle.id, fleet: this.fleet.id }).then(() => {
43
- this.universe.trigger('fleet.vehicle.assigned', this.fleet, vehicle);
44
- });
150
+ /**
151
+ * Handles the cancel action.
152
+ *
153
+ * @method
154
+ * @action
155
+ * @returns {Boolean} Indicates whether the cancel action was overridden.
156
+ */
157
+ @action onPressCancel() {
158
+ return contextComponentCallback(this, 'onPressCancel', this.fleet);
45
159
  }
46
160
 
47
- @action removeVehicle(vehicle) {
48
- this.fetch.post('fleets/remove-vehicle', { vehicle: vehicle.id, fleet: this.fleet.id }).then(() => {
49
- this.universe.trigger('fleet.vehicle.unassigned', this.fleet, vehicle);
50
- });
161
+ /**
162
+ * Finds and returns a tab based on its slug.
163
+ *
164
+ * @param {String} tabSlug - The slug of the tab.
165
+ * @returns {Object|null} The found tab or null.
166
+ */
167
+ getTabUsingSlug(tabSlug) {
168
+ if (tabSlug) {
169
+ return this.tabs.find(({ slug }) => slug === tabSlug);
170
+ }
171
+
172
+ return this.tabs[0];
51
173
  }
52
174
  }
@@ -4,7 +4,6 @@
4
4
  <div class="fleet-vehicle-listing-search">
5
5
  <Input @type="text" {{on "keyup" (perform this.search)}} placeholder="Search vehicle in fleet" class="w-64 form-input form-input-sm" />
6
6
  </div>
7
-
8
7
  {{#if this.isLoading}}
9
8
  <div class="mx-2">
10
9
  <Spinner @iconClass="text-sky-500 fa-spin-800ms" />