@fleetbase/fleetops-engine 0.4.23 → 0.4.25

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 (42) hide show
  1. package/addon/components/admin/navigator-app.hbs +0 -76
  2. package/addon/components/admin/navigator-app.js +0 -58
  3. package/addon/components/driver-onboard-settings.hbs +29 -0
  4. package/addon/components/driver-onboard-settings.js +75 -0
  5. package/addon/components/entity-field-editing-settings.hbs +79 -0
  6. package/addon/components/entity-field-editing-settings.js +106 -0
  7. package/addon/components/layout/fleet-ops-sidebar/driver-listing.hbs +1 -1
  8. package/addon/components/layout/fleet-ops-sidebar/driver-listing.js +11 -0
  9. package/addon/components/layout/fleet-ops-sidebar.hbs +2 -3
  10. package/addon/components/layout/fleet-ops-sidebar.js +3 -0
  11. package/addon/routes/settings/navigator-app.js +3 -0
  12. package/addon/routes/settings.js +3 -0
  13. package/addon/routes.js +3 -0
  14. package/addon/styles/fleetops-engine.css +24 -0
  15. package/addon/templates/settings/navigator-app.hbs +11 -0
  16. package/addon/templates/settings.hbs +1 -0
  17. package/app/components/driver-onboard-settings.js +1 -0
  18. package/app/components/entity-field-editing-settings.js +1 -0
  19. package/app/routes/settings/navigator-app.js +1 -0
  20. package/app/routes/settings.js +1 -0
  21. package/app/templates/settings/navigator-app.js +1 -0
  22. package/app/templates/settings.js +1 -0
  23. package/composer.json +2 -2
  24. package/extension.json +1 -1
  25. package/package.json +2 -2
  26. package/server/src/Console/Commands/FixInvalidPolymorphicRelationTypeNamespaces.php +1 -1
  27. package/server/src/Http/Controllers/Api/v1/DriverController.php +8 -2
  28. package/server/src/Http/Controllers/Api/v1/NavigatorController.php +35 -0
  29. package/server/src/Http/Controllers/Api/v1/OrderController.php +2 -2
  30. package/server/src/Http/Controllers/Api/v1/OrganizationController.php +23 -5
  31. package/server/src/Http/Controllers/FleetOpsController.php +0 -1
  32. package/server/src/Http/Controllers/Internal/v1/DriverController.php +8 -4
  33. package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +8 -0
  34. package/server/src/Http/Controllers/Internal/v1/SettingController.php +51 -5
  35. package/server/src/Http/Requests/CreateContactRequest.php +1 -1
  36. package/server/src/Http/Requests/CreateEntityRequest.php +1 -1
  37. package/server/src/Http/Requests/CreateIssueRequest.php +1 -1
  38. package/server/src/Http/Requests/CreatePlaceRequest.php +1 -1
  39. package/server/src/Http/Requests/CreateVehicleRequest.php +1 -1
  40. package/server/src/Support/Utils.php +4 -4
  41. package/server/src/routes.php +7 -0
  42. package/translations/en-us.yaml +28 -3
@@ -5,80 +5,4 @@
5
5
  <InputInfo>{{t "fleet-ops.component.admin.navigator-app.message" htmlSafe=true companyName=@app.name}}</InputInfo>
6
6
  </Attach::Tooltip>
7
7
  </InputGroup>
