@fleetbase/fleetops-engine 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/addon/components/driver-form-panel.hbs +131 -0
  2. package/addon/components/driver-form-panel.js +39 -0
  3. package/addon/components/driver-panel/details.hbs +48 -0
  4. package/addon/components/driver-panel.hbs +60 -0
  5. package/addon/components/driver-panel.js +57 -0
  6. package/addon/components/fleet-form-panel.hbs +46 -0
  7. package/addon/components/fleet-form-panel.js +3 -0
  8. package/addon/components/fleet-panel.hbs +70 -0
  9. package/addon/components/fleet-panel.js +43 -0
  10. package/addon/components/fleet-vehicle-listing.hbs +73 -0
  11. package/addon/components/fleet-vehicle-listing.js +117 -0
  12. package/addon/components/leaflet-drift-marker.js +53 -0
  13. package/addon/components/live-map.hbs +4 -4
  14. package/addon/components/live-map.js +104 -34
  15. package/addon/components/modals/fleet-details.hbs +1 -0
  16. package/addon/components/settings-window.hbs +1 -1
  17. package/addon/components/vehicle-form-panel.hbs +131 -0
  18. package/addon/components/vehicle-form-panel.js +39 -0
  19. package/addon/components/vehicle-panel/details.hbs +34 -0
  20. package/addon/components/vehicle-panel/tracking.hbs +1 -0
  21. package/addon/components/vehicle-panel.hbs +60 -0
  22. package/addon/components/vehicle-panel.js +57 -0
  23. package/addon/controllers/management/drivers/index/details.js +8 -0
  24. package/addon/controllers/management/drivers/index/edit.js +80 -0
  25. package/addon/controllers/management/drivers/index/new.js +128 -0
  26. package/addon/controllers/management/drivers/index.js +212 -202
  27. package/addon/controllers/management/fleets/index/details.js +8 -0
  28. package/addon/controllers/management/fleets/index/edit.js +77 -0
  29. package/addon/controllers/management/fleets/index/new.js +103 -0
  30. package/addon/controllers/management/fleets/index.js +49 -77
  31. package/addon/controllers/management/vehicles/index/details.js +12 -0
  32. package/addon/controllers/management/vehicles/index/edit.js +8 -0
  33. package/addon/controllers/management/vehicles/index/new.js +21 -0
  34. package/addon/controllers/management/vehicles/index.js +6 -129
  35. package/addon/controllers/operations/orders/index/new.js +67 -20
  36. package/addon/controllers/operations/orders/index/view.js +15 -4
  37. package/addon/controllers/operations/orders/index.js +58 -7
  38. package/addon/controllers/operations/service-rates/index/edit.js +1 -1
  39. package/addon/controllers/operations/service-rates/index/new.js +10 -11
  40. package/addon/controllers/operations/service-rates/index.js +7 -0
  41. package/addon/engine.js +6 -0
  42. package/addon/initializers/load-leaflet-assets.js +6 -1
  43. package/addon/instance-initializers/register-leaflet-drift-marker.js +17 -0
  44. package/addon/routes/management/drivers/index/details.js +9 -0
  45. package/addon/routes/management/drivers/index/edit.js +13 -0
  46. package/addon/routes/management/drivers/index/new.js +3 -0
  47. package/addon/routes/management/fleets/index/details.js +9 -0
  48. package/addon/routes/management/fleets/index/edit.js +9 -0
  49. package/addon/routes/management/fleets/index/new.js +3 -0
  50. package/addon/routes/management/fleets/index.js +1 -0
  51. package/addon/routes/management/vehicles/index/details.js +18 -0
  52. package/addon/routes/management/vehicles/index/edit.js +14 -0
  53. package/addon/routes/management/vehicles/index/new.js +3 -0
  54. package/addon/routes/operations/orders/index/new.js +3 -1
  55. package/addon/routes/operations/orders/index/view.js +50 -0
  56. package/addon/routes/operations/service-rates/index/edit.js +7 -0
  57. package/addon/routes.js +15 -3
  58. package/addon/templates/management/drivers/index/details.hbs +1 -0
  59. package/addon/templates/management/drivers/index/edit.hbs +1 -0
  60. package/addon/templates/management/drivers/index/new.hbs +1 -0
  61. package/addon/templates/management/drivers/index.hbs +3 -1
  62. package/addon/templates/management/fleets/index/details.hbs +1 -0
  63. package/addon/templates/management/fleets/index/edit.hbs +1 -0
  64. package/addon/templates/management/fleets/index/new.hbs +1 -0
  65. package/addon/templates/management/vehicles/index/details.hbs +1 -0
  66. package/addon/templates/management/vehicles/index/edit.hbs +1 -0
  67. package/addon/templates/management/vehicles/index/new.hbs +1 -0
  68. package/addon/templates/operations/orders/index/new.hbs +1 -1
  69. package/addon/templates/operations/service-rates/index/new.hbs +4 -4
  70. package/app/components/driver-form-panel.js +1 -0
  71. package/app/components/driver-panel/details.js +1 -0
  72. package/app/components/driver-panel.js +1 -0
  73. package/app/components/fleet-form-panel.js +1 -0
  74. package/app/components/fleet-panel.js +1 -0
  75. package/app/components/fleet-vehicle-listing.js +1 -0
  76. package/app/components/leaflet-drift-marker.js +1 -0
  77. package/app/components/vehicle-form-panel.js +1 -0
  78. package/app/components/vehicle-panel/details.js +1 -0
  79. package/app/components/vehicle-panel/tracking.js +1 -0
  80. package/app/components/vehicle-panel.js +1 -0
  81. package/app/controllers/management/drivers/index/new.js +1 -0
  82. package/app/controllers/management/vehicles/index/details.js +1 -0
  83. package/app/controllers/management/vehicles/index/new.js +1 -0
  84. package/app/routes/management/drivers/index/details.js +1 -0
  85. package/app/routes/management/drivers/index/edit.js +1 -0
  86. package/app/routes/management/drivers/index/new.js +1 -0
  87. package/app/routes/management/vehicles/index/details.js +1 -0
  88. package/app/routes/management/vehicles/index/edit.js +1 -0
  89. package/app/routes/management/vehicles/index/new.js +1 -0
  90. package/app/templates/management/drivers/index/details.js +1 -0
  91. package/app/templates/management/drivers/index/edit.js +1 -0
  92. package/app/templates/management/drivers/index/new.js +1 -0
  93. package/app/templates/management/vehicles/index/details.js +1 -0
  94. package/app/templates/management/vehicles/index/edit.js +1 -0
  95. package/app/templates/management/vehicles/index/new.js +1 -0
  96. package/assets/images/boxes/large.png +0 -0
  97. package/assets/images/boxes/medium.png +0 -0
  98. package/assets/images/boxes/small.png +0 -0
  99. package/assets/images/boxes/x-large.png +0 -0
  100. package/index.js +16 -0
  101. package/package.json +6 -5
