@fleetbase/fleetops-engine 0.4.12 → 0.4.13

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 (66) hide show
  1. package/addon/components/admin/avatar-management.hbs +78 -0
  2. package/addon/components/admin/avatar-management.js +191 -0
  3. package/addon/components/avatar-picker.hbs +15 -0
  4. package/addon/components/avatar-picker.js +57 -0
  5. package/addon/components/driver-form-panel.hbs +12 -13
  6. package/addon/components/driver-panel/details.hbs +7 -7
  7. package/addon/components/edit-order-route-panel.hbs +9 -69
  8. package/addon/components/edit-order-route-panel.js +78 -27
  9. package/addon/components/fleet-listing-panel.hbs +1 -1
  10. package/addon/components/layout/fleet-ops-sidebar/driver-listing.hbs +1 -1
  11. package/addon/components/layout/fleet-ops-sidebar.hbs +2 -1
  12. package/addon/components/live-map.js +0 -1
  13. package/addon/components/order/schedule-card.hbs +29 -17
  14. package/addon/components/order/schedule-card.js +1 -1
  15. package/addon/components/place-form-panel.hbs +35 -51
  16. package/addon/components/place-panel/details.hbs +10 -14
  17. package/addon/components/place-panel.hbs +2 -12
  18. package/addon/components/vehicle-form-panel.hbs +11 -80
  19. package/addon/components/vehicle-form-panel.js +33 -0
  20. package/addon/controllers/management/places/index.js +29 -21
  21. package/addon/controllers/operations/orders/index/view.js +10 -10
  22. package/addon/controllers/operations/scheduler/index.js +7 -4
  23. package/addon/engine.js +7 -1
  24. package/addon/styles/fleetops-engine.css +94 -0
  25. package/addon/templates/management/places/index.hbs +1 -1
  26. package/addon/templates/operations/scheduler/index.hbs +5 -4
  27. package/addon/utils/create-full-calendar-event-from-order.js +23 -1
  28. package/app/components/admin/avatar-management.js +1 -0
  29. package/app/components/avatar-picker.js +1 -0
  30. package/composer.json +2 -2
  31. package/config/environment.js +2 -0
  32. package/extension.json +1 -1
  33. package/package.json +3 -3
  34. package/server/migrations/2023_09_14_074512_update_vehicles_table.php +2 -2
  35. package/server/migrations/2023_09_14_074619_create_vehicle_devices_table.php +2 -2
  36. package/server/migrations/2023_09_26_071205_add_online_column_to_vehicles_table.php +2 -2
  37. package/server/migrations/2023_09_26_083957_create_fleet_vehicles_table.php +2 -2
  38. package/server/migrations/2023_09_27_023757_add_column_to_fleets_table.php +2 -2
  39. package/server/migrations/2023_10_05_074811_update_vehicle.php +2 -2
  40. package/server/migrations/2023_10_25_093014_create_vehicle_device_events_table.php +2 -2
  41. package/server/migrations/2023_11_03_072503_refactor_issues_table_columns.php +2 -2
  42. package/server/migrations/2023_11_06_040645_refactor_fuel_reports_table.php +2 -2
  43. package/server/migrations/2023_11_09_041807_add_status_column_to_fuel_reports_table.php +2 -2
  44. package/server/migrations/2023_11_15_062814_add_comments_column_and_resolved_at_column_to_vehicle_device_events_table.php +2 -2
  45. package/server/migrations/2023_11_17_053001_add_category_uuid_to_entities_table.php +2 -2
  46. package/server/migrations/2023_11_28_074244_add_supplier_uuid_column_to_entities_table.php +2 -2
  47. package/server/migrations/{2023_12_14_100209_add_meta_column_on_driver_table.php → 2023_12_14_100209_add_meta_column_on_driver_table copy.php } +5 -3
  48. package/server/migrations/2024_02_18_100209_add_avatar_url_columns_table.php +54 -0
  49. package/server/src/Expansions/UserExpansion.php +1 -0
  50. package/server/src/Http/Controllers/Api/v1/DriverController.php +7 -1
  51. package/server/src/Http/Controllers/Api/v1/PlaceController.php +11 -2
  52. package/server/src/Http/Controllers/Internal/v1/DriverController.php +15 -8
  53. package/server/src/Http/Controllers/Internal/v1/OrderController.php +46 -0
  54. package/server/src/Http/Controllers/Internal/v1/PlaceController.php +12 -0
  55. package/server/src/Http/Resources/v1/Driver.php +6 -4
  56. package/server/src/Http/Resources/v1/Order.php +2 -1
  57. package/server/src/Http/Resources/v1/Payload.php +8 -4
  58. package/server/src/Http/Resources/v1/Place.php +2 -0
  59. package/server/src/Http/Resources/v1/Vehicle.php +1 -0
  60. package/server/src/Models/Driver.php +76 -0
  61. package/server/src/Models/Payload.php +49 -3
  62. package/server/src/Models/Place.php +71 -0
  63. package/server/src/Models/Vehicle.php +44 -20
  64. package/server/src/Notifications/OrderAssigned.php +2 -0
  65. package/server/src/routes.php +3 -0
  66. package/translations/en-us.yaml +16 -4
@@ -3,6 +3,7 @@ import { tracked } from '@glimmer/tracking';
3
3
  import { action } from '@ember/object';
4
4
  import { inject as service } from '@ember/service';
5
5
  import { isArray } from '@ember/array';
6
+ import { task } from 'ember-concurrency-decorators';
6
7
  import contextComponentCallback from '../utils/context-component-callback';
7
8
  import applyContextComponentArguments from '../utils/apply-context-component-arguments';
8
9
  import getRoutingHost from '@fleetbase/ember-core/utils/get-routing-host';