8
- </ContentPanel>
9
-
10
- <ContentPanel @title={{t "fleet-ops.component.admin.navigator-app.settings"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
11
- <InputGroup>
12
- <div class="flex items-center">
13
- <Toggle @isToggled={{this.isEntityFieldsEditable}} @onToggle={{this.enableEditableEntityFields}} />
14
- <div class="ml-2">{{t "fleet-ops.component.admin.navigator-app.select-input"}}</div>
15
- </div>
16
- </InputGroup>
17
- {{#if this.isEntityFieldsEditable}}
18
- <OrderConfigManager @onConfigChanged={{this.onConfigChanged}} as |Action Context|>
19
- <div class="mt-2">
20
- <InputGroup @name="Select order config" @helpText="Apply entity editing settings for an order config.">
21
- <DropdownButton
22
- class="order-config-select-button mr-2"
23
- @disabled={{not Context.configs}}
24
- @text={{if Context.currentConfig.name Context.currentConfig.name (t "fleet-ops.component.order-config-manager.select-order-config")}}
25
- @textClass="text-sm mr-2"
26
- @buttonClass="flex-row-reverse w-44 justify-between"
27
- @icon="caret-down"
28
- @iconClass="mr-0i"
29
- @size="sm"
30
- @iconPrefix="fas"
31
- @triggerClass="hidden md:flex"
32
- as |dd|
33
- >
34
- <div class="next-dd-menu mt-1 mx-0" aria-labelledby="user-menu">
35
- <div class="p-1">
36
- {{#each Context.configs as |orderConfig|}}
37
- <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd Context.selectConfig orderConfig)}}>
38
- <div class="flex-1 flex flex-row items-center">
39
- <div class="w-6">
40
- <FaIcon @icon="cogs" />
41
- </div>
42
- <span>{{orderConfig.name}}</span>
43
- </div>
44
- <div>
45
- {{#if (eq Context.currentConfig.id orderConfig.id)}}
46
- <FaIcon @icon="check" class="text-green-500" />
47
- {{/if}}
48
- </div>
49
- </a>
50
- {{/each}}
51
- </div>
52
- </div>
53
- </DropdownButton>
54
- </InputGroup>
55
- </div>
56
- </OrderConfigManager>
57
- {{#if this.selectedOrderConfig}}
58
- <div class="bg-gray-400 border-gray-600 rounded-lg px-4 py-2 dark:bg-gray-700 dark:border-gray-800">
59
- {{#let (get (get this.entityEditingSettings this.selectedOrderConfig.id) "editable_entity_fields") as |editableEntityFields|}}
60
- {{#each this.entityFields as |entityField|}}
61
- <div class="mt-1">
62
- <Checkbox
63
- @value={{includes entityField editableEntityFields}}
64
- @label={{smart-humanize entityField}}
65
- @onToggle={{fn this.toggleFieldEditable entityField}}
66
- @helpText={{t "fleet-ops.component.admin.visibility-controls.checkbox-text"}}
67
- />
68
- </div>
69
- {{/each}}
70
- {{/let}}
71
- </div>
72
- <div class="mt-3 flex items-center">
73
- <Button
74
- @type="primary"
75
- @size="lg"
76
- @icon="save"
77
- @text={{t "fleet-ops.common.save-changes"}}
78
- @onClick={{perform this.saveEntityEditingSettings}}
79
- @isLoading={{not this.saveEntityEditingSettings.isIdle}}
80
- />
81
- </div>
82
- {{/if}}
83
- {{/if}}
84
8
  </ContentPanel>
@@ -1,62 +1,15 @@
1
1
  import Component from '@glimmer/component';
2
2
  import { tracked } from '@glimmer/tracking';
3
3
  import { inject as service } from '@ember/service';
4
- import { action } from '@ember/object';
5
- import { isArray } from '@ember/array';
6
4
  import { task } from 'ember-concurrency-decorators';
7
5
 
8
6
  export default class NavigatorAppControlsComponent extends Component {
9
7
  @service fetch;
10
- @tracked isLoading = false;
11
8
  @tracked url;
12
- @tracked selectedOrderConfig;
13
- @tracked entityFields = ['name', 'description', 'sku', 'height', 'width', 'length', 'weight', 'declared_value', 'sale_price'];
14
- @tracked entityEditingSettings = {};
15
- @tracked isEntityFieldsEditable = false;
16
9
 
17
10
  constructor() {
18
11
  super(...arguments);
19
12
  this.getAppLinkUrl.perform();
20
- this.getEntityEditableSettings.perform();
21
- }
22
-
23
- @action enableEditableEntityFields(isEntityFieldsEditable) {
24
- this.isEntityFieldsEditable = isEntityFieldsEditable;
25
- }
26
-
27
- @action onConfigChanged(orderConfig) {
28
- this.selectedOrderConfig = orderConfig;
29
- }
30
-
31
- @action toggleFieldEditable(fieldName, isEditable) {
32
- const editableFields = this.entityEditingSettings[this.selectedOrderConfig.id]?.editable_entity_fields;
33
- if (isArray(editableFields)) {
34
- if (isEditable) {
35
- editableFields.pushObject(fieldName);
36
- } else {
37
- editableFields.removeObject(fieldName);
38
- }
39
- } else {
40
- this.entityEditingSettings = {
41
- ...this.entityEditingSettings,
42
- [this.selectedOrderConfig.id]: {
43
- editable_entity_fields: [],
44
- },
45
- };
46
- return this.toggleFieldEditable(...arguments);
47
- }
48
-
49
- this.updateEditableEntityFieldsForOrderConfig(editableFields);
50
- }
51
-
52
- updateEditableEntityFieldsForOrderConfig(editableFields = [], orderConfig = null) {
53
- orderConfig = orderConfig === null ? this.selectedOrderConfig : orderConfig;
54
- this.entityEditingSettings = {
55
- ...this.entityEditingSettings,
56
- [orderConfig.id]: {
57
- editable_entity_fields: editableFields,
58
- },
59
- };
60
13
  }
61
14
 
62
15
  @task *getAppLinkUrl() {
@@ -66,15 +19,4 @@ export default class NavigatorAppControlsComponent extends Component {
66
19
  this.url = linkUrl;
67
20
  }
68
21
  }
69
-
70
- @task *getEntityEditableSettings() {
71
- const { entityEditingSettings, isEntityFieldsEditable } = yield this.fetch.get('fleet-ops/settings/entity-editing-settings');
72
- this.entityEditingSettings = entityEditingSettings;
73
- this.isEntityFieldsEditable = isEntityFieldsEditable;
74
- }
75
-
76
- @task *saveEntityEditingSettings() {
77
- const { entityEditingSettings, isEntityFieldsEditable } = this;
78
- yield this.fetch.post('fleet-ops/settings/entity-editing-settings', { entityEditingSettings, isEntityFieldsEditable });
79
- }
80
22
  }
@@ -0,0 +1,29 @@
1
+ <ContentPanel @title={{t "fleet-ops.component.driver-onboard-settings.driver-onboard-settings"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800 mb-4">
2
+ {{#if this.driverOnboardSettingsLoaded}}
3
+ <InputGroup>
4
+ <div class="flex items-center">
5
+ <Toggle @isToggled={{this.driverOnboardSettings.enableDriverOnboardFromApp}} @onToggle={{this.enableDriverOnboard}} @label={{t "fleet-ops.component.driver-onboard-settings.enable-driver-onboard-from-app"}} @helpText={{t "fleet-ops.component.driver-onboard-settings.enable-driver-onboard-from-app-help-text"}} />
6
+ </div>
7
+ </InputGroup>
8
+ {{#if this.driverOnboardSettings.enableDriverOnboardFromApp}}
9
+ <InputGroup @name={{t "fleet-ops.component.driver-onboard-settings.select-onboard-method"}} @helpText={{t "fleet-ops.component.driver-onboard-settings.select-onboard-method-help-text"}}>
10
+ <Select class="w-full flex-1" @value={{this.driverOnboardSettings.driverOnboardAppMethod}} @options={{this.driverOnboardMethods}} @placeholder={{t "fleet-ops.component.driver-onboard-settings.select-onboard-method"}} @onSelect={{this.selectDriverOnboardMethod}} />
11
+ </InputGroup>
12
+ <InputGroup>
13
+ <div class="flex items-center">
14
+ <Toggle @isToggled={{this.driverOnboardSettings.driverMustProvideOnboardDocuments}} @onToggle={{this.enableDriverOnboardDocuments}} @label={{t "fleet-ops.component.driver-onboard-settings.require-driver-to-upload-onboard-documents"}} @helpText={{t "fleet-ops.component.driver-onboard-settings.require-driver-to-upload-onboard-documents-help-text"}} />
15
+ </div>
16
+ </InputGroup>
17
+ {{#if this.driverOnboardSettings.driverMustProvideOnboardDocuments}}
18
+ <InputGroup>
19
+ <ArrayInput @data={{this.driverOnboardSettings.requiredOnboardDocuments}} @placeholder={{t "fleet-ops.component.driver-onboard-settings.enter-document-name"}} @onDataChanged={{this.onOnboardDocumentsChanged}} @addButtonText={{t "fleet-ops.component.driver-onboard-settings.add-onboard-document"}}>
20
+ <InputLabel @labelText={{t "fleet-ops.component.driver-onboard-settings.required-onboard-documents"}} @helpText={{t "fleet-ops.component.driver-onboard-settings.required-onboard-documents-help-text"}} />
21
+ </ArrayInput>
22
+ </InputGroup>
23
+ {{/if}}
24
+ {{/if}}
25
+ <div class="mt-3 flex items-center mb-4">
26
+ <Button @type="primary" @size="lg" @icon="save" @text={{t "fleet-ops.common.save-changes"}} @onClick={{perform this.saveDriverOnboardSettings}} @isLoading={{not this.saveDriverOnboardSettings.isIdle}} />
27
+ </div>
28
+ {{/if}}
29
+ </ContentPanel>
@@ -0,0 +1,75 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { action } from '@ember/object';
5
+ import { task } from 'ember-concurrency-decorators';
6
+
7
+ export default class DriverOnboardSettingsComponent extends Component {
8
+ @service fetch;
9
+ @service currentUser;
10
+ @tracked companyId;
11
+ @tracked driverOnboardSettingsLoaded = false;
12
+ @tracked driverOnboardSettings = {};
13
+ @tracked driverOnboardMethods = ['invite', 'button'];
14
+
15
+ constructor() {
16
+ super(...arguments);
17
+ this.companyId = this.currentUser.companyId;
18
+ this.getDriverOnboardSettings.perform();
19
+ }
20
+
21
+ @action enableDriverOnboard(enableDriverOnboardFromApp) {
22
+ this.updateDriverOnboardSettings({ enableDriverOnboardFromApp });
23
+ }
24
+
25
+ @action enableDriverOnboardDocuments(driverMustProvideOnboardDocuments) {
26
+ this.updateDriverOnboardSettings({ driverMustProvideOnboardDocuments });
27
+ }
28
+
29
+ @action selectDriverOnboardMethod(driverOnboardAppMethod) {
30
+ this.updateDriverOnboardSettings({ driverOnboardAppMethod });
31
+ }
32
+
33
+ @action onOnboardDocumentsChanged(requiredOnboardDocuments) {
34
+ requiredOnboardDocuments = requiredOnboardDocuments.filter((documentName) => typeof documentName === 'string');
35
+ this.updateDriverOnboardSettings({ requiredOnboardDocuments });
36
+ }
37
+
38
+ @task *saveDriverOnboardSettings() {
39
+ const { driverOnboardSettings } = this;
40
+ const driverOnboardSettingsResponse = yield this.fetch.post('fleet-ops/settings/driver-onboard-settings', { driverOnboardSettings });
41
+ if (driverOnboardSettings?.enableDriverOnboardFromApp == false) this.driverOnboardSettings = driverOnboardSettingsResponse?.driverOnboardSettings;
42
+ }
43
+
44
+ @task *getDriverOnboardSettings() {
45
+ const companyId = this.currentUser.companyId;
46
+ const { driverOnboardSettings } = yield this.fetch.get(`fleet-ops/settings/driver-onboard-settings/${companyId}`);
47
+ this.driverOnboardSettings = driverOnboardSettings;
48
+
49
+ if (this.companyDoesntHaveDriverOnboardSettings()) {
50
+ this.updateDriverOnboardSettings({
51
+ enableDriverOnboardFromApp: false,
52
+ driverOnboardAppMethod: 'invite',
53
+ driverMustProvideOnboardDocuments: false,
54
+ requiredOnboardDocuments: [],
55
+ });
56
+ }
57
+
58
+ this.driverOnboardSettingsLoaded = true;
59
+ }
60
+
61
+ companyDoesntHaveDriverOnboardSettings() {
62
+ const companyId = this.driverOnboardSettings.companyId;
63
+ return companyId === undefined;
64
+ }
65
+
66
+ updateDriverOnboardSettings(props = {}) {
67
+ const companyId = this.currentUser.companyId;
68
+ const driverOnboardSettings = this.driverOnboardSettings ?? {};
69
+ this.driverOnboardSettings = {
70
+ companyId: companyId,
71
+ ...driverOnboardSettings,
72
+ ...props,
73
+ };
74
+ }
75
+ }
@@ -0,0 +1,79 @@
1
+ <ContentPanel @title={{t "fleet-ops.component.entity-field-editing-settings.entitiy-field-editing-settings"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800 mb-4">
2
+ <OrderConfigManager @onConfigChanged={{this.onConfigChanged}} as |Action Context|>
3
+ <div>
4
+ <InputGroup
5
+ @name={{t "fleet-ops.component.entity-field-editing-settings.select-order-config"}}
6
+ @helpText={{t "fleet-ops.component.entity-field-editing-settings.select-order-config-help-text"}}
7
+ >
8
+ <DropdownButton
9
+ class="order-config-select-button mr-2"
10
+ @disabled={{not Context.configs}}
11
+ @text={{if Context.currentConfig.name Context.currentConfig.name (t "fleet-ops.component.entity-field-editing-settings.select-order-config")}}
12
+ @textClass="text-sm mr-2"
13
+ @buttonClass="flex-row-reverse w-44 justify-between"
14
+ @icon="caret-down"
15
+ @iconClass="mr-0i"
16
+ @size="sm"
17
+ @iconPrefix="fas"
18
+ @triggerClass="hidden md:flex"
19
+ as |dd|
20
+ >
21
+ <div class="next-dd-menu mt-1 mx-0" aria-labelledby="user-menu">
22
+ <div class="p-1">
23
+ {{#each Context.configs as |orderConfig|}}
24
+ <a href="javascript:;" class="next-dd-item" {{on "click" (dropdown-fn dd Context.selectConfig orderConfig)}}>
25
+ <div class="flex-1 flex flex-row items-center">
26
+ <div class="w-6">
27
+ <FaIcon @icon="cogs" />
28
+ </div>
29
+ <span>{{orderConfig.name}}</span>
30
+ </div>
31
+ <div>
32
+ {{#if (eq Context.currentConfig.id orderConfig.id)}}
33
+ <FaIcon @icon="check" class="text-green-500" />
34
+ {{/if}}
35
+ </div>
36
+ </a>
37
+ {{/each}}
38
+ </div>
39
+ </div>
40
+ </DropdownButton>
41
+ </InputGroup>
42
+ </div>
43
+ </OrderConfigManager>
44
+ {{#if this.selectedOrderConfig}}
45
+ {{#let (get this.entityEditingSettings this.selectedOrderConfig.id) as |orderConfigEntityEditingSettings|}}
46
+ <InputGroup>
47
+ <div class="flex items-center">
48
+ <Toggle
49
+ @isToggled={{orderConfigEntityEditingSettings.is_editable}}
50
+ @onToggle={{this.enableEditableEntityFields}}
51
+ @label={{t "fleet-ops.component.entity-field-editing-settings.enable-driver-to-edit-entity-fields"}}
52
+ @helpText={{t "fleet-ops.component.entity-field-editing-settings.enable-driver-to-edit-entity-fields-help-text"}}
53
+ />
54
+ </div>
55
+ </InputGroup>
56
+ {{#if orderConfigEntityEditingSettings.is_editable}}
57
+ <div class="bg-gray-400 border-gray-600 rounded-lg px-4 py-2 dark:bg-gray-700 dark:border-gray-800">
58
+ {{#let (get (get this.entityEditingSettings this.selectedOrderConfig.id) "editable_entity_fields") as |editableEntityFields|}}
59
+ {{#each this.entityFields as |entityField|}}
60
+ <div class="mt-1">
61
+ <Checkbox @value={{includes entityField editableEntityFields}} @label={{smart-humanize entityField}} @onToggle={{fn this.toggleFieldEditable entityField}} />
62
+ </div>
63
+ {{/each}}
64
+ {{/let}}
65
+ </div>
66
+ {{/if}}
67
+ <div class="mt-4 flex items-center">
68
+ <Button
69
+ @type="primary"
70
+ @size="lg"
71
+ @icon="save"
72
+ @text={{t "fleet-ops.common.save-changes"}}
73
+ @onClick={{perform this.saveEntityEditingSettings}}
74
+ @isLoading={{not this.saveEntityEditingSettings.isIdle}}
75
+ />
76
+ </div>
77
+ {{/let}}
78
+ {{/if}}
79
+ </ContentPanel>
@@ -0,0 +1,106 @@
1
+ import Component from '@glimmer/component';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { inject as service } from '@ember/service';
4
+ import { action } from '@ember/object';
5
+ import { isArray } from '@ember/array';
6
+ import { isNone } from '@ember/utils';
7
+ import { task } from 'ember-concurrency-decorators';
8
+
9
+ export default class EntityFieldEditingSettingsComponent extends Component {
10
+ @service notifications;
11
+ @service fetch;
12
+ @tracked selectedOrderConfig;
13
+ @tracked entityFields = ['name', 'description', 'sku', 'height', 'width', 'length', 'weight', 'declared_value', 'sale_price'];
14
+ @tracked entityEditingSettings = {};
15
+ @tracked settingsLoaded = false;
16
+
17
+ constructor() {
18
+ super(...arguments);
19
+ this.getEntityEditableSettings.perform();
20
+ }
21
+
22
+ @action onConfigChanged(orderConfig) {
23
+ if (!isNone(this.selectedOrderConfig) && this.orderConfigDoesntHaveSettings(orderConfig)) {
24
+ this.createSettingsForOrderConfig(orderConfig);
25
+ }
26
+ this.selectedOrderConfig = orderConfig;
27
+ }
28
+
29
+ @action enableEditableEntityFields(isEditable) {
30
+ const orderConfig = this.selectedOrderConfig;
31
+ if (orderConfig) {
32
+ if (this.orderConfigDoesntHaveSettings(orderConfig)) {
33
+ this.createSettingsForOrderConfig(orderConfig, isEditable);
34
+ } else {
35
+ const orderConfigSettings = this.entityEditingSettings[orderConfig.id] ?? {};
36
+ this.entityEditingSettings = {
37
+ ...this.entityEditingSettings,
38
+ [orderConfig.id]: {
39
+ ...orderConfigSettings,
40
+ is_editable: isEditable,
41
+ },
42
+ };
43
+ }
44
+ }
45
+ }
46
+
47
+ @action toggleFieldEditable(fieldName, isEditable) {
48
+ const editableFields = this.entityEditingSettings[this.selectedOrderConfig.id]?.editable_entity_fields;
49
+ if (isArray(editableFields)) {
50
+ if (isEditable) {
51
+ editableFields.pushObject(fieldName);
52
+ } else {
53
+ editableFields.removeObject(fieldName);
54
+ }
55
+ } else {
56
+ this.entityEditingSettings = {
57
+ ...this.entityEditingSettings,
58
+ [this.selectedOrderConfig.id]: {
59
+ ...this.entityEditingSettings[this.selectedOrderConfig.id],
60
+ editable_entity_fields: [],
61
+ },
62
+ };
63
+ return this.toggleFieldEditable(...arguments);
64
+ }
65
+
66
+ this.updateEditableEntityFieldsForOrderConfig(editableFields);
67
+ }
68
+
69
+ @task *getEntityEditableSettings() {
70
+ const { entityEditingSettings } = yield this.fetch.get('fleet-ops/settings/entity-editing-settings');
71
+ this.entityEditingSettings = entityEditingSettings;
72
+ this.settingsLoaded = true;
73
+ }
74
+
75
+ @task *saveEntityEditingSettings() {
76
+ const { entityEditingSettings } = this;
77
+ yield this.fetch.post('fleet-ops/settings/entity-editing-settings', { entityEditingSettings });
78
+ }
79
+
80
+ orderConfigDoesntHaveSettings(orderConfig) {
81
+ return isNone(this.entityEditingSettings[orderConfig.id]);
82
+ }
83
+
84
+ createSettingsForOrderConfig(orderConfig, isEditable = false) {
85
+ if (this.orderConfigDoesntHaveSettings(orderConfig)) {
86
+ this.entityEditingSettings = {
87
+ ...this.entityEditingSettings,
88
+ [orderConfig.id]: {
89
+ editable_entity_fields: [],
90
+ is_editable: isEditable,
91
+ },
92
+ };
93
+ }
94
+ }
95
+
96
+ updateEditableEntityFieldsForOrderConfig(editableFields = [], orderConfig = null) {
97
+ orderConfig = orderConfig === null ? this.selectedOrderConfig : orderConfig;
98
+ this.entityEditingSettings = {
99
+ ...this.entityEditingSettings,
100
+ [orderConfig.id]: {
101
+ ...this.entityEditingSettings[orderConfig.id],
102
+ editable_entity_fields: editableFields,
103
+ },
104
+ };
105
+ }
106
+ }
@@ -1,4 +1,4 @@
1
- <Layout::Sidebar::Panel @open={{true}} @title={{@title}} @titleIcon={{@icon}} @hideCaret={{true}} @toggleOnCaretOnly={{true}} @onClickPanelTitle={{this.transitionToRoute}} @wrapperClass="next-driver-listing">
1
+ <Layout::Sidebar::Panel @open={{true}} @title={{@title}} @titleIcon={{@icon}} @hideCaret={{true}} @toggleOnCaretOnly={{true}} @onClickPanelTitle={{this.transitionToRoute}} @wrapperClass="next-driver-listing" @dropdownButton={{this.displayPanelDropdown}} @dropdownButtonActions={{this.panelDropdownButtonActions}} @dropdownButtonRenderInPlace={{false}} @dropdownHorizontalPosition="left" @dropdownButtonMenuLabel={{t "fleet-ops.component.layout.fleet-ops-sidebar.drivers"}}>
2
2
  {{#each this.drivers as |driver|}}
3
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}}
@@ -18,6 +18,17 @@ export default class LayoutFleetOpsSidebarDriverListingComponent extends Compone
18
18
  this.fetchDrivers.perform();
19
19
  }
20
20
 
21
+ displayPanelDropdown = true;
22
+ panelDropdownButtonActions = [
23
+ {
24
+ label: 'Create new driver...',
25
+ onClick: () => {
26
+ const driver = this.store.createRecord('driver');
27
+ this.contextPanel.focus(driver, 'editing');
28
+ },
29
+ },
30
+ ];
31
+
21
32
  dropdownButtonActions = [
22
33
  {
23
34
  label: 'View driver details...',
@@ -9,7 +9,7 @@
9
9
  {{/if}}
10
10
  {{/each}}
11
11
  {{#each this.menuPanels as |menuPanel|}}
12
- <Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}}>
12
+ <Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}} @titleIcon={{menuPanel.icon}} @hideCaret={{menuPanel.hideCaret}} @toggleOnCaretOnly={{menuPanel.toggleOnCaretOnly}} @onClickPanelTitle={{menuPanel.onClickPanelTitle}} @wrapperClass={{menuPanel.wrapperClass}} @dropdownButton={{menuPanel.dropdownButton}} @dropdownButtonActions={{menuPanel.dropdownButtonActions}} @dropdownButtonRenderInPlace={{menuPanel.dropdownButtonRenderInPlace}} @dropdownHorizontalPosition={{menuPanel.dropdownHorizontalPosition}} @dropdownButtonMenuLabel={{menuPanel.dropdownButtonMenuLabel}}>
13
13
  {{#each menuPanel.items as |menuItem|}}
14
14
  {{#if menuItem.renderComponentInPlace}}
15
15
  {{component menuItem.component menuItem=menuItem title=menuItem.title onClick=menuItem.onClick 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}}
@@ -20,12 +20,11 @@
20
20
  </Layout::Sidebar::Panel>
21
21
  {{/each}}
22
22
  {{#each this.universeMenuPanels as |menuPanel|}}
23
- <Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}}>
23
+ <Layout::Sidebar::Panel @open={{menuPanel.open}} @title={{menuPanel.title}} @titleIcon={{menuPanel.icon}} @hideCaret={{menuPanel.hideCaret}} @toggleOnCaretOnly={{menuPanel.toggleOnCaretOnly}} @onClickPanelTitle={{menuPanel.onClickPanelTitle}} @wrapperClass={{menuPanel.wrapperClass}} @dropdownButton={{menuPanel.dropdownButton}} @dropdownButtonActions={{menuPanel.dropdownButtonActions}} @dropdownButtonRenderInPlace={{menuPanel.dropdownButtonRenderInPlace}} @dropdownHorizontalPosition={{menuPanel.dropdownHorizontalPosition}} @dropdownButtonMenuLabel={{menuPanel.dropdownButtonMenuLabel}}>
24
24
  {{#each menuPanel.items as |menuItem|}}
25
25
  <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>
26
26
  {{/each}}
27
27
  </Layout::Sidebar::Panel>
28
28
  {{/each}}
29
- {{!-- <Layout::Sidebar::Item @onClick={{this.onClickSettings}} @icon="cogs">{{t "fleet-ops.component.layout.fleet-ops-sidebar.settings"}}</Layout::Sidebar::Item> --}}
30
29
  {{yield}}
31
30
  <Spacer @height="10px" />
@@ -66,6 +66,8 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
66
66
  { title: this.intl.t('fleet-ops.component.layout.fleet-ops-sidebar.issues'), icon: 'triangle-exclamation', route: 'management.issues' },
67
67
  ];
68
68
 
69
+ const settingsItems = [{ title: this.intl.t('fleet-ops.component.layout.fleet-ops-sidebar.navigator-app'), icon: 'location-arrow', route: 'settings.navigator-app' }];
70
+
69
71
  const createPanel = (title, routePrefix, items = []) => ({
70
72
  title,
71
73
  open: true,
@@ -81,6 +83,7 @@ export default class LayoutFleetOpsSidebarComponent extends Component {
81
83
  this.menuPanels = [
82
84
  createPanel(this.intl.t('fleet-ops.component.layout.fleet-ops-sidebar.operations'), 'operations', operationsItems),
83
85
  createPanel(this.intl.t('fleet-ops.component.layout.fleet-ops-sidebar.resources'), 'management', resourcesItems),
86
+ createPanel(this.intl.t('fleet-ops.component.layout.fleet-ops-sidebar.settings'), 'settings', settingsItems),
84
87
  ].filter((panel) => {
85
88
  const isVisible = panel.visible && panel.items.length > 0;
86
89
  return isVisible;
@@ -0,0 +1,3 @@
1
+ import Route from '@ember/routing/route';
2
+
3
+ export default class SettingsNavigatorAppRoute extends Route {}
@@ -0,0 +1,3 @@
1
+ import Route from '@ember/routing/route';
2
+
3
+ export default class SettingsRoute extends Route {}
package/addon/routes.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import buildRoutes from 'ember-engines/routes';
2
2
 
3
3
  export default buildRoutes(function () {
4
+ this.route('settings', function () {
5
+ this.route('navigator-app');
6
+ });
4
7
  this.route('virtual', { path: '/:slug/:view' });
5
8
  this.route('operations', { path: '/' }, function () {
6
9
  this.route('dispatch');
@@ -61,6 +61,30 @@ body[data-theme='dark'] .scheduler-left-sidebar {
61
61
  padding-left: 3.5rem;
62
62
  }
63
63
 
64
+ /** content panel dropdown button */
65
+ .next-sidebar .next-sidebar-panel-container.next-driver-listing > .next-sidebar-panel > .next-content-panel > .next-content-panel-header.next-sidebar-panel-toggle {
66
+ padding-right: 0.25rem;
67
+ }
68
+
69
+ .next-sidebar
70
+ .next-sidebar-panel-container.next-driver-listing
71
+ > .next-sidebar-panel
72
+ > .next-content-panel
73
+ > .next-content-panel-header.next-sidebar-panel-toggle
74
+ .ember-basic-dropdown
75
+ button,
76
+ .next-sidebar
77
+ .next-sidebar-panel-container.next-driver-listing
78
+ > .next-sidebar-panel
79
+ > .next-content-panel
80
+ > .next-content-panel-header.next-sidebar-panel-toggle
81
+ .ember-basic-dropdown-trigger
82
+ button {
83
+ padding: 0.15rem 0.625rem;
84
+ font-size: 10px;
85
+ line-height: 0.5;
86
+ }
87
+
64
88
  .multi-drop-select-container .fleetbase-model-select.fleetbase-power-select.ember-model-select > .ember-model-select__loading {
65
89
  background: none;
66
90
  border: none;
@@ -0,0 +1,11 @@
1
+ <Layout::Section::Header @title={{t "fleet-ops.settings.navigator-app.navigator-app-settings"}} />
2
+
3
+ <Layout::Section::Body class="overflow-y-scroll h-full">
4
+ <div class="container mx-auto h-screen">
5
+ <div class="max-w-3xl my-10 mx-auto space-y-6">
6
+ <EntityFieldEditingSettings />
7
+ <DriverOnboardSettings />
8
+ </div>
9
+ </div>
10
+ <Spacer @height="600px" />
11
+ </Layout::Section::Body>
@@ -0,0 +1 @@
1
+ {{outlet}}
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/driver-onboard-settings';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/components/entity-field-editing-settings';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/settings/navigator-app';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/routes/settings';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/settings/navigator-app';
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/templates/settings';
package/composer.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbase/fleetops-api",
3
- "version": "0.4.23",
3
+ "version": "0.4.25",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "keywords": [
6
6
  "fleetbase-extension",
@@ -22,7 +22,7 @@
22
22
  ],
23
23
  "require": {
24
24
  "php": "^8.0",
25
- "fleetbase/core-api": "^1.4.15",
25
+ "fleetbase/core-api": "^1.4.16",
26
26
  "barryvdh/laravel-dompdf": "^2.0",
27
27
  "brick/geo": "0.7.2",
28
28
  "cknow/laravel-money": "^7.1",
package/extension.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Fleet-Ops",
3
- "version": "0.4.23",
3
+ "version": "0.4.25",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "repository": "https://github.com/fleetbase/fleetops",
6
6
  "license": "MIT",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleetbase/fleetops-engine",
3
- "version": "0.4.23",
3
+ "version": "0.4.25",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "fleetbase": {
6
6
  "route": "fleet-ops"
@@ -43,7 +43,7 @@
43
43
  "dependencies": {
44
44
  "@babel/core": "^7.23.2",
45
45
  "@fleetbase/ember-core": "^0.2.8",
46
- "@fleetbase/ember-ui": "^0.2.11",
46
+ "@fleetbase/ember-ui": "^0.2.12",
47
47
  "@fleetbase/fleetops-data": "^0.1.14",
48
48
  "@fleetbase/leaflet-routing-machine": "^3.2.16",
49
49
  "@fortawesome/ember-fontawesome": "^0.4.1",
@@ -36,7 +36,7 @@ class FixInvalidPolymorphicRelationTypeNamespaces extends Command
36
36
  ['model' => \Fleetbase\FleetOps\Models\Order::class, 'columns' => ['customer_type', 'facilitator_type']],
37
37
  ['model' => \Fleetbase\FleetOps\Models\Place::class, 'columns' => ['owner_type']],
38
38
  ['model' => \Fleetbase\FleetOps\Models\Entity::class, 'columns' => ['customer_type']],
39
- ['model' => \Fleetbase\FleetOps\Models\PurchaseRate::class, 'columns' => ['customer_type']]
39
+ ['model' => \Fleetbase\FleetOps\Models\PurchaseRate::class, 'columns' => ['customer_type']],
40
40
  ];
41
41
 
42
42
  foreach ($models as $modelConfig) {
@@ -44,6 +44,9 @@ class DriverController extends Controller
44
44
  // get request input
45
45
  $input = $request->except(['name', 'password', 'email', 'phone', 'location', 'altitude', 'heading', 'speed', 'meta']);
46
46
 
47
+ // Add default status
48
+ $input['status'] = 'active';
49
+
47
50
  // get user details for driver
48
51
  $userDetails = $request->only(['name', 'password', 'email', 'phone', 'timezone']);
49
52
 
@@ -145,7 +148,10 @@ class DriverController extends Controller
145
148
  $userDetails = $request->only(['name', 'password', 'email', 'phone']);
146
149
 
147
150
  // update driver user details
148
- $driver->user->update($userDetails);
151
+ $driverUser = $driver->getUser();
152
+ if ($driverUser) {
153
+ $driverUser->update($userDetails);
154
+ }
149
155
 
150
156
  // vehicle assignment public_id -> uuid
151
157
  if ($request->has('vehicle')) {
@@ -773,4 +779,4 @@ class DriverController extends Controller
773
779
 
774
780
  return $phone;
775
781
  }
776
- }
782
+ }
@@ -0,0 +1,35 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\FleetOps\Http\Controllers\Api\v1;
4
+
5
+ use Fleetbase\Http\Controllers\Controller;
6
+ use Fleetbase\Models\Setting;
7
+
8
+ class NavigatorController extends Controller
9
+ {
10
+ /**
11
+ * Retrieve the driver onboard settings.
12
+ *
13
+ * This method retrieves the driver onboard settings for the current company session. If no company session
14
+ * is found in the request, an error response is returned. The method retrieves the company ID from the session,
15
+ * then fetches the saved driver onboard settings. If settings for the current company are found, they are returned,
16
+ * otherwise, default settings are provided.
17
+ *
18
+ * @return \Illuminate\Http\JsonResponse
19
+ */
20
+
21
+ /**
22
+ * Retrieve driver onboard settings.
23
+ *
24
+ * @return \Illuminate\Http\JsonResponse
25
+ */
26
+ public function getDriverOnboardSettings($companyId)
27
+ {
28
+ $driverOnboardSettings = Setting::where('key', 'fleet-ops.driver-onboard-settings.' . $companyId)->value('value');
29
+ if (!$driverOnboardSettings) {
30
+ $driverOnboardSettings = [];
31
+ }
32
+
33
+ return response()->json(['driverOnboardSettings' => $driverOnboardSettings]);
34
+ }
35
+ }
@@ -498,7 +498,7 @@ class OrderController extends Controller
498
498
 
499
499
  if ($request->filled('on')) {
500
500
  $on = Carbon::parse($request->input('on'));
501
-
501
+
502
502
  $query->where(function ($q) use ($on) {
503
503
  $q->whereDate('created_at', $on);
504
504
  $q->orWhereDate('scheduled_at', $on);
@@ -1408,4 +1408,4 @@ class OrderController extends Controller
1408
1408
 
1409
1409
  return response()->json($entityEditingSettings);
1410
1410
  }
1411
- }
1411
+ }
@@ -5,6 +5,8 @@ namespace Fleetbase\FleetOps\Http\Controllers\Api\v1;
5
5
  use Fleetbase\Http\Controllers\Controller;
6
6
  use Fleetbase\Http\Resources\Organization;
7
7
  use Fleetbase\Models\Company;
8
+ use Fleetbase\Models\Setting;
9
+ use Illuminate\Http\Request;
8
10
 
9
11
  class OrganizationController extends Controller
10
12
  {
@@ -13,15 +15,31 @@ class OrganizationController extends Controller
13
15
  *
14
16
  * @return Organization
15
17
  */
16
- public function listOrganizations()
18
+ public function listOrganizations(Request $request)
17
19
  {
18
- $companies = Company::whereHas('users')->take(10)->get()->map(function ($company) {
20
+ $limit = $request->input('limit', 10);
21
+ $withDriverOnboardEnabled = $request->boolean('with_driver_onboard');
22
+
23
+ $companies = Company::whereHas('users')->get()->map(function ($company) {
19
24
  return [
20
- 'name' => $company->name,
21
- 'id' => $company->public_id,
25
+ 'name' => $company->name,
26
+ 'uuid' => $company->uuid,
22
27
  ];
23
28
  });
24
29
 
25
- return response()->json($companies);
30
+ if ($withDriverOnboardEnabled) {
31
+ $driverOnboardSettings = Setting::where('key', 'fleet-ops.driver-onboard-settings')->value('value');
32
+
33
+ $companies = $companies->filter(function ($company) use ($driverOnboardSettings) {
34
+ return $driverOnboardSettings && isset($driverOnboardSettings[$company['uuid']]) && data_get($driverOnboardSettings[$company['uuid']], 'enableDriverOnboardFromApp') === true;
35
+ });
36
+ }
37
+
38
+ // limit
39
+ $companies = $companies->take($limit);
40
+
41
+ $companiesArray = $companies->values()->toArray();
42
+
43
+ return response()->json($companiesArray);
26
44
  }
27
45
  }
@@ -2,7 +2,6 @@
2
2
 
3
3
  namespace Fleetbase\FleetOps\Http\Controllers;
4
4
 
5
- use Fleetbase\FleetOps\Models\Order;
6
5
  use Fleetbase\Http\Controllers\FleetbaseController;
7
6
 
8
7
  class FleetOpsController extends FleetbaseController
@@ -255,14 +255,18 @@ class DriverController extends FleetOpsController
255
255
  }
256
256
  $input = $input->except(['name', 'password', 'email', 'phone', 'meta', 'avatar_uuid', 'photo_uuid'])->toArray();
257
257
 
258
- $driver->user->update($userInput);
259
- $driver->flushAttributesCache();
258
+ // Update driver user details
259
+ $driverUser = $driver->getUser();
260
+ if ($driverUser) {
261
+ $driverUser->update($userInput);
262
+ $input['slug'] = $driverUser->slug;
263
+ }
260
264
 
261
- $input['slug'] = $driver->user->slug;
265
+ // Flush cache
266
+ $driver->flushAttributesCache();
262
267
  },
263
268
  function ($request, &$driver) {
264
269
  $driver->load(['user']);
265
-
266
270
  if ($driver->user) {
267
271
  $driver->user->setHidden(['driver']);
268
272
  }
@@ -6,6 +6,7 @@ use Fleetbase\Http\Controllers\Controller;
6
6
  use Fleetbase\Http\Resources\Organization;
7
7
  use Fleetbase\Models\ApiCredential;
8
8
  use Fleetbase\Models\Company;
9
+ use Fleetbase\Models\Setting;
9
10
  use Fleetbase\Models\User;
10
11
  use Illuminate\Http\Request;
11
12
  use Illuminate\Support\Str;
@@ -76,4 +77,11 @@ class NavigatorController extends Controller
76
77
 
77
78
  return new Organization($organization);
78
79
  }
80
+
81
+ public function getDriverOnboardSettings()
82
+ {
83
+ $onBoardSettings = Setting::where('key', 'fleet-ops.driver-onboard')->value('value');
84
+
85
+ return response()->json($onBoardSettings);
86
+ }
79
87
  }
@@ -48,23 +48,69 @@ class SettingController extends Controller
48
48
  return response()->json(['visibilitySettings' => $visibilitySettings]);
49
49
  }
50
50
 
51
+ /**
52
+ * Save entity editing settings.
53
+ *
54
+ * @return \Illuminate\Http\JsonResponse
55
+ */
51
56
  public function saveEntityEditingSettings(Request $request)
52
57
  {
53
58
  $entityEditingSettings = $request->input('entityEditingSettings', []);
54
- $isEntityFieldsEditable = $request->boolean('isEntityFieldsEditable');
55
59
 
56
60
  // Save entity editing settings
57
61
  Setting::configure('fleet-ops.entity-editing-settings', $entityEditingSettings);
58
- Setting::configure('fleet-ops.entity-fields-editable', $isEntityFieldsEditable);
59
62
 
60
- return response()->json(['entityEditingSettings' => $entityEditingSettings, 'isEntityFieldsEditable' => $isEntityFieldsEditable]);
63
+ return response()->json(['entityEditingSettings' => $entityEditingSettings]);
61
64
  }
62
65
 
66
+ /**
67
+ * Retrieve entity editing settings.
68
+ *
69
+ * @return \Illuminate\Http\JsonResponse
70
+ */
63
71
  public function getEntityEditingSettings()
64
72
  {
65
73
  $entityEditingSettings = Setting::where('key', 'fleet-ops.entity-editing-settings')->value('value');
66
- $isEntityFieldsEditable = Setting::where('key', 'fleet-ops.entity-fields-editable')->value('value');
74
+ if (!$entityEditingSettings) {
75
+ $entityEditingSettings = [];
76
+ }
77
+
78
+ return response()->json(['entityEditingSettings' => $entityEditingSettings]);
79
+ }
80
+
81
+ /**
82
+ * Retrieve driver onboard settings.
83
+ *
84
+ * @return \Illuminate\Http\JsonResponse
85
+ */
86
+ public function getDriverOnboardSettings($companyId)
87
+ {
88
+ $driverOnboardSettings = Setting::where('key', 'fleet-ops.driver-onboard-settings.' . $companyId)->value('value');
89
+ if (!$driverOnboardSettings) {
90
+ $driverOnboardSettings = [];
91
+ }
92
+
93
+ return response()->json(['driverOnboardSettings' => $driverOnboardSettings]);
94
+ }
95
+
96
+ /**
97
+ * Save driver onboard settings.
98
+ *
99
+ * @return \Illuminate\Http\JsonResponse
100
+ */
101
+ public function savedDriverOnboardSettings(Request $request)
102
+ {
103
+ $driverOnboardSettings = $request->input('driverOnboardSettings', []);
104
+
105
+ if ($driverOnboardSettings['enableDriverOnboardFromApp'] == false) {
106
+ $driverOnboardSettings['driverMustProvideOnboardDoucments'] = false;
107
+ $driverOnboardSettings['requiredOnboardDocuments'] = [];
108
+ $driverOnboardSettings['driverOnboardAppMethod'] = '';
109
+ $driverOnboardSettings['enableDriverOnboardFromApp'] = false;
110
+ }
111
+
112
+ Setting::configure('fleet-ops.driver-onboard-settings.' . $driverOnboardSettings['companyId'], $driverOnboardSettings);
67
113
 
68
- return response()->json(['entityEditingSettings' => $entityEditingSettings, 'isEntityFieldsEditable' => $isEntityFieldsEditable]);
114
+ return response()->json(['driverOnboardSettings' => $driverOnboardSettings]);
69
115
  }
70
116
  }
@@ -14,7 +14,7 @@ class CreateContactRequest extends FleetbaseRequest
14
14
  */
15
15
  public function authorize()
16
16
  {
17
- return request()->session()->has('storefront_key') || request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');;
17
+ return request()->session()->has('storefront_key') || request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');
18
18
  }
19
19
 
20
20
  /**
@@ -14,7 +14,7 @@ class CreateEntityRequest extends FleetbaseRequest
14
14
  */
15
15
  public function authorize()
16
16
  {
17
- return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');;
17
+ return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');
18
18
  }
19
19
 
20
20
  /**
@@ -13,7 +13,7 @@ class CreateIssueRequest extends FleetbaseRequest
13
13
  */
14
14
  public function authorize()
15
15
  {
16
- return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');;
16
+ return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');
17
17
  }
18
18
 
19
19
  /**
@@ -16,7 +16,7 @@ class CreatePlaceRequest extends FleetbaseRequest
16
16
  */
17
17
  public function authorize()
18
18
  {
19
- return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');;
19
+ return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');
20
20
  }
21
21
 
22
22
  /**
@@ -14,7 +14,7 @@ class CreateVehicleRequest extends FleetbaseRequest
14
14
  */
15
15
  public function authorize()
16
16
  {
17
- return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');;
17
+ return request()->session()->has('api_credential') || request()->session()->has('is_sanctum_token');
18
18
  }
19
19
 
20
20
  /**
@@ -851,8 +851,8 @@ class Utils extends FleetbaseUtils
851
851
  * Calculates driving distance and time between two points using Vincenty's formula.
852
852
  * Returns distance in meters and time in seconds.
853
853
  *
854
- * @param \Fleetbase\FleetOps\Models\Place|\Fleetbase\LaravelMysqlSpatial\Types\Point|array $origin
855
- * @param \Fleetbase\FleetOps\Models\Place|\Fleetbase\LaravelMysqlSpatial\Types\Point|array $destination
854
+ * @param \Fleetbase\FleetOps\Models\Place|Point|array $origin
855
+ * @param \Fleetbase\FleetOps\Models\Place|Point|array $destination
856
856
  */
857
857
  public static function calculateDrivingDistanceAndTime($origin, $destination): DistanceMatrix
858
858
  {
@@ -870,8 +870,8 @@ class Utils extends FleetbaseUtils
870
870
  * Calculates driving distance and time between two points using Vincenty's formula.
871
871
  * Returns distance in meters and time in seconds.
872
872
  *
873
- * @param \Fleetbase\FleetOps\Models\Place|\Fleetbase\LaravelMysqlSpatial\Types\Point|array $origin
874
- * @param \Fleetbase\FleetOps\Models\Place|\Fleetbase\LaravelMysqlSpatial\Types\Point|array $destination
873
+ * @param \Fleetbase\FleetOps\Models\Place|Point|array $origin
874
+ * @param \Fleetbase\FleetOps\Models\Place|Point|array $destination
875
875
  */
876
876
  public static function getPreliminaryDistanceMatrix($origin, $destination): DistanceMatrix
877
877
  {
@@ -179,6 +179,11 @@ Route::prefix(config('fleetops.api.routing.prefix', null))->namespace('Fleetbase
179
179
  $router->group(['prefix' => 'labels'], function () use ($router) {
180
180
  $router->get('{id}', 'LabelController@getLabel');
181
181
  });
182
+
183
+ // navigator routes
184
+ $router->group(['prefix' => 'onboard'], function () use ($router) {
185
+ $router->get('driver-onboard-settings/{companyId}', 'NavigatorController@getDriverOnboardSettings');
186
+ });
182
187
  });
183
188
 
184
189
  /*
@@ -435,6 +440,8 @@ Route::prefix(config('fleetops.api.routing.prefix', null))->namespace('Fleetbase
435
440
  $router->post('visibility', 'SettingController@saveVisibilitySettings');
436
441
  $router->get('entity-editing-settings', 'SettingController@getEntityEditingSettings');
437
442
  $router->post('entity-editing-settings', 'SettingController@saveEntityEditingSettings');
443
+ $router->post('driver-onboard-settings', 'SettingController@savedDriverOnboardSettings');
444
+ $router->get('driver-onboard-settings/{companyId}', 'SettingController@getDriverOnboardSettings');
438
445
  }
439
446
  );
440
447
  $router->group(
@@ -94,7 +94,6 @@ fleet-ops:
94
94
  total: Total
95
95
  back: Back
96
96
  done: Done
97
-
98
97
  component:
99
98
  activity-logic-builder:
100
99
  activity-logic: Activity Logic
@@ -238,7 +237,11 @@ fleet-ops:
238
237
  message: Use this URL to link the official Navigator app to this {companyName} instance. Opening this URL on a mobile device will open the Navigator app and update it's configuration and branding.
239
238
  settings: Entity Settings
240
239
  select-input: Allow driver to update entity details
241
-
240
+ driver-settings: Driver Settings
241
+ description: Enable driver on-board
242
+ upload-document: Require driver to upload documents
243
+ upload-body: Add documents
244
+ document: Document
242
245
  visibility-controls:
243
246
  title: Visibility Controls
244
247
  message: Visibility controls allow you to disable sections of Fleet-Ops. Toggle the checkbox to enable or disable sections to hide in Fleet-ops.
@@ -249,6 +252,25 @@ fleet-ops:
249
252
  vehicles : Vehicles
250
253
  drivers : Drivers
251
254
  places : Places
255
+ entity-field-editing-settings:
256
+ entitiy-field-editing-settings: Entity Field Editing Settings
257
+ entity-field-editing-settings-help-text: These settings determine which fields of an entity are editable by a driver via Navigator App
258
+ select-order-config: Select Order Config
259
+ select-order-config-help-text: Select an order config which these settings will apply to
260
+ enable-driver-to-edit-entity-fields: Allow driver to edit entity details
261
+ enable-driver-to-edit-entity-fields-help-text: Enabling this toggle grants the driver permission to modify specific entity fields chosen below.
262
+ driver-onboard-settings:
263
+ driver-onboard-settings: Driver Onboard Settings
264
+ enable-driver-onboard-from-app: Enable driver onboard from Navigator App
265
+ enable-driver-onboard-from-app-help-text: Enabling this setting allows drivers to independently onboard (create their own account) via the Navigator App.
266
+ select-onboard-method: Select driver onboard method
267
+ select-onboard-method-help-text: This setting determines how drivers are permitted to create their accounts through the Navigator App. Choose 'Invite' if drivers need to receive an email invitation to create their account. Select 'Button' if you wish to enable a button within the app that allows anyone to create a driver account.
268
+ require-driver-to-upload-onboard-documents: Require driver to upload onboard documents
269
+ require-driver-to-upload-onboard-documents-help-text: This setting enforces documents that a driver must provide before their account can be created.
270
+ required-onboard-documents: Required onboard documents
271
+ required-onboard-documents-help-text: Input all the onboard documents required for a driver to provide below using the "Add onboard document" button.
272
+ enter-document-name: Enter document name
273
+ add-onboard-document: Add onboard document
252
274
  cell:
253
275
  driver-name:
254
276
  not-assigned: No driver assigned
@@ -265,6 +287,7 @@ fleet-ops:
265
287
  loading-vehicle: Loading fleet vehicles...
266
288
  layout:
267
289
  fleet-ops-sidebar:
290
+ navigator-app: Navigator App
268
291
  resources: Resources
269
292
  operations: Operations
270
293
  dashboard: Dashboard
@@ -1511,4 +1534,6 @@ fleet-ops:
1511
1534
  zone-label: Zone
1512
1535
  zone-help-text: Restrict this service to order request originating from a specific zone.
1513
1536
  zone-placeholder: Restrict to zone
1514
-
1537
+ settings:
1538
+ navigator-app:
1539
+ navigator-app-settings: Navigator App Settings