@@ -0,0 +1,131 @@
1
+ <Overlay @position="right" @noBackdrop={{true}} @fullHeight={{true}} @width="700">
2
+ <Overlay::Header @hideLeftSection={{true}} @actionsWrapperClass="flex-1 flex-col py-3" class="h-auto-i min-h-[127px]">
3
+ <div class="flex flex-row items-center justify-between w-full mb-4">
4
+ <div class="flex flex-1 space-x-2">
5
+ {{#if @driver.id}}
6
+ <Button @type="default" @icon="id-card" @helpText="View driver details" @onClick={{this.viewDetails}} />
7
+ {{/if}}
8
+ </div>
9
+ <div class="flex flex-1 justify-end">
10
+ <div class="mr-2">
11
+ <Button @icon={{if @driver.id "save" "check"}} @type="primary" @text={{if @driver.id "Save Driver" "Create Driver"}} @onClick={{this.save}} />
12
+ </div>
13
+ <Button @type="default" @icon="times" @helpText={{if @driver.id "Cancel edit driver" "Cancel new driver"}} @onClick={{@onPressCancel}} />
14
+ </div>
15
+ </div>
16
+ <div class="flex flex-row justify-between w-full">
17
+ <div class="flex flex-col flex-1 w-3/4">
18
+ <div class="flex flex-row">
19
+ <div class="w-14 flex items-center justify-start">
20
+ <Image src={{@driver.photo_url}} @fallbackSrc={{config "defaultValues.driverImage"}} alt={{@driver.name}} height="48" width="48" class="h-12 w-12 rounded-lg shadow-sm" />
21
+ <Attach::Tooltip @class="clean" @animation="scale" @placement={{"top"}}>
22
+ <InputInfo @text={{@driver.public_id}} />
23
+ </Attach::Tooltip>
24
+ </div>
25
+ <div class="flex flex-col pt-2">
26
+ <h1 class="text-gray-900 dark:text-white text-2xl">
27
+ {{#if @driver.id}}
28
+ {{@driver.name}}
29
+ {{else}}
30
+ {{#if @driver.name}}
31
+ {{@driver.name}}
32
+ {{else}}
33
+ <span>New Driver</span>
34
+ {{/if}}
35
+ {{/if}}
36
+ </h1>
37
+ <div class="-mt-1">
38
+ {{#if @driver.vehicle}}
39
+ <div class="flex flex-row items-center">
40
+ <span class="text-sm dark:text-gray-500 text-gray-700 mr-3">{{@driver.vehicle.displayName}}</span>
41
+ </div>
42
+ {{else}}
43
+ <div class="flex flex-row items-center">
44
+ <span class="text-sm dark:text-gray-500 text-gray-700 mr-3">No vehicle assigned</span>
45
+ </div>
46
+ {{/if}}
47
+ </div>
48
+ </div>
49
+ </div>
50
+ </div>
51
+ <div class="flex justify-end w-1/4">
52
+ <Badge @status={{@driver.status}} />
53
+ </div>
54
+ </div>
55
+ </Overlay::Header>
56
+
57
+ <Overlay::Body @wrapperClass="new-service-rate-overlay-body px-4 space-y-4 pt-4" @increaseInnerBodyHeightBy={{1000}}>
58
+ <div class="flex-1">
59
+ <div class="grid grid-cols-1 gap-2 text-xs dark:text-gray-100 mb-4">
60
+ <div class="input-group">
61
+ <label>
62
+ Name
63
+ </label>
64
+ <Input @value={{@driver.name}} @type="text" class="w-full form-input" placeholder="Name" />
65
+ </div>
66
+ </div>
67
+
68
+ <div class="grid grid-cols-2 gap-2 text-xs dark:text-gray-100">
69
+ <div class="input-group">
70
+ <label>
71
+ Internal ID
72
+ </label>
73
+ <Input @value={{@driver.internal_id}} @type="text" class="w-full form-input" placeholder="Internal ID" />
74
+ </div>
75
+
76
+ <div class="input-group">
77
+ <label>
78
+ Drivers License
79
+ </label>
80
+ <Input @value={{@driver.drivers_license_number}} @type="text" class="w-full form-input" placeholder="Drivers License" />
81
+ </div>
82
+
83
+ <div class="input-group">
84
+ <label>
85
+ Email
86
+ </label>
87
+ <Input @value={{@driver.email}} @type="text" class="w-full form-input" placeholder="Email" />
88
+ </div>
89
+
90
+ <div class="input-group">
91
+ <label>
92
+ Phone
93
+ </label>
94
+ <PhoneInput @value={{@driver.phone}} @onInput={{fn (mut @driver.phone)}} class="form-input w-full" />
95
+ </div>
96
+
97
+ <div class="input-group">
98
+ <label>
99
+ Vendor
100
+ </label>
101
+ <ModelSelect @modelName="vendor" @selectedModel={{@driver.vendor}} @placeholder="Select Vendor" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{fn (mut @driver.vendor)}} as |model|>
102
+ {{model.name}}
103
+ </ModelSelect>
104
+ </div>
105
+
106
+ <div class="input-group">
107
+ <label>
108
+ Vehicle
109
+ </label>
110
+ <ModelSelect @modelName="vehicle" @selectedModel={{@driver.vehicle}} @placeholder="Select Vehicle" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{fn (mut @driver.vehicle)}} as |model|>
111
+ {{model.display_name}}
112
+ </ModelSelect>
113
+ </div>
114
+
115
+ <div class="input-group">
116
+ <label>
117
+ City
118
+ </label>
119
+ <Input @value={{@driver.city}} @type="text" class="w-full form-input" placeholder="City" />
120
+ </div>
121
+
122
+ <div class="input-group">
123
+ <label>
124
+ Country
125
+ </label>
126
+ <CountrySelect class="w-full form-input form-select form-datalist" @value={{@driver.country}} @onChange={{fn (mut @driver.country)}} placeholder="Country" />
127
+ </div>
128
+ </div>
129
+ </div>
130
+ </Overlay::Body>
131
+ </Overlay>
@@ -0,0 +1,39 @@
1
+ import Component from '@glimmer/component';
2
+ import { inject as service } from '@ember/service';
3
+ import { action } from '@ember/object';
4
+
5
+ export default class DriverFormPanelComponent extends Component {
6
+ @service store;
7
+ @service notifications;
8
+ @service hostRouter;
9
+ @service loader;
10
+
11
+ @action save() {
12
+ const { driver, onAfterSave } = this.args;
13
+
14
+ this.loader.showLoader('.overlay-inner-content', 'Saving driver...');
15
+
16
+ try {
17
+ return driver
18
+ .save()
19
+ .then((vehicle) => {
20
+ this.notifications.success(`Driver (${driver.name}) saved successfully.`);
21
+
22
+ if (typeof onAfterSave === 'function') {
23
+ onAfterSave(vehicle);
24
+ }
25
+ })
26
+ .catch(this.notifications.serverError)
27
+ .finally(() => {
28
+ this.loader.removeLoader();
29
+ });
30
+ } catch (error) {
31
+ this.loader.removeLoader();
32
+ }
33
+ }
34
+
35
+ @action viewDetails() {
36
+ const { driver } = this.args;
37
+ return this.hostRouter.transitionTo('console.fleet-ops.management.drivers.index.details', driver.public_id);
38
+ }
39
+ }
@@ -0,0 +1,48 @@
1
+ <div class="p-4">
2
+ <ContentPanel @title="Details" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-900">
3
+ <div class="grid grid-cols-2 gap-2 text-xs md:mb-6 dark:text-gray-100">
4
+ <div class="field-info-container ">
5
+ <div class="field-name">Name</div>
6
+ <div class="field-value">{{n-a @driver.name}}</div>
7
+ </div>
8
+ <div class="field-info-container">
9
+ <div class="field-name">ID</div>
10
+ <div class="field-value">{{n-a @driver.public_id}}</div>
11
+ </div>
12
+ <div class="field-info-container">
13
+ <div class="field-name">Internal ID</div>
14
+ <div class="field-value">{{n-a @driver.internal_id}}</div>
15
+ </div>
16
+ <div class="field-info-container">
17
+ <div class="field-name">Drivers License</div>
18
+ <div class="field-value">{{n-a @driver.drivers_license}}</div>
19
+ </div>
20
+ <div class="field-info-container">
21
+ <div class="field-name">Email</div>
22
+ <div class="field-value">{{n-a @driver.email}}</div>
23
+ </div>
24
+ <div class="field-info-container">
25
+ <div class="field-name">Phone</div>
26
+ <div class="field-value">{{n-a @driver.phone}}</div>
27
+ </div>
28
+ <div class="field-info-container">
29
+ <div class="field-name">Current Job</div>
30
+ <div class="field-value">{{n-a @driver.current_job_id}}</div>
31
+ </div>
32
+ <div class="field-info-container">
33
+ <div class="field-name">City</div>
34
+ <div class="field-value">{{n-a @driver.city}}</div>
35
+ </div>
36
+ {{!-- <div class="field-info-container">
37
+ <div class="field-name">Country</div>
38
+ <div class="field-value">
39
+ <CountryName @country={{@driver.country}} />
40
+ </div>
41
+ </div> --}}
42
+ <div class="field-info-container md:col-span-3">
43
+ <div class="field-name">Coordinates</div>
44
+ <div class="field-value">{{point-coordinates @driver.location}}</div>
45
+ </div>
46
+ </div>
47
+ </ContentPanel>
48
+ </div>
@@ -0,0 +1,60 @@
1
+ <Overlay @position="right" @noBackdrop={{true}} @fullHeight={{true}} @width="700">
2
+ <Overlay::Header @hideLeftSection={{true}} @actionsWrapperClass="flex-1 flex-col py-3" class="h-auto-i min-h-[127px]">
3
+ <div class="flex flex-row items-center justify-between w-full mb-4">
4
+ <div class="flex flex-1 space-x-2">
5
+ {{!-- <Button @type="default" @icon="location-arrow" @helpText="Locate driver" @onClick={{@onPressCancel}} /> --}}
6
+ <Button @type="default" @icon="pen" @helpText="Edit driver" @onClick={{this.editDriver}} />
7
+ </div>
8
+ <div class="flex flex-1 justify-end">
9
+ <Button @type="default" @icon="times" @helpText="Close driver details" @onClick={{@onPressCancel}} />
10
+ </div>
11
+ </div>
12
+ <div class="flex flex-row justify-between w-full">
13
+ <div class="flex flex-col flex-1 w-3/4">
14
+ <div class="flex flex-row">
15
+ <div class="w-14 flex items-center justify-start">
16
+ <Image src={{@driver.photo_url}} @fallbackSrc={{config "defaultValues.driverImage"}} alt={{@driver.name}} height="48" width="48" class="h-12 w-12 rounded-lg shadow-sm" />
17
+ <Attach::Tooltip @class="clean" @animation="scale" @placement={{"top"}}>
18
+ <InputInfo @text={{@driver.public_id}} />
19
+ </Attach::Tooltip>
20
+ </div>
21
+ <div class="flex flex-col">
22
+ <h1 class="text-gray-900 dark:text-white text-2xl">{{@driver.name}}</h1>
23
+ <div class="-mt-1">
24
+ {{#if @driver.vehicle}}
25
+ <div class="flex flex-row items-center">
26
+ <span class="text-sm dark:text-gray-500 text-gray-700 mr-3">{{@driver.vehicle.displayName}}</span>
27
+ </div>
28
+ {{else}}
29
+ <div class="flex flex-row items-center">
30
+ <span class="text-sm dark:text-gray-500 text-gray-700 mr-3">No vehicle assigned</span>
31
+ {{!-- <Button @icon="plus" @size="xs" @helpText="Assign a vehicle to driver" /> --}}
32
+ </div>
33
+ {{/if}}
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ <div class="flex justify-end w-1/4">
39
+ <Badge @status={{@driver.status}} />
40
+ </div>
41
+ </div>
42
+ </Overlay::Header>
43
+ <Overlay::Body class="no-padding" @increaseInnerBodyHeightBy={{1000}}>
44
+ <div class="section-header-actions w-full overflow-x-scroll lg:overflow-x-auto">
45
+ <div class="ui-tabs mt-4">
46
+ <nav>
47
+ {{#each this.tabs as |tab|}}
48
+ <a href="javascript:;" class="ui-tab {{if (eq this.currentTab tab.slug) 'active' }}" {{on "click" (fn this.changeTab tab.slug)}}>
49
+ <FaIcon @icon={{tab.icon}} class="mr-1" />
50
+ <span>{{tab.title}}</span>
51
+ </a>
52
+ {{/each}}
53
+ </nav>
54
+ </div>
55
+ </div>
56
+ <div class="tab-content tab-{{this.currentTab}}">
57
+ {{component this.tab.component driver=@driver tabOptions=this.tab params=this.tab.componentParams}}
58
+ </div>
59
+ </Overlay::Body>
60
+ </Overlay>
@@ -0,0 +1,57 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { action, computed } from '@ember/object';
4
+ import { inject as service } from '@ember/service';
5
+ import { isArray } from '@ember/array';
6
+ import DriverPanelDetailComponent from './driver-panel/details';
7
+
8
+ export default class DriverPanelComponent extends Component {
9
+ @service fetch;
10
+ @service modalsManager;
11
+ @service universe;
12
+ @service store;
13
+ @service hostRouter;
14
+ @tracked currentTab;
15
+ @tracked devices = [];
16
+ @tracked deviceApi = {};
17
+ @tracked vehicle;
18
+
19
+ get tabs() {
20
+ const registeredTabs = this.universe.getMenuItemsFromRegistry('component:driver-panel');
21
+ // this.universe._createMenuItem('Tracking', null, { icon: 'satellite-dish', component: DriverPanelTrackingComponent }),
22
+ const defaultTabs = [this.universe._createMenuItem('Details', null, { icon: 'circle-info', component: DriverPanelDetailComponent })];
23
+
24
+ if (isArray(registeredTabs)) {
25
+ return [...defaultTabs, ...registeredTabs];
26
+ }
27
+
28
+ return defaultTabs;
29
+ }
30
+
31
+ @computed('currentTab', 'tabs') get tab() {
32
+ if (this.currentTab) {
33
+ return this.tabs.find(({ slug }) => slug === this.currentTab);
34
+ }
35
+
36
+ return null;
37
+ }
38
+
39
+ constructor() {
40
+ super(...arguments);
41
+ this.vehicle = this.args.vehicle;
42
+ this.changeTab(this.args.tab || 'details');
43
+ }
44
+
45
+ @action async changeTab(tab) {
46
+ this.currentTab = tab;
47
+
48
+ if (typeof this.args.onTabChanged === 'function') {
49
+ this.args.onTabChanged(tab);
50
+ }
51
+ }
52
+
53
+ @action editDriver() {
54
+ const { driver } = this.args;
55
+ return this.hostRouter.transitionTo('console.fleet-ops.management.drivers.index.edit', driver.public_id);
56
+ }
57
+ }
@@ -0,0 +1,46 @@
1
+ <Overlay @position="right" @noBackdrop={{true}} @fullHeight={{true}} @width="700">
2
+ <Overlay::Header @title={{if @fleet.public_id "Update Fleet" "New Fleet"}} @status={{@fleet.public_id}} @hideStatusDot={{true}} @createdAt={{@fleet.createdAt}} @onPressCancel={{@onPressCancel}}>
3
+ {{#if @fleet.id}}
4
+ <Button @icon="save" @type="primary" @text="Save Fleet" @onClick={{@onUpdateFleet}} />
5
+ {{else}}
6
+ <Button @icon="check" @type="primary" @text="Create Fleet" @onClick={{@onCreateFleet}} />
7
+ {{/if}}
8
+ </Overlay::Header>
9
+
10
+ <Overlay::Body @wrapperClass="new-service-rate-overlay-body px-4 space-y-4 pt-4" @increaseInnerBodyHeightBy={{1000}}>
11
+ <div class="modal-body-container">
12
+ <div class="grid grid-cols-2 gap-2 text-xs dark:text-gray-100">
13
+ <div class="col-span-2 mb-2">
14
+ <InputGroup @name="Fleet Name" @value={{@fleet.name}} />
15
+ </div>
16
+ <InputGroup @name="Assign to Service Area" @value={{@fleet.service_area}}>
17
+ <ModelSelect @modelName="service-area" @selectedModel={{@fleet.service_area}} @placeholder="Select service area to assign fleet to" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{fn (mut @fleet.service_area)}} as |model|>
18
+ {{model.name}}
19
+ </ModelSelect>
20
+ </InputGroup>
21
+ {{#if @fleet.service_area}}
22
+ <InputGroup @name="Assign to Zone" @value={{@fleet.zone}}>
23
+ <ModelSelect @modelName="zone" @selectedModel={{@fleet.zone}} @query={{hash service_area_uuid=@fleet.service_area.id}} @placeholder="Select zone to assign fleet to" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{fn (mut @fleet.zone)}} as |model|>
24
+ {{model.name}}
25
+ </ModelSelect>
26
+ </InputGroup>
27
+ {{/if}}
28
+ <InputGroup @name="Task/ Mission" @helpText="Give a description of this fleet's primary task or mission if applicable." @value={{@fleet.task}} />
29
+ <InputGroup @name="Status" @helpText="Select the status of the fleet.">
30
+ <Select this={{@statusOptions}} @value={{@fleet.status}} @onSelect={{fn (mut @fleet.status)}} @placeholder="Select status" class="w-full" />
31
+ </InputGroup>
32
+ <InputGroup @name="Vendor" @value={{@fleet.vendor}}>
33
+ <ModelSelect @modelName="vendor" @selectedModel={{@fleet.vendor}} @placeholder="Select vendor to assign fleet to" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{fn (mut @fleet.vendor)}} as |model|>
34
+ {{model.name}}
35
+ </ModelSelect>
36
+ </InputGroup>
37
+ <InputGroup @name="Fleet" @value={{@fleet.parent_fleet}}>
38
+ <ModelSelect @modelName="fleet" @selectedModel={{@fleet.parent_fleet}} @placeholder="Select parent fleet to assign fleet to" @triggerClass="form-select form-input" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{fn (mut @fleet.parent_fleet)}} as |model|>
39
+ {{model.name}}
40
+ </ModelSelect>
41
+ </InputGroup>
42
+ </div>
43
+ </div>
44
+ {{yield}}
45
+ </Overlay::Body>
46
+ </Overlay>
@@ -0,0 +1,3 @@
1
+ import Component from '@glimmer/component';
2
+
3
+ export default class FleetFormPanelComponent extends Component {}
@@ -0,0 +1,70 @@
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}}>
4
+ </Overlay::Header>
5
+
6
+ <Overlay::Body class="no-padding" @increaseInnerBodyHeightBy={{1000}}>
7
+ <div class="section-header-actions w-full overflow-x-scroll lg:overflow-x-auto">
8
+ <div class="ui-tabs mt-4">
9
+ <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>
22
+ </nav>
23
+ </div>
24
+ </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>
68
+ </div>
69
+ </Overlay::Body>
70
+ </Overlay>
@@ -0,0 +1,43 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { action } from '@ember/object';
4
+ import { inject as service } from '@ember/service';
5
+
6
+ export default class FleetPanelComponent extends Component {
7
+ @service fetch;
8
+ @service modalsManager;
9
+ @service store;
10
+ @service fetch;
11
+ @tracked currentTab;
12
+ @tracked fleet;
13
+
14
+ constructor() {
15
+ super(...arguments);
16
+ this.fleet = this.args.fleet;
17
+ this.changeTab(this.args.tab || 'details');
18
+ }
19
+
20
+ @action async changeTab(tab) {
21
+ this.currentTab = tab;
22
+
23
+ if (typeof this.args.onTabChanged === 'function') {
24
+ this.args.onTabChanged(tab);
25
+ }
26
+ }
27
+
28
+ @action addDriver(driver) {
29
+ this.fetch.post('fleets/assign-device', { driver: driver.id, fleet: this.fleet.id });
30
+ }
31
+
32
+ @action removeDriver(driver) {
33
+ this.fetch.post('fleets/remove-device', { driver: driver.id, fleet: this.fleet.id });
34
+ }
35
+
36
+ @action addVehicle(vehicle) {
37
+ this.fetch.post('fleets/assign-vehicle', { vehicle: vehicle.id, fleet: this.fleet.id });
38
+ }
39
+
40
+ @action removeVehicle(vehicle) {
41
+ this.fetch.post('fleets/remove-vehicle', { vehicle: vehicle.id, fleet: this.fleet.id });
42
+ }
43
+ }
@@ -0,0 +1,73 @@
1
+ {{yield}}<div class="fleet-vehicle-listing" {{did-insert this.setupComponent}} ...attributes>
2
+ <div class="mb-2 flex items-center justify-between">
3
+ <div class="flex items-center">
4
+ <div class="fleet-vehicle-listing-search">
5
+ <Input @type="text" {{on "keyup" (perform this.search)}} placeholder="Search vehicle in fleet" class="w-64 form-input form-input-sm" />
6
+ </div>
7
+
8
+ {{#if this.isLoading}}
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
+ {{#if @onAddVehicle}}
16
+ <ModelSelect @modelName="vehicle" @selectedModel={{@options.selectedVehicle}} @placeholder="Add vehicle to fleet" @triggerClass="form-select form-input form-select-sm form-input-sm" @infiniteScroll={{false}} @renderInPlace={{true}} @onChange={{this.onAdd}} as |model|>
17
+ {{model.display_name}}
18
+ </ModelSelect>
19
+ {{/if}}
20
+ </div>
21
+ </div>
22
+ <div class="bg-white border border-gray-200 rounded shadow-sm dark:bg-gray-800 dark:border-gray-900 text-xs">
23
+ <div class="w-full">
24
+ <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">
25
+ {{#if @selectable}}
26
+ <div></div>
27
+ {{/if}}
28
+ <div class="col-span-4 flex items-center">Vehicle</div>
29
+ <div class="col-span-7 flex items-center"></div>
30
+ </div>
31
+ </div>
32
+ <div class="h-48 overflow-y-scroll">
33
+ {{#unless this.isLoaded}}
34
+ <div class="flex text-center items-center justify-center p-4 dark:text-gray-100">
35
+ <Spinner class="mr-2" @iconClass="text-sky-500" />
36
+ <span>Loading fleet vehicle...</span>
37
+ </div>
38
+ {{/unless}}
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>
42
+ {{#if @selectable}}
43
+ <div class="flex items-center">
44
+ <Checkbox @value={{vehicle.selected}} @onToggle={{fn this.select 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
+ <img src={{vehicle.photo_url}} alt={{vehicle.display_name}} class="w-5 h-5" />
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.display_name}}</div>
57
+ </div>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ <div class="flex items-center justify-end">
62
+ {{#if @onRemoveVehicle}}
63
+ <a href="javascript:;" class="text-danger text-opacity-75" {{on "click" (fn this.onRemove vehicle)}}>
64
+ <FaIcon @icon="times" @prefix="fas" class="mr-1" />
65
+ <span>Remove</span>
66
+ </a>
67
+ {{/if}}
68
+ </div>
69
+ </div>
70
+ {{/each}}
71
+ </div>
72
+ </div>
73
+ </div>