@@ -87,26 +88,50 @@ export default class EditOrderRoutePanelComponent extends Component {
87
88
  contextComponentCallback(this, 'onLoad', ...arguments);
88
89
  }
89
90
 
90
- /**
91
- * Handles save action for the order route.
92
- *
93
- * @method
94
- * @action
95
- */
96
- @action onSave() {
97
- const isActionOverrided = contextComponentCallback(this, 'onSave', this.order);
98
-
99
- if (!isActionOverrided) {
100
- return this.order
101
- .save()
102
- .then((order) => {
103
- this.notifications.success(this.intl.t('fleet-ops.operations.orders.index.view.update-success', { orderId: order.public_id }));
104
- contextComponentCallback(this, 'onAfterSave', order);
105
- })
106
- .catch((error) => {
107
- this.notifications.serverError(error);
108
- });
91
+ @task *save() {
92
+ const { payload } = this.order;
93
+
94
+ yield this.fetch
95
+ .patch(
96
+ `orders/route/${this.order.id}`,
97
+ {
98
+ pickup: payload.pickup,
99
+ dropoff: payload.dropoff,
100
+ return: payload.return,
101
+ waypoints: this._serializeWaypoints(payload.waypoints),
102
+ },
103
+ {
104
+ normalizeToEmberData: true,
105
+ normalizeModelType: 'order',
106
+ }
107
+ )
108
+ .then((order) => {
109
+ this.notifications.success(this.intl.t('fleet-ops.operations.orders.index.view.update-success', { orderId: order.public_id }));
110
+ contextComponentCallback(this, 'onAfterSave', order);
111
+ })
112
+ .catch((error) => {
113
+ this.notifications.serverError(error);
114
+ });
115
+ }
116
+
117
+ _serializeWaypoints(waypoints = []) {
118
+ if (!waypoints) {
119
+ return [];
109
120
  }
121
+
122
+ waypoints = typeof waypoints.toArray === 'function' ? waypoints.toArray() : Array.from(waypoints);
123
+ return waypoints.map((waypoint) => {
124
+ const json = waypoint.serialize();
125
+ // if place is serialized just send it back
126
+ if (json.place) {
127
+ return json;
128
+ }
129
+
130
+ // set id for place_uuid
131
+ json.place_uuid = waypoint.place ? waypoint.place.id : waypoint.place_uuid;
132
+
133
+ return json;
134
+ });
110
135
  }
111
136
 
112
137
  /**
@@ -147,26 +172,50 @@ export default class EditOrderRoutePanelComponent extends Component {
147
172
  }
148
173
 
149
174
  this.order.payload.setProperties({
175
+ pickup: null,
176
+ dropoff: null,
177
+ return: null,
150
178
  pickup_uuid: null,
151
179
  dropoff_uuid: null,
180
+ return_uuid: null,
152
181
  });
153
182
  } else {
154
- const waypoint = this.store.createRecord('waypoint');
155
- this.order.payload.waypoints.pushObject(waypoint);
183
+ // get pickup from payload waypoints if available
184
+ const waypoints = typeof this.order.payload.waypoints.toArray === 'function' ? this.order.payload.waypoints.toArray() : Array.from(this.order.payload.waypoints);
185
+
186
+ if (waypoints[0]) {
187
+ const pickup = this.createPlaceFromWaypoint(waypoints[0]);
188
+ this.order.payload.set('pickup', pickup);
189
+ }
190
+
191
+ if (waypoints[1]) {
192
+ const dropoff = this.createPlaceFromWaypoint(waypoints[1]);
193
+ this.order.payload.set('dropoff', dropoff);
194
+ }
156
195
 
157
196
  this.order.payload.setProperties({
158
- pickup_uuid: null,
159
- dropoff_uuid: null,
160
- pickup: null,
161
- dropoff: null,
197
+ waypoints: [],
162
198
  });
163
199
  }
164
200
 
201
+ // this.isMultiDrop = isMultiDrop;
165
202
  contextComponentCallback(this, 'onRouteChanged');
166
203
  }
167
204
 
205
+ createPlaceFromWaypoint(waypoint) {
206
+ const json = waypoint.serialize();
207
+ return this.store.createRecord('place', json);
208
+ }
209
+
168
210
  addWaypointFromExistingPlace(place) {
169
- const waypoint = this.store.createRecord('waypoint', { place, location: place.location });
211
+ const json = place.serialize();
212
+ const waypoint = this.store.createRecord('waypoint', {
213
+ uuid: place.id,
214
+ place_uuid: place.id,
215
+ location: place.location,
216
+ place,
217
+ ...json,
218
+ });
170
219
  this.order.payload.waypoints.pushObject(waypoint);
171
220
 
172
221
  // fire callback
@@ -196,11 +245,13 @@ export default class EditOrderRoutePanelComponent extends Component {
196
245
  return;
197
246
  }
198
247
 
248
+ const json = place.serialize();
199
249
  this.order.payload.waypoints.objectAt(index).setProperties({
200
- name: place.name,
250
+ uuid: place.id,
201
251
  place_uuid: place.id,
202
252
  location: place.location,
203
253
  place,
254
+ ...json,
204
255
  });
205
256
 
206
257
  // fire callback waypoint place selected
@@ -3,6 +3,6 @@
3
3
  <FleetListingPanel @fleet={{subFleet}} @onVehicleClicked={{this.onVehicleClicked}} @depth={{add @depth 1}} @itemDropdownButton={{@itemDropdownButton}} @itemDropdownButtonActions={{@itemDropdownButtonActions}} />
4
4
  {{/each}}
5
5
  {{#each this.fleet.vehicles as |vehicle|}}
6
- <Layout::Sidebar::Item @icon="circle" @iconSize="2xs" @iconClass={{if vehicle.online "text-green-500" "text-yellow-200"}} @onClick={{fn this.onVehicleClicked vehicle}} @rightSideComponent={{@itemRightSideComponent}} @rightSideComponentContext={{@itemRightSideComponentContext}} @rightSideStatus={{@itemRightSideStatus}} @rightSideStatusText={{@itemRightSideStatusText}} @hideRightSideStatusDot={{@itemHideRightSideStatusDot}} @rightSideStatusClass={{@itemRightSideStatusClass}} @disableRightSideStatusHumanize={{@itemDisableRightSideStatusHumanize}} @dropdownButton={{@itemDropdownButton}} @dropdownButtonActions={{@itemDropdownButtonActions}} @dropdownContext={{vehicle}} @dropdownButtonIcon={{@itemDropdownButtonIcon}} @dropdownButtonIconPrefix={{@itemDropdownButtonIconPrefix}} @dropdownButtonText={{@itemDropdownButtonText}} @dropdownButtonCalculatePosition={{@itemDropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{@itemDropdownButtonRenderInPlace}} @dropdownButtonMenuLabel={{vehicle.displayName}} @dropdownButtonWrapperClass={{@itemDropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{@itemDropdownButtonTriggerClass}} @registerDropdownButtonAPI={{@itemRegisterDropdownButtonAPI}}>{{vehicle.displayName}}</Layout::Sidebar::Item>
6
+ <Layout::Sidebar::Item @icon="circle" @iconSize="2xs" @iconClass={{if vehicle.online "text-green-500" "text-yellow-200"}} @onClick={{fn this.onVehicleClicked vehicle}} @rightSideComponent={{@itemRightSideComponent}} @rightSideComponentContext={{@itemRightSideComponentContext}} @rightSideStatus={{@itemRightSideStatus}} @rightSideStatusText={{@itemRightSideStatusText}} @hideRightSideStatusDot={{@itemHideRightSideStatusDot}} @rightSideStatusClass={{@itemRightSideStatusClass}} @disableRightSideStatusHumanize={{@itemDisableRightSideStatusHumanize}} @dropdownButton={{@itemDropdownButton}} @dropdownButtonActions={{@itemDropdownButtonActions}} @dropdownContext={{vehicle}} @dropdownButtonIcon={{@itemDropdownButtonIcon}} @dropdownButtonIconPrefix={{@itemDropdownButtonIconPrefix}} @dropdownButtonText={{@itemDropdownButtonText}} @dropdownButtonCalculatePosition={{@itemDropdownButtonCalculatePosition}} @dropdownButtonMenuLabel={{vehicle.displayName}} @dropdownButtonWrapperClass={{@itemDropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{@itemDropdownButtonTriggerClass}} @registerDropdownButtonAPI={{@itemRegisterDropdownButtonAPI}} @dropdownButtonRenderInPlace={{false}}>{{vehicle.displayName}}</Layout::Sidebar::Item>
7
7
  {{/each}}
8
8
  </Layout::Sidebar::Panel>
@@ -1,5 +1,5 @@
1
1
  <Layout::Sidebar::Panel @open={{true}} @title={{@title}} @titleIcon={{@icon}} @hideCaret={{true}} @toggleOnCaretOnly={{true}} @onClickPanelTitle={{this.transitionToRoute}} @wrapperClass="next-driver-listing">
2
2
  {{#each this.drivers as |driver|}}
3
- <Layout::Sidebar::Item @icon="circle" @iconSize="2xs" @iconClass={{if driver.online "text-green-500" "text-yellow-200"}} @onClick={{fn this.onDriverClicked driver}} class="driver-nav-item" @dropdownButton={{true}} @dropdownButtonActions={{this.dropdownButtonActions}} @dropdownContext={{driver}} @dropdownButtonIcon={{@itemDropdownButtonIcon}} @dropdownButtonIconPrefix={{@itemDropdownButtonIconPrefix}} @dropdownButtonText={{@itemDropdownButtonText}} @dropdownButtonCalculatePosition={{@itemDropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{true}} @dropdownButtonMenuLabel={{driver.name}} @dropdownButtonWrapperClass={{@itemDropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{@itemDropdownButtonTriggerClass}} @registerDropdownButtonAPI={{@itemRegisterDropdownButtonAPI}} @rightSideComponent={{@itemRightSideComponent}} @rightSideComponentContext={{@itemRightSideComponentContext}} @rightSideStatus={{@itemRightSideStatus}} @rightSideStatusText={{@itemRightSideStatusText}} @hideRightSideStatusDot={{@itemHideRightSideStatusDot}} @rightSideStatusClass={{@itemRightSideStatusClass}} @disableRightSideStatusHumanize={{@itemDisableRightSideStatusHumanize}}>{{driver.name}}</Layout::Sidebar::Item>
3
+ <Layout::Sidebar::Item @icon="circle" @iconSize="2xs" @iconClass={{if driver.online "text-green-500" "text-yellow-200"}} @onClick={{fn this.onDriverClicked driver}} class="driver-nav-item" @dropdownButton={{true}} @dropdownButtonActions={{this.dropdownButtonActions}} @dropdownContext={{driver}} @dropdownButtonIcon={{@itemDropdownButtonIcon}} @dropdownButtonIconPrefix={{@itemDropdownButtonIconPrefix}} @dropdownButtonText={{@itemDropdownButtonText}} @dropdownButtonCalculatePosition={{@itemDropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{false}} @dropdownButtonMenuLabel={{driver.name}} @dropdownButtonWrapperClass={{@itemDropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{@itemDropdownButtonTriggerClass}} @dropdownHorizontalPosition="left" @registerDropdownButtonAPI={{@itemRegisterDropdownButtonAPI}} @rightSideComponent={{@itemRightSideComponent}} @rightSideComponentContext={{@itemRightSideComponentContext}} @rightSideStatus={{@itemRightSideStatus}} @rightSideStatusText={{@itemRightSideStatusText}} @hideRightSideStatusDot={{@itemHideRightSideStatusDot}} @rightSideStatusClass={{@itemRightSideStatusClass}} @disableRightSideStatusHumanize={{@itemDisableRightSideStatusHumanize}}>{{driver.name}}</Layout::Sidebar::Item>
4
4
  {{/each}}
5
5
  </Layout::Sidebar::Panel>
@@ -27,4 +27,5 @@
27
27
  </Layout::Sidebar::Panel>
28
28
  {{/each}}
29
29
  <Layout::Sidebar::Item @onClick={{this.onClickSettings}} @icon="cogs">{{t "fleet-ops.component.layout.fleet-ops-sidebar.settings"}}</Layout::Sidebar::Item>
30
- {{yield}}
30
+ {{yield}}
31
+ <Spacer @height="10px" />
@@ -393,7 +393,6 @@ export default class LiveMapComponent extends Component {
393
393
 
394
394
  // trigger that initial coordinates is set to livemap component
395
395
  this.universe.trigger('fleet-ops.live-map.has_coordinates', { latitude: this.latitude, longitude: this.longitude });
396
- return [this.latitude, this.longitude];
397
396
  }
398
397
 
399
398
  /**
@@ -7,25 +7,31 @@
7
7
  </a>
8
8
  <div class="{{@contentClass}} card-content bg-white dark:bg-gray-900 text-sm space-y-2">
9
9
  <div class="flex items-center justify-between">
10
- <div>
11
- <FaIcon @icon="calendar" class="mr-2" />
10
+ <div class="flex flex-row items-center leading-5">
11
+ <div class="w-4">
12
+ <FaIcon @icon="clock" @size="xs" />
13
+ </div>
12
14
  <span class="font-semibold">{{t "fleet-ops.component.order.schedule-card.date"}}</span>
13
15
  </div>
14
16
  <span class={{unless @order.scheduled_at "dark:text-gray-600 text-gray-400"}}>{{n-a @order.scheduledAt "Not Scheduled"}}</span>
15
17
  </div>
16
18
  <div class="flex items-center justify-between">
17
- <div>
18
- <FaIcon @icon="calendar" class="mr-2" />
19
+ <div class="flex flex-row items-center leading-5">
20
+ <div class="w-4">
21
+ <FaIcon @icon="calendar" @size="xs" />
22
+ </div>
19
23
  <span class="font-semibold">Date created</span>
20
24
  </div>
21
25
  <span>{{n-a @order.createdAtWithTime}}</span>
22
26
  </div>
23
27
  <div class="flex items-center justify-between">
24
28
  <div class="flex flex-row items-center">
25
- <FaIcon @icon="calendar" class="mr-2" />
29
+ <div class="w-4">
30
+ <FaIcon @icon="id-card-alt" @size="xs" />
31
+ </div>
26
32
  <span class="font-semibold">{{t "fleet-ops.component.order.schedule-card.driver-assigned"}}</span>
27
- <div class="ml-2">
28
- <a href="javascript:;" class="text-blue-400 hover:opacity-75" {{on "click" this.startAssignDriver}}>
33
+ <div class="ml-1">
34
+ <a href="javascript:;" class="text-blue-400 text-xs hover:opacity-75" {{on "click" this.startAssignDriver}}>
29
35
  <FaIcon @icon="edit" @size="xs" />
30
36
  </a>
31
37
  </div>
@@ -33,14 +39,9 @@
33
39
  <div>
34
40
  {{#if this.isAssigningDriver}}
35
41
  <ModelSelect @modelName="driver" @selectedModel={{@order.driver_assigned}} @placeholder={{t "fleet-ops.component.order.schedule-card.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>
42
+ <div class="flex flex-row items-center truncate uppercase">
43
+ <span class="uppercase mr-1.5">{{model.name}}</span>
44
+ <span class="uppercase">{{model.phone}}</span>
44
45
  </div>
45
46
  </ModelSelect>
46
47
  {{else}}
@@ -49,12 +50,23 @@
49
50
  </div>
50
51
  </div>
51
52
  <div class="flex items-center justify-between">
52
- <div class="flex flex-row items-center">
53
- <FaIcon @icon="calendar" class="mr-2" />
53
+ <div class="flex flex-row items-center leading-5">
54
+ <div class="w-4">
55
+ <FaIcon @icon="car" @size="xs" />
56
+ </div>
54
57
  <span class="font-semibold">{{t "fleet-ops.component.order.schedule-card.vehicle-assigned"}}</span>
55
58
  </div>
56
59
  <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 (t "fleet-ops.component.order.schedule-card.no-vehicle")}}</a>
57
60
  </div>
61
+ <div class="flex items-center justify-between">
62
+ <div class="flex flex-row items-center leading-5">
63
+ <div class="w-4">
64
+ <FaIcon @icon="location-dot" @size="xs" />
65
+ </div>
66
+ <span class="font-semibold">{{t "fleet-ops.component.order.schedule-card.destination"}}</span>
67
+ </div>
68
+ <span>{{n-a @order.pickupName}}</span>
69
+ </div>
58
70
  {{!-- <div class="z-20 relative">
59
71
  <RouteList @order={{@order}} />
60
72
  </div> --}}
@@ -79,7 +79,7 @@ export default class OrderScheduleCardComponent extends Component {
79
79
  * @memberof OrderScheduleCardComponent
80
80
  */
81
81
  @action startAssignDriver() {
82
- this.isAssigningDriver = true;
82
+ this.isAssigningDriver = !this.isAssigningDriver;
83
83
  }
84
84
 
85
85
  /**
@@ -1,61 +1,45 @@
1
- <Overlay
2
- @onLoad={{this.setOverlayContext}}
3
- @onOpen={{this.onOpen}}
4
- @onClose={{this.onClose}}
5
- @onToggle={{this.onToggle}}
6
- @position="right"
7
- @noBackdrop={{true}}
8
- @fullHeight={{true}}
9
- @isResizeble={{or this.isResizable @isResizable}}
10
- @width={{or this.width @width "570px"}}
11
- >
12
- <Overlay::Header
13
- @title={{if this.place.public_id this.place.name (t "fleet-ops.component.place-form-panel.place") }}
14
- @status={{this.place.public_id}}
15
- @hideStatusDot={{true}}
16
- @createdAt={{this.place.createdAt}}
17
- @titleWrapperClass="leading-5"
18
- >
1
+ <Overlay @onLoad={{this.setOverlayContext}} @onOpen={{this.onOpen}} @onClose={{this.onClose}} @onToggle={{this.onToggle}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizeble={{true}} @width="570px" @overlayClass="place-form-panel">
2
+ <Overlay::Header @title={{if this.place.public_id this.place.address (t "fleet-ops.component.place-form-panel.place")}} @status={{this.place.public_id}} @hideStatusDot={{true}} @titleWrapperClass="flex-col leading-5">
19
3
  <div class="flex flex-1 justify-end">
20
- <Button @icon={{if this.place.id "save" "check"}} @type="primary" @text={{if this.place.id (t "fleet-ops.component.place-form-panel.save-place")(t "fleet-ops.component.place-form-panel.create-place") }} @onClick={{this.save}} @wrapperClass="mr-2" />
4
+ <Button @icon={{if this.place.id "save" "check"}} @type="primary" @text={{if this.place.id (t "fleet-ops.component.place-form-panel.save-place") (t "fleet-ops.component.place-form-panel.create-place")}} @onClick={{this.save}} @wrapperClass="mr-2" />
21
5
  <Button @type="default" @icon="times" @helpText={{if this.place.id (t "fleet-ops.component.place-form-panel.cancel-edit-place")(t "fleet-ops.component.place-form-panel.cancel-new-place") }} @onClick={{this.onPressCancel}} />
22
6
  </div>
23
7
  </Overlay::Header>
24
8
 
25
9
  <Overlay::Body @wrapperClass="new-service-rate-overlay-body px-4 space-y-4 pt-4" @increaseInnerBodyHeightBy={{1000}}>
26
- <div class="grid grid-cols-3 gap-1 text-xs dark:text-gray-100">
27
- <InputGroup @name={{t "fleet-ops.common.name"}} @wrapperClass="col-span-2">
28
- <Input @value={{this.place.name}} @type="text" class="w-full form-input" placeholder={{t "fleet-ops.common.name"}} />
29
- </InputGroup>
30
- <InputGroup @name={{t "fleet-ops.component.place-form-panel.street-1"}} @value={{this.place.street1}} @wrapperClass="col-span-3">
31
- <AutocompleteInput @value={{this.place.street1}} @fetchUrl="places/lookup" @onSelect={{this.onAutocomplete}} placeholder={{t "fleet-ops.component.place-form-panel.street-1"}} class="w-full" as |result|>
32
- {{result.address}}
33
- </AutocompleteInput>
34
- </InputGroup>
35
- <InputGroup @name={{t "fleet-ops.component.place-form-panel.street-2"}} @autocomplete="nope" @value={{this.place.street2}} @wrapperClass="col-span-3" />
36
- <InputGroup @name={{t "fleet-ops.component.place-form-panel.neighborhood"}} @autocomplete="nope" @value={{this.place.neighborhood}} />
37
- <InputGroup @name={{t "fleet-ops.component.place-form-panel.building"}} @autocomplete="nope" @value={{this.place.building}} />
38
- <InputGroup @name={{t "fleet-ops.component.place-form-panel.security-code"}} @autocomplete="nope" @value={{this.place.security_access_code}} />
39
- <InputGroup @name={{t "fleet-ops.component.place-form-panel.postal-code"}} @autocomplete="nope" @value={{this.place.postal_code}} />
40
- <InputGroup @name={{t "fleet-ops.common.city"}} @autocomplete="nope" @value={{this.place.city}} />
41
- <InputGroup @name={{t "fleet-ops.component.place-form-panel.state"}} @autocomplete="nope" @value={{this.place.province}} />
42
- <InputGroup @name={{t "fleet-ops.common.country"}} @wrapperClass="col-span-2">
43
- <CountrySelect class="w-full form-input form-select form-datalist" @value={{this.place.country}} @onChange={{fn (mut this.place.country)}} placeholder={{t "fleet-ops.common.country"}} />
44
- </InputGroup>
45
- <InputGroup @name={{t "fleet-ops.common.coordinates"}} @wrapperClass="col-span-2">
46
- <CoordinatesInput
47
- @value={{this.place.location}}
48
- @onChange={{this.updatePlaceCoordinates}}
49
- @onGeocode={{this.onAutocomplete}}
50
- @onUpdatedFromMap={{this.onReverseGeocode}}
51
- @onInit={{this.setCoordinatesInput}}
52
- />
53
- </InputGroup>
54
- <div class="col-span-1"></div>
55
- <InputGroup @name={{t "fleet-ops.common.phone"}}>
56
- <PhoneInput @value={{this.place.phone}} @autocomplete="nope" @onInput={{this.phone}} class="form-input w-full" />
57
- </InputGroup>
10
+ <div class="flex-1 space-y-4">
11
+ <div class="grid grid-cols-3 gap-1 text-xs dark:text-gray-100">
12
+ <InputGroup @name={{t "fleet-ops.common.name"}} @wrapperClass="col-span-2">
13
+ <Input @value={{this.place.name}} @type="text" class="w-full form-input" placeholder={{t "fleet-ops.common.name"}} />
14
+ </InputGroup>
15
+ <InputGroup @name={{t "fleet-ops.component.place-form-panel.street-1"}} @value={{this.place.street1}} @wrapperClass="col-span-3">
16
+ <AutocompleteInput @value={{this.place.street1}} @fetchUrl="places/lookup" @onSelect={{this.onAutocomplete}} placeholder={{t "fleet-ops.component.place-form-panel.street-1"}} class="w-full" as |result|>
17
+ {{result.address}}
18
+ </AutocompleteInput>
19
+ </InputGroup>
20
+ <InputGroup @name={{t "fleet-ops.component.place-form-panel.street-2"}} @autocomplete="nope" @value={{this.place.street2}} @wrapperClass="col-span-3" />
21
+ <InputGroup @name={{t "fleet-ops.component.place-form-panel.neighborhood"}} @autocomplete="nope" @value={{this.place.neighborhood}} />
22
+ <InputGroup @name={{t "fleet-ops.component.place-form-panel.building"}} @autocomplete="nope" @value={{this.place.building}} />
23
+ <InputGroup @name={{t "fleet-ops.component.place-form-panel.security-code"}} @autocomplete="nope" @value={{this.place.security_access_code}} />
24
+ <InputGroup @name={{t "fleet-ops.component.place-form-panel.postal-code"}} @autocomplete="nope" @value={{this.place.postal_code}} />
25
+ <InputGroup @name={{t "fleet-ops.common.city"}} @autocomplete="nope" @value={{this.place.city}} />
26
+ <InputGroup @name={{t "fleet-ops.component.place-form-panel.state"}} @autocomplete="nope" @value={{this.place.province}} />
27
+ <InputGroup @name={{t "fleet-ops.common.country"}} @wrapperClass="col-span-2">
28
+ <CountrySelect class="w-full form-input form-select form-datalist" @value={{this.place.country}} @onChange={{fn (mut this.place.country)}} placeholder={{t "fleet-ops.common.country"}} />
29
+ </InputGroup>
30
+ <InputGroup @name={{t "fleet-ops.common.coordinates"}} @wrapperClass="col-span-2">
31
+ <CoordinatesInput @value={{this.place.location}} @onChange={{this.updatePlaceCoordinates}} @onGeocode={{this.onAutocomplete}} @onUpdatedFromMap={{this.onReverseGeocode}} @onInit={{this.setCoordinatesInput}} />
32
+ </InputGroup>
33
+ <div class="col-span-1"></div>
34
+ <InputGroup @name={{t "fleet-ops.common.phone"}}>
35
+ <PhoneInput @value={{this.place.phone}} @autocomplete="nope" @onInput={{this.phone}} class="form-input w-full" />
36
+ </InputGroup>
37
+ </div>
38
+ <ContentPanel @title={{t "fleet-ops.component.avatar-picker.avatar"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
39
+ <AvatarPicker @model={{this.place}} @defaultAvatar={{config "defaultValues.placeAvatar"}} />
40
+ </ContentPanel>
58
41
  </div>
42
+
59
43
  <Spacer @height="300px" />
60
44
  </Overlay::Body>
61
45
  </Overlay>
@@ -1,5 +1,5 @@
1
1
  <div class="p-4 space-y-4">
2
- <ContentPanel @title="Map" @open={{false}}>
2
+ <ContentPanel @title="Map" @open={{true}}>
3
3
  <LeafletMap class="w-full h-48 rounded-b-md shadow-md" @lat={{@place.latitude}} @lng={{@place.longitude}} @zoom={{17}} @zoomControl={{false}} as |layers|>
4
4
  <layers.tile @url="https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png" />
5
5
  <layers.marker
@@ -23,58 +23,54 @@
23
23
  <div class="grid grid-cols-1 lg:grid-cols-3 gap-2 text-xs dark:text-gray-100">
24
24
  <div class="field-info-container col-span-3">
25
25
  <div class="field-name">{{t "fleet-ops.common.name"}}</div>
26
- <div class="field-value">{{n-a @place.name}}</div>
26
+ <div class="field-value uppercase">{{n-a @place.name}}</div>
27
27
  </div>
28
28
 
29
29
  <div class="field-info-container col-span-3">
30
30
  <div class="field-name">{{t "fleet-ops.common.street"}}</div>
31
- <div class="field-value">{{n-a @place.street1}}</div>
31
+ <div class="field-value uppercase">{{n-a @place.street1}}</div>
32
32
  </div>
33
33
 
34
34
  <div class="field-info-container">
35
35
  <div class="field-name">{{t "fleet-ops.common.neighborhood"}}</div>
36
- <div class="field-value">{{n-a @place.neighborhood}}</div>
36
+ <div class="field-value uppercase">{{n-a @place.neighborhood}}</div>
37
37
  </div>
38
38
 
39
39
  <div class="field-info-container">
40
40
  <div class="field-name">{{t "fleet-ops.common.building"}}</div>
41
- <div class="field-value">{{n-a @place.building}}</div>
41
+ <div class="field-value uppercase">{{n-a @place.building}}</div>
42
42
  </div>
43
43
 
44
44
  <div class="field-info-container">
45
45
  <div class="field-name">{{t "fleet-ops.common.security-access-code"}}</div>
46
- <div class="field-value">{{n-a @place.security_access_code}}</div>
46
+ <div class="field-value uppercase">{{n-a @place.security_access_code}}</div>
47
47
  </div>
48
48
 
49
49
  <div class="field-info-container">
50
50
  <div class="field-name">{{t "fleet-ops.common.city"}}</div>
51
- <div class="field-value">{{n-a @place.city}}</div>
51
+ <div class="field-value uppercase">{{n-a @place.city}}</div>
52
52
  </div>
53
53
 
54
54
  <div class="field-info-container">
55
55
  <div class="field-name">{{t "fleet-ops.common.state"}}</div>
56
- <div class="field-value">{{n-a @place.province}}</div>
56
+ <div class="field-value uppercase">{{n-a @place.province}}</div>
57
57
  </div>
58
58
 
59
59
  <div class="field-info-container">
60
60
  <div class="field-name">{{t "fleet-ops.common.country"}}</div>
61
- <div class="field-value">
61
+ <div class="field-value uppercase">
62
62
  <CountryName @country={{@place.country}} @showFlag={{true}} />
63
63
  </div>
64
64
  </div>
65
65
 
66
66
  <div class="field-info-container">
67
67
  <div class="field-name">{{t "fleet-ops.common.phone"}}</div>
68
- <div class="field-value">{{n-a @place.phone}}</div>
68
+ <div class="field-value uppercase">{{n-a @place.phone}}</div>
69
69
  </div>
70
70
 
71
71
  <div class="field-info-container col-span-3">
72
72
  <div class="field-name">
73
73
  {{t "fleet-ops.common.coordinates"}}
74
- {{!-- <a href="javascript:;" class="block ml-3" {{on "click" @place.viewPlaceOnMap}}>
75
- <FaIcon @icon="map" class="mr-1" />
76
- View on map
77
- </a> --}}
78
74
  </div>
79
75
  <div class="field-value">
80
76
  {{point-coordinates @place.location}}
@@ -1,15 +1,5 @@
1
- <Overlay
2
- @onLoad={{this.setOverlayContext}}
3
- @onOpen={{this.onOpen}}
4
- @onClose={{this.onClose}}
5
- @onToggle={{this.onToggle}}
6
- @position="right"
7
- @noBackdrop={{true}}
8
- @fullHeight={{true}}
9
- @isResizable={{or this.isResizable @isResizable}}
10
- @width={{or this.width @width "570px"}}
11
- >
12
- <Overlay::Header @title={{this.place.name}} @status={{this.place.public_id}} @hideStatusDot={{true}} @createdAt={{this.place.createdAt}}>
1
+ <Overlay @onLoad={{this.setOverlayContext}} @onOpen={{this.onOpen}} @onClose={{this.onClose}} @onToggle={{this.onToggle}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizable={{true}} @width="570px" @overlayClass="place-panel">
2
+ <Overlay::Header @title={{this.place.address}} @status={{this.place.public_id}} @hideStatusDot={{true}}>
13
3
  <Button @type="default" @icon="pen" @helpText={{t "fleet-ops.component.place-panel.edit-place"}} @onClick={{this.onEdit}} @wrapperClass="mr-2" />
14
4
  <Button @type="default" @icon="times" @helpText={{if this.place.id (t "fleet-ops.component.place-panel.cancel-edit-place")(t "fleet-ops.component.place-panel.cancel-new-place") }} @onClick={{this.onPressCancel}} />
15
5
  </Overlay::Header>
@@ -1,14 +1,4 @@
1
- <Overlay
2
- @onLoad={{this.setOverlayContext}}
3
- @onOpen={{this.onOpen}}
4
- @onClose={{this.onClose}}
5
- @onToggle={{this.onToggle}}
6
- @position="right"
7
- @noBackdrop={{true}}
8
- @fullHeight={{true}}
9
- @isResizeble={{or this.isResizable @isResizable}}
10
- @width={{or this.width @width "570px"}}
11
- >
1
+ <Overlay @onLoad={{this.setOverlayContext}} @onOpen={{this.onOpen}} @onClose={{this.onClose}} @onToggle={{this.onToggle}} @position="right" @noBackdrop={{true}} @fullHeight={{true}} @isResizeble={{or this.isResizable @isResizable}} @width={{or this.width @width "570px"}}>
12
2
  <Overlay::Header @hideLeftSection={{true}} @actionsWrapperClass="flex-1 flex-col py-3" class="h-auto-i min-h-[127px]">
13
3
  <div class="flex flex-row items-center justify-between w-full mb-4">
14
4
  <div class="flex flex-1 space-x-2">
@@ -18,21 +8,9 @@
18
8
  </div>
19
9
  <div class="flex flex-1 justify-end">
20
10
  <div class="mr-2">
21
- <Button
22
- @icon={{if this.vehicle.id "save" "check"}}
23
- @type="primary"
24
- @text={{if this.vehicle.id (t "fleet-ops.component.vehicle-form-panel.save-vehicle")(t "fleet-ops.component.vehicle-form-panel.create-vehicle") }}
25
- @onClick={{this.save}}
26
- @isLoading={{this.isLoading}}
27
- />
11
+ <Button @icon={{if this.vehicle.id "save" "check"}} @type="primary" @text={{if this.vehicle.id (t "fleet-ops.component.vehicle-form-panel.save-vehicle") (t "fleet-ops.component.vehicle-form-panel.create-vehicle")}} @onClick={{this.save}} @isLoading={{this.isLoading}} />
28
12
  </div>
29
- <Button
30
- @type="default"
31
- @icon="times"
32
- @helpText={{if this.vehicle.id (t "fleet-ops.component.vehicle-form-panel.cancel-edit-vehicle")(t "fleet-ops.component.vehicle-form-panel.cancel-new-vehicle") }}
33
- @onClick={{this.onPressCancel}}
34
- @disabled={{this.isLoading}}
35
- />
13
+ <Button @type="default" @icon="times" @helpText={{if this.vehicle.id (t "fleet-ops.component.vehicle-form-panel.cancel-edit-vehicle") (t "fleet-ops.component.vehicle-form-panel.cancel-new-vehicle")}} @onClick={{this.onPressCancel}} @disabled={{this.isLoading}} />
36
14
  </div>
37
15
  </div>
38
16
  <div class="flex flex-row justify-between w-full">
@@ -45,15 +23,7 @@
45
23
  <InputInfo @text={{t "fleet-ops.component.vehicle-form-panel.upload-photo"}} />
46
24
  </Attach::Tooltip>
47
25
  <div class="upload-avatar-button-wrapper rounded-lg">
48
- <UploadButton
49
- @name={{t "fleet-ops.common.photos"}}
50
- @accept="image/*"
51
- @onFileAdded={{this.onUploadNewPhoto}}
52
- @icon="upload"
53
- @hideButtonText={{true}}
54
- @labelClass="upload-avatar-label-overlay"
55
- class="w-12 btn-reset"
56
- />
26
+ <UploadButton @name={{t "fleet-ops.common.photos"}} @accept="image/*" @onFileAdded={{this.onUploadNewPhoto}} @icon="upload" @hideButtonText={{true}} @labelClass="upload-avatar-label-overlay" class="w-12 btn-reset" />
57
27
  </div>
58
28
  </div>
59
29
  </div>
@@ -118,68 +88,29 @@
118
88
  </InputGroup>
119
89
 
120
90
  <InputGroup @name={{t "fleet-ops.component.vehicle-form-panel.driver-assigned"}}>
121
- <ModelSelect
122
- @modelName="driver"
123
- @selectedModel={{this.vehicle.driver}}
124
- @placeholder={{t "fleet-ops.component.vehicle-form-panel.select-driver"}}
125
- @triggerClass="form-select form-input"
126
- @infiniteScroll={{false}}
127
- @renderInPlace={{true}}
128
- @onChange={{fn (mut this.vehicle.driver)}}
129
- as |model|
130
- >
91
+ <ModelSelect @modelName="driver" @selectedModel={{this.vehicle.driver}} @placeholder={{t "fleet-ops.component.vehicle-form-panel.select-driver"}} @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{fn (mut this.vehicle.driver)}} as |model|>
131
92
  {{model.name}}
132
93
  </ModelSelect>
133
94
  </InputGroup>
134
95
 
135
96
  <InputGroup @name={{t "fleet-ops.common.status"}}>
136
97
  <div class="fleetbase-model-select fleetbase-power-select ember-model-select">
137
- <PowerSelect
138
- @options={{this.vehicleStatusOptions}}
139
- @selected={{this.vehicle.status}}
140
- @onChange={{fn (mut this.vehicle.status)}}
141
- @placeholder={{t "fleet-ops.component.vehicle-form-panel.select-vehicle"}}
142
- @triggerClass="form-select form-input"
143
- as |status|
144
- >
98
+ <PowerSelect @options={{this.vehicleStatusOptions}} @selected={{this.vehicle.status}} @onChange={{fn (mut this.vehicle.status)}} @placeholder={{t "fleet-ops.component.vehicle-form-panel.select-vehicle"}} @triggerClass="form-select form-input" as |status|>
145
99
  {{smart-humanize status}}
146
100
  </PowerSelect>
147
101
  </div>
148
102
  </InputGroup>
149
103
  <InputGroup @name={{t "fleet-ops.common.coordinates"}} @wrapperClass="col-span-2">
150
- <CoordinatesInput
151
- @value={{this.vehicle.location}}
152
- @onChange={{this.onCoordinatesChanged}}
153
- @onGeocode={{this.onAutocomplete}}
154
- @onUpdatedFromMap={{this.onCoordinatesChanged}}
155
- @onInit={{this.setCoordinatesInput}}
156
- />
157
- </InputGroup>
104
+ <CoordinatesInput @value={{this.vehicle.location}} @onChange={{this.onCoordinatesChanged}} @onGeocode={{this.onAutocomplete}} @onUpdatedFromMap={{this.onCoordinatesChanged}} @onInit={{this.setCoordinatesInput}} />
105
+ </InputGroup>
158
106
  </div>
159
107
  </ContentPanel>
160
108
 
161
- <ContentPanel @title={{t "fleet-ops.component.vehicle-form-panel.avatar"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
162
- <div class="grid grid-cols-1 gap-4 lg:grid-cols-2 lg:gap-2">
163
- <div class="input-group mb-2">
164
- <InputLabel @labelText={{t "fleet-ops.component.vehicle-form-panel.select-map-avatar"}} @helpText={{t "fleet-ops.component.vehicle-form-panel.select-avatar-rendering"}} />
165
- <FetchSelect
166
- @wrapperClass="w-60"
167
- @placeholder={{t "fleet-ops.component.vehicle-form-panel.select-avatar"}}
168
- @endpoint="vehicles/avatars"
169
- @selected={{this.vehicle.avatar_url}}
170
- @optionValue="value"
171
- @onChange={{fn (mut this.vehicle.avatar_url)}}
172
- as |option|
173
- >
174
- {{titleize (humanize option.key)}}
175
- </FetchSelect>
176
- </div>
177
- <div>
178
- <img alt={{this.vehicle.displayName}} src={{this.vehicle.avatar_url}} class="w-24 h-24" />
179
- </div>
180
- </div>
109
+ <ContentPanel @title={{t "fleet-ops.component.avatar-picker.avatar"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
110
+ <AvatarPicker @model={{this.vehicle}} @defaultAvatar={{config "defaultValues.vehicleAvatar"}} />
181
111
  </ContentPanel>
182
112
  </div>
113
+
183
114
  <Spacer @height="300px" />
184
115
  </Overlay::Body>
185
116
  </Overlay>