@fleetbase/fleetops-engine 0.3.3 → 0.3.5

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 (154) hide show
  1. package/addon/components/contact-form-panel.hbs +28 -6
  2. package/addon/components/driver-form-panel.hbs +10 -0
  3. package/addon/components/driver-form-panel.js +51 -0
  4. package/addon/components/driver-panel/details.hbs +1 -5
  5. package/addon/components/driver-panel.hbs +21 -3
  6. package/addon/components/fleet-form-panel.hbs +60 -6
  7. package/addon/components/fleet-listing-panel.hbs +2 -2
  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/fleet-listing.hbs +1 -0
  15. package/addon/components/layout/fleet-ops-sidebar/fleet-listing.js +3 -0
  16. package/addon/components/layout/fleet-ops-sidebar.hbs +4 -4
  17. package/addon/components/layout/fleet-ops-sidebar.js +10 -0
  18. package/addon/components/live-map-drawer.hbs +1 -1
  19. package/addon/components/live-map.hbs +1 -1
  20. package/addon/components/modals/driver-assign-vehicle.hbs +2 -11
  21. package/addon/components/modals/driver-assign-vendor.hbs +1 -9
  22. package/addon/components/modals/fuel-report-details.hbs +4 -0
  23. package/addon/components/order/schedule-card.hbs +32 -4
  24. package/addon/components/order/schedule-card.js +155 -5
  25. package/addon/components/place-form-panel.hbs +14 -7
  26. package/addon/components/place-form-panel.js +71 -0
  27. package/addon/components/place-panel/details.hbs +9 -19
  28. package/addon/components/vehicle-form-panel.hbs +67 -7
  29. package/addon/components/vehicle-form-panel.js +37 -0
  30. package/addon/components/vehicle-panel/details.hbs +9 -5
  31. package/addon/components/vehicle-panel.hbs +18 -4
  32. package/addon/components/vendor-form-panel/create-form.hbs +72 -11
  33. package/addon/components/vendor-form-panel/edit-form.hbs +1 -1
  34. package/addon/components/vendor-form-panel.hbs +70 -30
  35. package/addon/components/vendor-form-panel.js +4 -40
  36. package/addon/components/vendor-panel/details.hbs +2 -2
  37. package/addon/components/vendor-panel.hbs +16 -2
  38. package/addon/controllers/management/contacts/index.js +49 -3
  39. package/addon/controllers/management/drivers/index.js +7 -0
  40. package/addon/controllers/management/fleets/index.js +19 -23
  41. package/addon/controllers/management/fuel-reports/index/new.js +1 -1
  42. package/addon/controllers/management/fuel-reports/index.js +80 -20
  43. package/addon/controllers/management/issues/index/new.js +2 -2
  44. package/addon/controllers/management/issues/index.js +72 -45
  45. package/addon/controllers/management/places/index.js +65 -18
  46. package/addon/controllers/management/vehicles/index.js +56 -4
  47. package/addon/controllers/management/vendors/index.js +70 -8
  48. package/addon/controllers/operations/orders/index.js +42 -1
  49. package/addon/controllers/operations/service-rates/index.js +7 -0
  50. package/addon/routes/management/contacts/index.js +8 -0
  51. package/addon/routes/management/fleets/index.js +8 -2
  52. package/addon/routes/management/fuel-reports/index.js +6 -0
  53. package/addon/routes/management/issues/index.js +9 -1
  54. package/addon/routes/management/places/index.js +11 -1
  55. package/addon/routes/management/vehicles/index.js +1 -1
  56. package/addon/routes/management/vendors/index.js +8 -0
  57. package/addon/routes/operations/scheduler/index.js +1 -1
  58. package/addon/templates/management/contacts/index.hbs +1 -0
  59. package/addon/templates/management/drivers/index.hbs +2 -1
  60. package/addon/templates/management/fleets/index.hbs +23 -3
  61. package/addon/templates/management/fuel-reports/index.hbs +1 -0
  62. package/addon/templates/management/issues/index.hbs +22 -2
  63. package/addon/templates/management/places/index.hbs +9 -1
  64. package/addon/templates/management/vehicles/index.hbs +22 -2
  65. package/addon/templates/management/vendors/index.hbs +22 -2
  66. package/addon/templates/operations/orders/index.hbs +1 -1
  67. package/addon/templates/operations/service-rates/index.hbs +11 -3
  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/layout/fleet-ops-sidebar/fleet-listing.js +1 -0
  73. package/app/utils/get-issue-categories.js +1 -0
  74. package/app/utils/get-issue-types.js +1 -0
  75. package/app/utils/get-vendor-categories.js +1 -0
  76. package/app/utils/get-vendor-status-options.js +1 -0
  77. package/app/utils/get-vendor-type-options.js +1 -0
  78. package/app/utils/get-vendor-types.js +1 -0
  79. package/composer.json +1 -1
  80. package/extension.json +1 -1
  81. package/package.json +4 -4
  82. package/server/migrations/2023_04_27_053456_create_contacts_table.php +2 -2
  83. package/server/migrations/2023_04_27_053456_create_drivers_table.php +5 -5
  84. package/server/migrations/2023_04_27_053456_create_entities_table.php +5 -5
  85. package/server/migrations/2023_04_27_053456_create_fleet_drivers_table.php +2 -2
  86. package/server/migrations/2023_04_27_053456_create_fleets_table.php +3 -3
  87. package/server/migrations/2023_04_27_053456_create_fuel_reports_table.php +3 -3
  88. package/server/migrations/2023_04_27_053456_create_issues_table.php +4 -4
  89. package/server/migrations/2023_04_27_053456_create_orders_table.php +8 -8
  90. package/server/migrations/2023_04_27_053456_create_payloads_table.php +5 -5
  91. package/server/migrations/2023_04_27_053456_create_places_table.php +1 -1
  92. package/server/migrations/2023_04_27_053456_create_purchase_rates_table.php +4 -4
  93. package/server/migrations/2023_04_27_053456_create_service_areas_table.php +2 -2
  94. package/server/migrations/2023_04_27_053456_create_service_quote_items_table.php +1 -1
  95. package/server/migrations/2023_04_27_053456_create_service_quotes_table.php +3 -3
  96. package/server/migrations/2023_04_27_053456_create_service_rate_fees_table.php +1 -1
  97. package/server/migrations/2023_04_27_053456_create_service_rate_parcel_fees_table.php +1 -1
  98. package/server/migrations/2023_04_27_053456_create_service_rates_table.php +3 -3
  99. package/server/migrations/2023_04_27_053456_create_tracking_numbers_table.php +3 -3
  100. package/server/migrations/2023_04_27_053456_create_tracking_statuses_table.php +2 -2
  101. package/server/migrations/2023_04_27_053456_create_vehicles_table.php +3 -3
  102. package/server/migrations/2023_04_27_053456_create_vendors_table.php +5 -5
  103. package/server/migrations/2023_04_27_053456_create_waypoints_table.php +4 -4
  104. package/server/migrations/2023_04_27_053456_create_zones_table.php +2 -2
  105. package/server/migrations/2023_11_09_041807_add_status_column_to_fuel_reports_table.php +32 -0
  106. package/server/migrations/2023_11_15_062814_add_comments_column_and_resolved_at_column_to_vehicle_device_events_table.php +33 -0
  107. package/server/migrations/2023_11_17_053001_add_category_uuid_to_entities_table.php +33 -0
  108. package/server/src/Http/Controllers/Api/v1/DriverController.php +2 -2
  109. package/server/src/Http/Controllers/Api/v1/EntityController.php +2 -0
  110. package/server/src/Http/Controllers/Api/v1/VehicleController.php +2 -2
  111. package/server/src/Http/Controllers/Internal/v1/DriverController.php +5 -14
  112. package/server/src/Http/Controllers/Internal/v1/OrderController.php +1 -3
  113. package/server/src/Http/Filter/ContactFilter.php +10 -0
  114. package/server/src/Http/Filter/FleetFilter.php +8 -6
  115. package/server/src/Http/Filter/FuelReportFilter.php +51 -0
  116. package/server/src/Http/Filter/IssueFilter.php +61 -5
  117. package/server/src/Http/Filter/PlaceFilter.php +48 -6
  118. package/server/src/Http/Filter/VehicleFilter.php +21 -6
  119. package/server/src/Http/Filter/VendorFilter.php +11 -8
  120. package/server/src/Http/Middleware/TransformLocationMiddleware.php +1 -1
  121. package/server/src/Http/Resources/Internal/v1/IntegratedVendorFacilitator.php +17 -18
  122. package/server/src/Http/Resources/v1/Contact.php +16 -19
  123. package/server/src/Http/Resources/v1/CurrentJob.php +13 -16
  124. package/server/src/Http/Resources/v1/Driver.php +59 -57
  125. package/server/src/Http/Resources/v1/Entity.php +30 -33
  126. package/server/src/Http/Resources/v1/Fleet.php +19 -17
  127. package/server/src/Http/Resources/v1/FuelReport.php +16 -14
  128. package/server/src/Http/Resources/v1/Order.php +1 -1
  129. package/server/src/Http/Resources/v1/Payload.php +21 -24
  130. package/server/src/Http/Resources/v1/Place.php +27 -30
  131. package/server/src/Http/Resources/v1/Proof.php +13 -16
  132. package/server/src/Http/Resources/v1/PurchaseRate.php +14 -17
  133. package/server/src/Http/Resources/v1/ServiceArea.php +13 -16
  134. package/server/src/Http/Resources/v1/ServiceQuote.php +15 -18
  135. package/server/src/Http/Resources/v1/ServiceRate.php +33 -36
  136. package/server/src/Http/Resources/v1/ServiceRateFee.php +14 -17
  137. package/server/src/Http/Resources/v1/ServiceRateParcelFee.php +9 -12
  138. package/server/src/Http/Resources/v1/TrackingNumber.php +18 -21
  139. package/server/src/Http/Resources/v1/TrackingStatus.php +18 -21
  140. package/server/src/Http/Resources/v1/Vehicle.php +31 -34
  141. package/server/src/Http/Resources/v1/VehicleDevice.php +23 -25
  142. package/server/src/Http/Resources/v1/VehicleWithoutDriver.php +38 -32
  143. package/server/src/Http/Resources/v1/Vendor.php +31 -26
  144. package/server/src/Http/Resources/v1/Zone.php +14 -17
  145. package/server/src/Models/Driver.php +23 -1
  146. package/server/src/Models/Entity.php +18 -23
  147. package/server/src/Models/FuelReport.php +1 -0
  148. package/server/src/Models/IntegratedVendor.php +6 -1
  149. package/server/src/Models/Order.php +2 -2
  150. package/server/src/Models/Place.php +2 -2
  151. package/server/src/Models/Vehicle.php +4 -2
  152. package/server/src/Models/VehicleDeviceEvent.php +1 -0
  153. package/server/src/Models/Vendor.php +1 -1
  154. package/server/src/Observers/DriverObserver.php +15 -0
@@ -6,6 +6,8 @@ import { isArray } from '@ember/array';
6
6
  import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
7
7
  import contextComponentCallback from '../utils/context-component-callback';
8
8
  import applyContextComponentArguments from '../utils/apply-context-component-arguments';
9
+ import getIssueTypes from '../utils/get-issue-types';
10
+ import getIssueCategories from '../utils/get-issue-categories';
9
11
 
10
12
  export default class IssueFormPanelComponent extends Component {
11
13
  /**
@@ -55,24 +57,14 @@ export default class IssueFormPanelComponent extends Component {
55
57
  *
56
58
  * @var {String}
57
59
  */
58
- @tracked issueTypes = ['vehicle', 'driver', 'route', 'payload-cargo', 'software-technical', 'operational', 'customer', 'security', 'environmental-sustainability'];
60
+ @tracked issueTypes = getIssueTypes();
59
61
 
60
62
  /**
61
63
  * The subcategories for issue types.
62
64
  *
63
65
  * @var {Object}
64
66
  */
65
- @tracked issueCategoriesByType = {
66
- vehicle: ['Mechanical Problems', 'Cosmetic Damages', 'Tire Issues', 'Electronics and Instruments', 'Maintenance Alerts', 'Fuel Efficiency Issues'],
67
- driver: ['Behavior Concerns', 'Documentation', 'Time Management', 'Communication', 'Training Needs', 'Health and Safety Violations'],
68
- route: ['Inefficient Routes', 'Safety Concerns', 'Blocked Routes', 'Environmental Considerations', 'Unfavorable Weather Conditions'],
69
- 'payload-cargo': ['Damaged Goods', 'Misplaced Goods', 'Documentation Issues', 'Temperature-Sensitive Goods', 'Incorrect Cargo Loading'],
70
- 'software-technical': ['Bugs', 'UI/UX Concerns', 'Integration Failures', 'Performance', 'Feature Requests', 'Security Vulnerabilities'],
71
- operational: ['Compliance', 'Resource Allocation', 'Cost Overruns', 'Communication', 'Vendor Management Issues'],
72
- customer: ['Service Quality', 'Billing Discrepancies', 'Communication Breakdown', 'Feedback and Suggestions', 'Order Errors'],
73
- security: ['Unauthorized Access', 'Data Concerns', 'Physical Security', 'Data Integrity Issues'],
74
- 'environmental-sustainability': ['Fuel Consumption', 'Carbon Footprint', 'Waste Management', 'Green Initiatives Opportunities'],
75
- };
67
+ @tracked issueCategoriesByType = getIssueCategories({ fullObject: true });
76
68
 
77
69
  /**
78
70
  * Selectable issue categories.
@@ -101,7 +93,7 @@ export default class IssueFormPanelComponent extends Component {
101
93
  constructor() {
102
94
  super(...arguments);
103
95
  this.issue = this.args.issue;
104
- this.issueCategories = getWithDefault(this.issueCategoriesByType, this.issue.type, []);
96
+ this.issueCategories = getWithDefault(this.issueCategoriesByType, getWithDefault(this.issue, 'type', 'operational'), []);
105
97
  applyContextComponentArguments(this);
106
98
  }
107
99
 
@@ -0,0 +1 @@
1
+ <FleetListingPanel ...attributes />
@@ -0,0 +1,3 @@
1
+ import Component from '@glimmer/component';
2
+
3
+ export default class LayoutFleetOpsSidebarFleetListingComponent extends Component {}
@@ -5,20 +5,20 @@
5
5
  {{#if menuItem.renderComponentInPlace}}
6
6
  {{component menuItem.component}}
7
7
  {{else}}
8
- <Layout::Sidebar::Item @onClick={{fn this.universe.transitionMenuItem (concat this.routePrefix "virtual") menuItem}} @item={{menuItem}} @icon={{menuItem.icon}}>{{menuItem.title}}</Layout::Sidebar::Item>
8
+ <Layout::Sidebar::Item @onClick={{fn this.universe.transitionMenuItem (concat this.routePrefix "virtual") menuItem}} @menuItem={{menuItem}} @icon={{menuItem.icon}} @rightSideComponent={{menuItem.rightSideComponent}} @rightSideComponentContext={{menuItem.rightSideComponentContext}} @rightSideStatus={{menuItem.rightSideStatus}} @rightSideStatusText={{menuItem.rightSideStatusText}} @hideRightSideStatusDot={{menuItem.hideRightSideStatusDot}} @rightSideStatusClass={{menuItem.rightSideStatusClass}} @disableRightSideStatusHumanize={{menuItem.disableRightSideStatusHumanize}} @dropdownButton={{menuItem.dropdownButton}} @dropdownButtonActions={{menuItem.dropdownButtonActions}} @dropdownButtonIcon={{menuItem.dropdownButtonIcon}} @dropdownButtonIconPrefix={{menuItem.dropdownButtonIconPrefix}} @dropdownButtonText={{menuItem.dropdownButtonText}} @dropdownButtonCalculatePosition={{menuItem.dropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{menuItem.dropdownButtonRenderInPlace}} @dropdownButtonMenuLabel={{menuItem.dropdownButtonMenuLabel}} @dropdownButtonWrapperClass={{menuItem.dropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{menuItem.dropdownButtonTriggerClass}} @registerDropdownButtonAPI={{menuItem.registerDropdownButtonAPI}}>{{menuItem.title}}</Layout::Sidebar::Item>
9
9
  {{/if}}
10
10
  {{/each}}
11
11
  {{#each this.menuPanels as |menuPanel|}}
12
12
  <Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}}>
13
- {{#each menuPanel.items as |item|}}
14
- <Layout::Sidebar::Item @route={{concat this.routePrefix item.route}} @icon={{item.icon}}>{{item.title}}</Layout::Sidebar::Item>
13
+ {{#each menuPanel.items as |menuItem|}}
14
+ <Layout::Sidebar::Item @route={{concat this.routePrefix menuItem.route}} @icon={{menuItem.icon}} @rightSideComponent={{menuItem.rightSideComponent}} @rightSideComponentContext={{menuItem.rightSideComponentContext}} @rightSideStatus={{menuItem.rightSideStatus}} @rightSideStatusText={{menuItem.rightSideStatusText}} @hideRightSideStatusDot={{menuItem.hideRightSideStatusDot}} @rightSideStatusClass={{menuItem.rightSideStatusClass}} @disableRightSideStatusHumanize={{menuItem.disableRightSideStatusHumanize}} @dropdownButton={{menuItem.dropdownButton}} @dropdownButtonActions={{menuItem.dropdownButtonActions}} @dropdownButtonIcon={{menuItem.dropdownButtonIcon}} @dropdownButtonIconPrefix={{menuItem.dropdownButtonIconPrefix}} @dropdownButtonText={{menuItem.dropdownButtonText}} @dropdownButtonCalculatePosition={{menuItem.dropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{menuItem.dropdownButtonRenderInPlace}} @dropdownButtonMenuLabel={{menuItem.dropdownButtonMenuLabel}} @dropdownButtonWrapperClass={{menuItem.dropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{menuItem.dropdownButtonTriggerClass}} @registerDropdownButtonAPI={{menuItem.registerDropdownButtonAPI}}>{{menuItem.title}}</Layout::Sidebar::Item>
15
15
  {{/each}}
16
16
  </Layout::Sidebar::Panel>
17
17
  {{/each}}
18
18
  {{#each this.universeMenuPanels as |menuPanel|}}
19
19
  <Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}}>
20
20
  {{#each menuPanel.items as |menuItem|}}
21
- <Layout::Sidebar::Item @onClick={{fn this.universe.transitionMenuItem (concat this.routePrefix "virtual") menuItem}} @item={{menuItem}} @icon={{menuItem.icon}}>{{menuItem.title}}</Layout::Sidebar::Item>
21
+ <Layout::Sidebar::Item @onClick={{fn this.universe.transitionMenuItem (concat this.routePrefix "virtual") menuItem}} @menuItem={{menuItem}} @icon={{menuItem.icon}} @rightSideComponent={{menuItem.rightSideComponent}} @rightSideComponentContext={{menuItem.rightSideComponentContext}} @rightSideStatus={{menuItem.rightSideStatus}} @rightSideStatusText={{menuItem.rightSideStatusText}} @hideRightSideStatusDot={{menuItem.hideRightSideStatusDot}} @rightSideStatusClass={{menuItem.rightSideStatusClass}} @disableRightSideStatusHumanize={{menuItem.disableRightSideStatusHumanize}} @dropdownButton={{menuItem.dropdownButton}} @dropdownButtonActions={{menuItem.dropdownButtonActions}} @dropdownButtonIcon={{menuItem.dropdownButtonIcon}} @dropdownButtonIconPrefix={{menuItem.dropdownButtonIconPrefix}} @dropdownButtonText={{menuItem.dropdownButtonText}} @dropdownButtonCalculatePosition={{menuItem.dropdownButtonCalculatePosition}} @dropdownButtonRenderInPlace={{menuItem.dropdownButtonRenderInPlace}} @dropdownButtonMenuLabel={{menuItem.dropdownButtonMenuLabel}} @dropdownButtonWrapperClass={{menuItem.dropdownButtonWrapperClass}} @dropdownButtonTriggerClass={{menuItem.dropdownButtonTriggerClass}} @registerDropdownButtonAPI={{menuItem.registerDropdownButtonAPI}}>{{menuItem.title}}</Layout::Sidebar::Item>
22
22
  {{/each}}
23
23
  </Layout::Sidebar::Panel>
24
24
  {{/each}}
@@ -11,6 +11,8 @@ import { isArray } from '@ember/array';
11
11
  */
12
12
  export default class LayoutFleetOpsSidebarComponent extends Component {
13
13
  @service universe;
14
+ @service contextPanel;
15
+ @service store;
14
16
  @tracked routePrefix = 'console.fleet-ops.';
15
17
  @tracked menuPanels = [];
16
18
  @tracked universeMenuItems = [];
@@ -100,6 +102,14 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
100
102
  return true;
101
103
  }
102
104
 
105
+ // Check if the route exists in the settings
106
+ const routeExists = visibilitySettings.some((visibilityControl) => (exactMatch ? visibilityControl.route === routePrefix : visibilityControl.route.startsWith(routePrefix)));
107
+
108
+ // If the route doesn't exist in the settings, return true (visible by default)
109
+ if (!routeExists) {
110
+ return true;
111
+ }
112
+
103
113
  return visibilitySettings.some((visibilityControl) => {
104
114
  const match = exactMatch ? visibilityControl.route === routePrefix : visibilityControl.route.startsWith(routePrefix);
105
115
  return match && visibilityControl.visible;
@@ -1,4 +1,4 @@
1
- <Drawer @isMinimized={{true}} @notchEnabled={{true}} @onLoad={{this.setDrawerContext}}>
1
+ <Drawer @onResizeEnd={{@onResizeEnd}} @onResizeStart={{@onResizeStart}} @isMinimized={{@isMinimized}} @isOpen={{@isOpen}} @notchEnabled={{true}} @onLoad={{this.setDrawerContext}}>
2
2
  <div class="ui-tabs pt-4">
3
3
  <nav>
4
4
  {{#each this.tabs as |tab|}}
@@ -87,5 +87,5 @@
87
87
  </div>
88
88
 
89
89
  {{#if this.isDataLoaded}}
90
- <LiveMapDrawer @vehicles={{this.vehicles}} @drivers={{this.drivers}} @places={{this.places}} @liveMap={{this}} @onDrawerReady={{this.setDrawerContext}} />
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
91
  {{/if}}
@@ -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>
@@ -21,15 +21,43 @@
21
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 class={{unless @order.driver_assigned "dark:text-gray-600 text-gray-400"}}>{{n-a @order.driver_assigned.name "No Driver Assigned"}}</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>
@@ -1,19 +1,147 @@
1
1
  import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
2
3
  import { action } from '@ember/object';
4
+ import { isBlank } from '@ember/utils';
5
+ import { inject as service } from '@ember/service';
3
6
 
7
+ /**
8
+ * Component representing the schedule card of an order.
9
+ * @extends Component
10
+ * @memberof OrderScheduleCardComponent
11
+ */
4
12
  export default class OrderScheduleCardComponent extends Component {
13
+ /**
14
+ * Service for managing the context panel.
15
+ * @service
16
+ * @memberof OrderScheduleCardComponent
17
+ */
18
+ @service contextPanel;
19
+
20
+ /**
21
+ * Service for managing modals.
22
+ * @service
23
+ * @memberof OrderScheduleCardComponent
24
+ */
25
+ @service modalsManager;
26
+
27
+ /**
28
+ * Service for managing notifications.
29
+ * @service
30
+ * @memberof OrderScheduleCardComponent
31
+ */
32
+ @service notifications;
33
+
34
+ /**
35
+ * Indicates if a driver is currently being assigned.
36
+ * @tracked
37
+ * @memberof OrderScheduleCardComponent
38
+ */
39
+ @tracked isAssigningDriver;
40
+
41
+ /**
42
+ * Constructor for OrderScheduleCardComponent.
43
+ * @param {Object} owner - The owner of the component.
44
+ * @param {Object} args - Arguments passed to the component, including the order.
45
+ */
5
46
  constructor(owner, { order }) {
6
47
  super(...arguments);
48
+ this.loadDriverFromOrder(order);
49
+ this.loadPayloadFromOrder(order);
50
+ }
7
51
 
8
- if (order && typeof order.loadDriver === 'function') {
9
- order.loadDriver();
10
- }
52
+ /**
53
+ * Action to handle driver click events.
54
+ * @action
55
+ * @param {DriverModel} driver - The clicked driver object.
56
+ * @memberof OrderScheduleCardComponent
57
+ */
58
+ @action onClickDriver(driver) {
59
+ this.contextPanel.focus(driver);
60
+ }
11
61
 
12
- if (order && typeof order.loadPayload === 'function') {
13
- order.loadPayload();
62
+ /**
63
+ * Action to handle vehicle click events.
64
+ * @action
65
+ * @param {VehicleModel} vehicle - The clicked vehicle object.
66
+ * @memberof OrderScheduleCardComponent
67
+ */
68
+ @action onClickVehicle(vehicle) {
69
+ this.contextPanel.focus(vehicle);
70
+ }
71
+
72
+ /**
73
+ * Action to start the process of assigning a driver.
74
+ * @action
75
+ * @memberof OrderScheduleCardComponent
76
+ */
77
+ @action startAssignDriver() {
78
+ this.isAssigningDriver = true;
79
+ }
80
+
81
+ /**
82
+ * Action to assign a driver to an order.
83
+ * @action
84
+ * @param {DriverModel} driver - The driver to be assigned.
85
+ * @memberof OrderScheduleCardComponent
86
+ */
87
+ @action assignDriver(driver) {
88
+ const order = this.args.order;
89
+
90
+ if (isBlank(driver)) {
91
+ return this.modalsManager.confirm({
92
+ title: 'Unassign Driver?',
93
+ body: `You are about to unassign the driver for Order ${order.public_id}. Click continue to confirm removal of driver.`,
94
+ acceptButtonText: 'Continue and unassign driver',
95
+ confirm: () => {
96
+ order.setProperties({
97
+ driver_assigned: null,
98
+ driver_assigned_uuid: null,
99
+ });
100
+
101
+ return order
102
+ .save()
103
+ .catch((error) => {
104
+ this.notifications.serverError(error);
105
+ })
106
+ .finally(() => {
107
+ this.isAssigningDriver = false;
108
+ });
109
+ },
110
+ decline: (modal) => {
111
+ this.isAssigningDriver = false;
112
+ modal.done();
113
+ },
114
+ });
14
115
  }
116
+
117
+ return this.modalsManager.confirm({
118
+ title: 'Assign New Driver?',
119
+ body: `You are about to assign a new driver (${driver.name}) to Order ${order.public_id}. Click continue to confirm driver.`,
120
+ acceptButtonText: 'Continue and assign driver',
121
+ confirm: () => {
122
+ order.set('driver_assigned_uuid', driver.id);
123
+ return order
124
+ .save()
125
+ .catch((error) => {
126
+ this.notifications.serverError(error);
127
+ })
128
+ .finally(() => {
129
+ this.isAssigningDriver = false;
130
+ });
131
+ },
132
+ decline: (modal) => {
133
+ this.isAssigningDriver = false;
134
+ modal.done();
135
+ },
136
+ });
15
137
  }
16
138
 
139
+ /**
140
+ * Action triggered when the title of an order is clicked.
141
+ * @action
142
+ * @param {OrderModel} order - The order associated with the clicked title.
143
+ * @memberof OrderScheduleCardComponent
144
+ */
17
145
  @action onTitleClick(order) {
18
146
  const { onTitleClick } = this.args;
19
147
 
@@ -21,4 +149,26 @@ export default class OrderScheduleCardComponent extends Component {
21
149
  onTitleClick(order);
22
150
  }
23
151
  }
152
+
153
+ /**
154
+ * Loads the driver information from the order.
155
+ * @param {OrderModel} order - The order to load the driver from.
156
+ * @memberof OrderScheduleCardComponent
157
+ */
158
+ loadDriverFromOrder(order) {
159
+ if (order && typeof order.loadDriver === 'function') {
160
+ order.loadDriver();
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Loads the payload information from the order.
166
+ * @param {OrderModel} order - The order to load the payload from.
167
+ * @memberof OrderScheduleCardComponent
168
+ */
169
+ loadPayloadFromOrder(order) {
170
+ if (order && typeof order.loadPayload === 'function') {
171
+ order.loadPayload();
172
+ }
173
+ }
24
174
  }
@@ -6,7 +6,13 @@
6
6
  @isResizeble={{or this.isResizable @isResizable}}
7
7
  @width={{or this.width @width "600px"}}
8
8
  >
9
- <Overlay::Header @title={{if this.place.public_id this.place.name "New Place"}} @status={{this.place.public_id}} @hideStatusDot={{true}} @createdAt={{this.place.createdAt}} @titleWrapperClass="leading-5">
9
+ <Overlay::Header
10
+ @title={{if this.place.public_id this.place.name "New Place"}}
11
+ @status={{this.place.public_id}}
12
+ @hideStatusDot={{true}}
13
+ @createdAt={{this.place.createdAt}}
14
+ @titleWrapperClass="leading-5"
15
+ >
10
16
  <div class="flex flex-1 justify-end">
11
17
  <Button @icon={{if this.place.id "save" "check"}} @type="primary" @text={{if this.place.id "Save Place" "Create Place"}} @onClick={{this.save}} @wrapperClass="mr-2" />
12
18
  <Button @type="default" @icon="times" @helpText={{if this.place.id "Cancel edit place" "Cancel new place"}} @onClick={{this.onPressCancel}} />
@@ -15,9 +21,11 @@
15
21
 
16
22
  <Overlay::Body @wrapperClass="new-service-rate-overlay-body px-4 space-y-4 pt-4" @increaseInnerBodyHeightBy={{1000}}>
17
23
  <div class="grid grid-cols-3 gap-1 text-xs dark:text-gray-100">
18
- <InputGroup @name="Name" @autocomplete="nope" @value={{this.place.name}} @wrapperClass="col-span-3" />
24
+ <InputGroup @name="Name" @wrapperClass="col-span-2">
25
+ <Input @value={{this.place.name}} @type="text" class="w-full form-input" placeholder="Name" />
26
+ </InputGroup>
19
27
  <InputGroup @name="Street 1" @value={{this.place.street1}} @wrapperClass="col-span-3">
20
- <AutocompleteInput @value={{this.place.street1}} @fetchUrl="places/lookup" @onSelect={{this.autocomplete}} placeholder="Street 1" class="w-full" as |result|>
28
+ <AutocompleteInput @value={{this.place.street1}} @fetchUrl="places/lookup" @onSelect={{this.onAutocomplete}} placeholder="Street 1" class="w-full" as |result|>
21
29
  {{result.address}}
22
30
  </AutocompleteInput>
23
31
  </InputGroup>
@@ -29,14 +37,14 @@
29
37
  <InputGroup @name="City" @autocomplete="nope" @value={{this.place.city}} />
30
38
  <InputGroup @name="State" @autocomplete="nope" @value={{this.place.province}} />
31
39
  <InputGroup @name="Country" @wrapperClass="col-span-2">
32
- <CountrySelect class="w-full form-input form-select form-datalist" @value={{this.place.country}} @onChange={{this.place.country}} placeholder="Country" />
40
+ <CountrySelect class="w-full form-input form-select form-datalist" @value={{this.place.country}} @onChange={{fn (mut this.place.country)}} placeholder="Country" />
33
41
  </InputGroup>
34
42
  <InputGroup @name="Coordinates" @wrapperClass="col-span-2">
35
43
  <CoordinatesInput
36
44
  @value={{this.place.location}}
37
45
  @onChange={{this.updatePlaceCoordinates}}
38
- @onGeocode={{this.autocomplete}}
39
- @onUpdatedFromMap={{this.reverseGeocode}}
46
+ @onGeocode={{this.onAutocomplete}}
47
+ @onUpdatedFromMap={{this.onReverseGeocode}}
40
48
  @onInit={{this.setCoordinatesInput}}
41
49
  />
42
50
  </InputGroup>
@@ -44,7 +52,6 @@
44
52
  <InputGroup @name="Phone">
45
53
  <PhoneInput @value={{this.place.phone}} @autocomplete="nope" @onInput={{this.phone}} class="form-input w-full" />
46
54
  </InputGroup>
47
- <InputGroup @name="Email" @autocomplete="nope" @value={{this.place.email}} />
48
55
  </div>
49
56
  </Overlay::Body>
50
57
  </Overlay>
@@ -2,6 +2,8 @@ import Component from '@glimmer/component';
2
2
  import { tracked } from '@glimmer/tracking';
3
3
  import { inject as service } from '@ember/service';
4
4
  import { action } from '@ember/object';
5
+ import { isBlank } from '@ember/utils';
6
+ import Point from '@fleetbase/fleetops-data/utils/geojson/point';
5
7
  import contextComponentCallback from '../utils/context-component-callback';
6
8
  import applyContextComponentArguments from '../utils/apply-context-component-arguments';
7
9
 
@@ -48,6 +50,12 @@ export default class PlaceFormPanelComponent extends Component {
48
50
  */
49
51
  @tracked isLoading = false;
50
52
 
53
+ /**
54
+ * The coordinates input component instance.
55
+ * @type {CoordinateInputComponent}
56
+ */
57
+ @tracked coordinatesInputComponent;
58
+
51
59
  /**
52
60
  * All possible place types
53
61
  *
@@ -131,4 +139,67 @@ export default class PlaceFormPanelComponent extends Component {
131
139
  @action onPressCancel() {
132
140
  return contextComponentCallback(this, 'onPressCancel', this.place);
133
141
  }
142
+
143
+ /**
144
+ * Handles the selection from an autocomplete. Updates the place properties with the selected data.
145
+ * If a coordinates input component is present, updates its coordinates too.
146
+ *
147
+ * @action
148
+ * @param {Object} selected - The selected item from the autocomplete.
149
+ * @param {Object} selected.location - The location data of the selected item.
150
+ * @memberof PlaceFormPanelComponent
151
+ */
152
+ @action onAutocomplete(selected) {
153
+ this.place.setProperties({ ...selected });
154
+
155
+ if (this.coordinatesInputComponent) {
156
+ this.coordinatesInputComponent.updateCoordinates(selected.location);
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Performs reverse geocoding given latitude and longitude. Updates place properties with the geocoding result.
162
+ *
163
+ * @action
164
+ * @param {Object} coordinates - The latitude and longitude coordinates.
165
+ * @param {number} coordinates.latitude - Latitude value.
166
+ * @param {number} coordinates.longitude - Longitude value.
167
+ * @returns {Promise} A promise that resolves with the reverse geocoding result.
168
+ * @memberof PlaceFormPanelComponent
169
+ */
170
+ @action onReverseGeocode({ latitude, longitude }) {
171
+ return this.fetch.get('geocoder/reverse', { coordinates: [latitude, longitude].join(','), single: true }).then((result) => {
172
+ if (isBlank(result)) {
173
+ return;
174
+ }
175
+
176
+ this.place.setProperties({ ...result });
177
+ });
178
+ }
179
+
180
+ /**
181
+ * Sets the coordinates input component.
182
+ *
183
+ * @action
184
+ * @param {Object} coordinatesInputComponent - The coordinates input component to be set.
185
+ * @memberof PlaceFormPanelComponent
186
+ */
187
+ @action setCoordinatesInput(coordinatesInputComponent) {
188
+ this.coordinatesInputComponent = coordinatesInputComponent;
189
+ }
190
+
191
+ /**
192
+ * Updates the place coordinates with the given latitude and longitude.
193
+ *
194
+ * @action
195
+ * @param {Object} coordinates - The latitude and longitude coordinates.
196
+ * @param {number} coordinates.latitude - Latitude value.
197
+ * @param {number} coordinates.longitude - Longitude value.
198
+ * @memberof PlaceFormPanelComponent
199
+ */
200
+ @action updatePlaceCoordinates({ latitude, longitude }) {
201
+ const location = new Point(longitude, latitude);
202
+
203
+ this.place.setProperties({ location });
204
+ }
134
205
  }
@@ -2,7 +2,15 @@
2
2
  <ContentPanel @title="Map" @open={{false}}>
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
- <layers.marker @id={{@place.id}} @icon={{icon iconUrl="/engines-dist/images/building-marker.png" iconSize=(array 16 16)}} @location={{point-to-coordinates @place.location}} @riseOnHover={{true}} @title={{@place.address}} @alt={{@place.address}} as |marker|>
5
+ <layers.marker
6
+ @id={{@place.id}}
7
+ @icon={{icon iconUrl="/engines-dist/images/building-marker.png" iconSize=(array 16 16)}}
8
+ @location={{point-to-coordinates @place.location}}
9
+ @riseOnHover={{true}}
10
+ @title={{@place.address}}
11
+ @alt={{@place.address}}
12
+ as |marker|
13
+ >
6
14
  <marker.popup>
7
15
  <div>{{@place.address}}</div>
8
16
  <div>{{format-point @place.location}}</div>
@@ -60,24 +68,6 @@
60
68
  <div class="field-value">{{n-a @place.phone}}</div>
61
69
  </div>
62
70
 
63
- <div class="field-info-container">
64
- <div class="field-name">Email</div>
65
- <div class="field-value">{{n-a @place.email}}</div>
66
- </div>
67
-
68
- <div class="field-info-container">
69
- <div class="field-name">Vendor</div>
70
- <div class="field-value">
71
- {{#if @place.vendor_uuid}}
72
- <a href="javascript:;" {{on "click" @place.viewVendor}}>
73
- {{@place.vendor_name}}
74
- </a>
75
- {{else}}
76
- {{@place.vendor_name}}
77
- {{/if}}
78
- </div>
79
- </div>
80
-
81
71
  <div class="field-info-container col-span-3">
82
72
  <div class="field-name">
83
73
  Coordinates