@fleetbase/fleetops-engine 0.4.6 → 0.4.8

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.
@@ -105,12 +105,12 @@ export default class LayoutFleetOpsSidebarFleetListingComponent extends Componen
105
105
  listenForChanges() {
106
106
  // when a vehicle is assigned/ or unassigned reload
107
107
  this.universe.on('fleet.vehicle.assigned', () => {
108
- this.loadFleetsWithVehicles();
108
+ this.fetchFleets.perform();
109
109
  });
110
110
 
111
111
  // when a vehicle is assigned/ or unassigned reload
112
112
  this.universe.on('fleet.vehicle.unassigned', () => {
113
- this.loadFleetsWithVehicles();
113
+ this.fetchFleets.perform();
114
114
  });
115
115
  }
116
116
 
@@ -1,41 +1,42 @@
1
- <div class="live-map-component {{@wrapperClass}}" {{did-insert this.setupComponent}}>
2
- <LeafletMap id={{this.mapId}} class={{@mapClass}} @lat={{this.latitude}} @lng={{this.longitude}} @zoom={{this.zoom}} @zoomControl={{@zoomControl}} @contextmenu={{true}} @contextmenuWidth={{140}} @contextmenuItems={{this.contextMenuItems}} @onLoad={{this.setupMap}} {{will-destroy this.closeChannels}} ...attributes as |layers|>
3
- <layers.tile @url={{this.tileSourceUrl}} />
4
- {{#if this.visibilityControls.drivers}}
5
- {{#each this.drivers as |driver|}}
6
- <layers.drift-marker @id={{driver.id}} @rotationAngle={{driver.heading}} @duration={{300}} @icon={{icon iconUrl=(or driver.vehicle_avatar (config "defaultValues.vehicleAvatar")) iconSize=(array 24 24)}} @location={{point-to-coordinates driver.location}} @publicId={{driver.public_id}} @onAdd={{fn this.triggerAction "onDriverAdded" driver}} @onClick={{fn this.triggerAction "onDriverClicked" driver}} as |marker|>
7
- <marker.popup @maxWidth="500" @minWidth="225">
8
- <DriverCard @driver={{driver}} @showCoordinates={{true}} @textClass="text-gray-900 dark:text-gray-100" />
9
- </marker.popup>
10
- <marker.tooltip @permanent={{false}} @sticky={{true}}>{{driver.name}}</marker.tooltip>
11
- </layers.drift-marker>
12
- {{/each}}
13
- {{/if}}
1
+ <div class="live-map-component {{@wrapperClass}}">
2
+ {{#if this.isReady}}
3
+ <LeafletMap id={{this.mapId}} class={{@mapClass}} @lat={{this.latitude}} @lng={{this.longitude}} @zoom={{this.zoom}} @zoomControl={{@zoomControl}} @contextmenu={{true}} @contextmenuWidth={{140}} @contextmenuItems={{this.contextMenuItems}} @onLoad={{this.setupMap}} {{will-destroy this.closeChannels}} ...attributes as |layers|>
4
+ <layers.tile @url={{this.tileSourceUrl}} />
5
+ {{#if this.visibilityControls.drivers}}
6
+ {{#each this.drivers as |driver|}}
7
+ <layers.drift-marker @id={{driver.id}} @rotationAngle={{driver.heading}} @duration={{300}} @icon={{icon iconUrl=(or driver.vehicle_avatar (config "defaultValues.vehicleAvatar")) iconSize=(array 24 24)}} @location={{point-to-coordinates driver.location}} @publicId={{driver.public_id}} @onAdd={{fn this.triggerAction "onDriverAdded" driver}} @onClick={{fn this.triggerAction "onDriverClicked" driver}} as |marker|>
8
+ <marker.popup @maxWidth="500" @minWidth="225">
9
+ <DriverCard @driver={{driver}} @showCoordinates={{true}} @textClass="text-gray-900 dark:text-gray-100" />
10
+ </marker.popup>
11
+ <marker.tooltip @permanent={{false}} @sticky={{true}}>{{driver.name}}</marker.tooltip>
12
+ </layers.drift-marker>
13
+ {{/each}}
14
+ {{/if}}
14
15
 
15
- {{#if this.visibilityControls.vehicles}}
16
- {{#each this.vehicles as |vehicle|}}
17
- <layers.drift-marker @id={{vehicle.id}} @rotationAngle={{vehicle.heading}} @duration={{300}} @icon={{icon iconUrl=(or vehicle.avatar_url (config "defaultValues.vehicleAvatar")) iconSize=(array 24 24)}} @location={{point-to-coordinates vehicle.location}} @publicId={{vehicle.public_id}} @onAdd={{fn this.triggerAction "onVehicleAdded" vehicle}} @onClick={{fn this.triggerAction "onVehicleClicked" vehicle}} as |marker|>
18
- <marker.tooltip @permanent={{false}} @sticky={{true}}>
19
- <div>{{vehicle.displayName}}</div>
20
- <div>{{if vehicle.online "Online" "Offline"}}</div>
21
- </marker.tooltip>
22
- </layers.drift-marker>
23
- {{/each}}
24
- {{/if}}
16
+ {{#if this.visibilityControls.vehicles}}
17
+ {{#each this.vehicles as |vehicle|}}
18
+ <layers.drift-marker @id={{vehicle.id}} @rotationAngle={{vehicle.heading}} @duration={{300}} @icon={{icon iconUrl=(or vehicle.avatar_url (config "defaultValues.vehicleAvatar")) iconSize=(array 24 24)}} @location={{point-to-coordinates vehicle.location}} @publicId={{vehicle.public_id}} @onAdd={{fn this.triggerAction "onVehicleAdded" vehicle}} @onClick={{fn this.triggerAction "onVehicleClicked" vehicle}} as |marker|>
19
+ <marker.tooltip @permanent={{false}} @sticky={{true}}>
20
+ <div>{{vehicle.displayName}}</div>
21
+ <div>{{if vehicle.online "Online" "Offline"}}</div>
22
+ </marker.tooltip>
23
+ </layers.drift-marker>
24
+ {{/each}}
25
+ {{/if}}
25
26
 
26
- {{#if this.visibilityControls.places}}
27
- {{#each this.places as |place|}}
28
- <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}} @onAdd={{fn this.triggerAction "onPlaceAdded" place}} @onClick={{fn this.triggerAction "onPlaceClicked" place}} as |marker|>
29
- <marker.popup>
30
- <div>{{place.address}}</div>
31
- <div>{{format-point place.location}}</div>
32
- </marker.popup>
33
- <marker.tooltip @permanent={{false}} @sticky={{true}} @direction="bottom">{{place.name}}</marker.tooltip>
34
- </layers.marker>
35
- {{/each}}
36
- {{/if}}
27
+ {{#if this.visibilityControls.places}}
28
+ {{#each this.places as |place|}}
29
+ <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}} @onAdd={{fn this.triggerAction "onPlaceAdded" place}} @onClick={{fn this.triggerAction "onPlaceClicked" place}} as |marker|>
30
+ <marker.popup>
31
+ <div>{{place.address}}</div>
32
+ <div>{{format-point place.location}}</div>
33
+ </marker.popup>
34
+ <marker.tooltip @permanent={{false}} @sticky={{true}} @direction="bottom">{{place.name}}</marker.tooltip>
35
+ </layers.marker>
36
+ {{/each}}
37
+ {{/if}}
37
38
 
38
- {{!-- {{#if this.isRoutesVisible}}
39
+ {{!-- {{#if this.isRoutesVisible}}
39
40
  {{#each this.routes as |route|}}
40
41
  <layers.polyline @locations={{route.details.coordinates}} />
41
42
 
@@ -67,22 +68,27 @@
67
68
  {{/each}}
68
69
  {{/if}} --}}
69
70
 
70
- <layers.draw-control @position="topright" @draw={{hash marker=false circlemarker=false circle=false polyline=false}} @onDrawDrawstop={{fn this.triggerAction "onDrawDrawstop"}} @onDrawDeleted={{fn this.triggerAction "onDrawDeleted"}} @onDrawEdited={{fn this.triggerAction "onDrawEdited"}} @onDrawDeletestart={{fn this.triggerAction "onDrawDeletestart"}} @onDrawEditstop={{fn this.triggerAction "onDrawEditstop"}} @onDrawControlCreated={{fn this.triggerAction "onDrawControlCreated"}} @onDrawFeatureGroupCreated={{fn this.triggerAction "onDrawFeatureGroupCreated"}} />
71
+ <layers.draw-control @position="topright" @draw={{hash marker=false circlemarker=false circle=false polyline=false}} @onDrawDrawstop={{fn this.triggerAction "onDrawDrawstop"}} @onDrawDeleted={{fn this.triggerAction "onDrawDeleted"}} @onDrawEdited={{fn this.triggerAction "onDrawEdited"}} @onDrawDeletestart={{fn this.triggerAction "onDrawDeletestart"}} @onDrawEditstop={{fn this.triggerAction "onDrawEditstop"}} @onDrawControlCreated={{fn this.triggerAction "onDrawControlCreated"}} @onDrawFeatureGroupCreated={{fn this.triggerAction "onDrawFeatureGroupCreated"}} />
71
72
 
72
- {{#each this.activeServiceAreas as |serviceArea|}}
73
- <layers.polygon @id={{serviceArea.id}} @record={{serviceArea}} @locations={{serviceArea.bounds}} @fillColor={{serviceArea.color}} @color={{serviceArea.stroke_color}} @onAdd={{fn this.triggerAction "onServiceAreaLayerAdded" serviceArea}} as |polygon|>
74
- <polygon.tooltip @permanent={{true}} @sticky={{true}}>{{serviceArea.name}} {{t "fleet-ops.component.live-map.service-area"}}</polygon.tooltip>
75
- </layers.polygon>
76
-
77
- {{#each serviceArea.zones as |zone|}}
78
- <layers.polygon @id={{zone.id}} @record={{zone}} @locations={{zone.locations}} @fillColor={{zone.color}} @color={{zone.stroke_color}} @onAdd={{fn this.triggerAction "onZoneLayerAdd" zone}} as |polygon|>
79
- <polygon.tooltip @permanent={{true}} @sticky={{true}}>{{zone.name}} {{t "fleet-ops.component.live-map.zone"}}</polygon.tooltip>
73
+ {{#each this.activeServiceAreas as |serviceArea|}}
74
+ <layers.polygon @id={{serviceArea.id}} @record={{serviceArea}} @locations={{serviceArea.bounds}} @fillColor={{serviceArea.color}} @color={{serviceArea.stroke_color}} @onAdd={{fn this.triggerAction "onServiceAreaLayerAdded" serviceArea}} as |polygon|>
75
+ <polygon.tooltip @permanent={{true}} @sticky={{true}}>{{serviceArea.name}} {{t "fleet-ops.component.live-map.service-area"}}</polygon.tooltip>
80
76
  </layers.polygon>
77
+
78
+ {{#each serviceArea.zones as |zone|}}
79
+ <layers.polygon @id={{zone.id}} @record={{zone}} @locations={{zone.locations}} @fillColor={{zone.color}} @color={{zone.stroke_color}} @onAdd={{fn this.triggerAction "onZoneLayerAdd" zone}} as |polygon|>
80
+ <polygon.tooltip @permanent={{true}} @sticky={{true}}>{{zone.name}} {{t "fleet-ops.component.live-map.zone"}}</polygon.tooltip>
81
+ </layers.polygon>
82
+ {{/each}}
81
83
  {{/each}}
82
- {{/each}}
83
84
 
84
- {{yield layers}}
85
- </LeafletMap>
85
+ {{yield layers}}
86
+ </LeafletMap>
87
+ {{else}}
88
+ <div class="flex w-full h-full items-center justify-center">
89
+ <Spinner />
90
+ </div>
91
+ {{/if}}
86
92
  </div>
87
93
 
88
94
  {{#if this.isDataLoaded}}
@@ -5,14 +5,10 @@ import { action, set } from '@ember/object';
5
5
  import { isArray } from '@ember/array';
6
6
  import { dasherize, camelize, classify } from '@ember/string';
7
7
  import { singularize } from 'ember-inflector';
8
- import { alias } from '@ember/object/computed';
9
8
  import { later } from '@ember/runloop';
10
9
  import { allSettled } from 'rsvp';
11
10
  import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
12
11
 
13
- const DEFAULT_LATITUDE = 1.369;
14
- const DEFAULT_LONGITUDE = 103.8864;
15
-
16
12
  /**
17
13
  * Component which displays live activity.
18
14
  *
@@ -66,6 +62,13 @@ export default class LiveMapComponent extends Component {
66
62
  */
67
63
  @service serviceAreas;
68
64
 
65
+ /**
66
+ * Inject the `location` service.
67
+ *
68
+ * @memberof LiveMapComponent
69
+ */
70
+ @service location;
71
+
69
72
  /**
70
73
  * Inject the `appCache` service.
71
74
  *
@@ -240,14 +243,14 @@ export default class LiveMapComponent extends Component {
240
243
  * @type {number}
241
244
  * @memberof LiveMapComponent
242
245
  */
243
- @tracked latitude = DEFAULT_LATITUDE;
246
+ @tracked latitude = this.location.getLatitude();
244
247
 
245
248
  /**
246
249
  * The longitude for the map view.
247
250
  * @type {number}
248
251
  * @memberof LiveMapComponent
249
252
  */
250
- @tracked longitude = DEFAULT_LONGITUDE;
253
+ @tracked longitude = this.location.getLongitude();
251
254
 
252
255
  /**
253
256
  * Indicates if coordinate setting should be skipped.
@@ -263,33 +266,21 @@ export default class LiveMapComponent extends Component {
263
266
  */
264
267
  originalResources = {};
265
268
 
266
- /**
267
- * The user's latitude from the currentUser.
268
- * @type {number}
269
- * @memberof LiveMapComponent
270
- */
271
- @alias('currentUser.latitude') userLatitude;
272
-
273
- /**
274
- * The user's longitude from the currentUser.
275
- * @type {number}
276
- * @memberof LiveMapComponent
277
- */
278
- @alias('currentUser.longitude') userLongitude;
279
-
280
269
  /**
281
270
  * Creates an instance of LiveMapComponent.
282
271
  * @memberof LiveMapComponent
283
272
  */
284
- constructor() {
273
+ constructor(owner, { zoom = 12, tileSourceUrl = 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', darkMode }) {
285
274
  super(...arguments);
286
- this.skipSetCoordinates = getWithDefault(this.args, 'skipSetCoordinates', false);
287
- this.zoom = getWithDefault(this.args, 'zoom', 12);
288
- this.tileSourceUrl = getWithDefault(this.args, 'tileSourceUrl', 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png');
289
275
 
290
- if (this.args.darkMode === true) {
276
+ this.zoom = zoom;
277
+ this.tileSourceUrl = tileSourceUrl;
278
+ if (darkMode === true) {
291
279
  this.tileSourceUrl = 'https://{s}.tile.jawg.io/jawg-matrix/{z}/{x}/{y}{r}.png?access-token=';
292
280
  }
281
+
282
+ this.ready();
283
+ this.setupComponent();
293
284
  }
294
285
 
295
286
  /**
@@ -300,7 +291,7 @@ export default class LiveMapComponent extends Component {
300
291
  * @action
301
292
  * @function
302
293
  */
303
- @action setupComponent() {
294
+ setupComponent() {
304
295
  // trigger that initial coordinates have been set
305
296
  this.universe.trigger('fleet-ops.live-map.loaded', this);
306
297
 
@@ -394,36 +385,15 @@ export default class LiveMapComponent extends Component {
394
385
  * if available, or null if the function is skipped.
395
386
  */
396
387
  async setInitialCoordinates() {
397
- if (this.skipSetCoordinates === false) {
398
- if (this.appCache.has(['map_latitude', 'map_longitude'])) {
399
- this.latitude = this.appCache.get('map_latitude');
400
- this.longitude = this.appCache.get('map_longitude');
401
- this.isReady = true;
402
-
403
- // trigger that initial coordinates is set to livemap component
404
- this.universe.trigger('fleet-ops.live-map.has_coordinates', { latitude: this.latitude, longitude: this.longitude });
405
-
406
- return [this.latitude, this.longitude];
407
- }
408
-
409
- const { latitude, longitude } = await this.getInitialCoordinates();
410
-
411
- if (this.appCache.doesntHave(['map_latitude', 'map_longitude'])) {
412
- this.appCache.set('map_latitude', latitude);
413
- this.appCache.set('map_longitude', longitude);
414
- }
388
+ const { latitude, longitude } = await this.location.getUserLocation();
415
389
 
416
- this.latitude = latitude;
417
- this.longitude = longitude;
418
- this.isReady = true;
390
+ this.latitude = latitude;
391
+ this.longitude = longitude;
392
+ this.ready();
419
393
 
420
- // trigger that initial coordinates is set to livemap component
421
- this.universe.trigger('fleet-ops.live-map.has_coordinates', { latitude: this.latitude, longitude: this.longitude });
422
-
423
- return [this.latitude, this.longitude];
424
- }
425
-
426
- return null;
394
+ // trigger that initial coordinates is set to livemap component
395
+ this.universe.trigger('fleet-ops.live-map.has_coordinates', { latitude: this.latitude, longitude: this.longitude });
396
+ return [this.latitude, this.longitude];
427
397
  }
428
398
 
429
399
  /**
@@ -1883,70 +1853,6 @@ export default class LiveMapComponent extends Component {
1883
1853
  }
1884
1854
  }
1885
1855
 
1886
- /**
1887
- * Retrieve the initial coordinates for the map view.
1888
- *
1889
- * @returns {Promise} A promise that resolves to an object containing latitude and longitude.
1890
- * @memberof LiveMapComponent
1891
- */
1892
- getInitialCoordinates() {
1893
- const initialCoordinates = {
1894
- latitude: DEFAULT_LATITUDE,
1895
- longitude: DEFAULT_LONGITUDE,
1896
- };
1897
-
1898
- const getCoordinateFromNavigator = () => {
1899
- return new Promise((resolve) => {
1900
- // eslint-disable-next-line no-undef
1901
- if (window.navigator && window.navigator.geolocation) {
1902
- // eslint-disable-next-line no-undef
1903
- return navigator.geolocation.getCurrentPosition(
1904
- ({ coords }) => {
1905
- const { latitude, longitude } = coords;
1906
-
1907
- initialCoordinates.latitude = latitude;
1908
- initialCoordinates.longitude = longitude;
1909
-
1910
- resolve(initialCoordinates);
1911
- },
1912
- () => {
1913
- // if failed use default user lat/lng
1914
- initialCoordinates.latitude = this.getLocalLatitude();
1915
- initialCoordinates.longitude = this.getLocalLongitude();
1916
-
1917
- resolve(initialCoordinates);
1918
- }
1919
- );
1920
- }
1921
- });
1922
- };
1923
-
1924
- return new Promise((resolve) => {
1925
- // get location from active orders
1926
- this.fetch
1927
- .get('fleet-ops/live/coordinates')
1928
- .then((coordinates) => {
1929
- if (!coordinates) {
1930
- return getCoordinateFromNavigator().then((navigatorCoordinates) => {
1931
- resolve(navigatorCoordinates);
1932
- });
1933
- }
1934
-
1935
- // from the `get-active-order-coordinates` the responded coordinates will always be [longitude, latitude]
1936
- const validCoordinates = coordinates.filter((point) => point.cordinates[0] !== 0);
1937
- const [longitude, latitude] = getWithDefault(validCoordinates, '0.coordiantes', [0, 0]);
1938
-
1939
- initialCoordinates.latitude = latitude;
1940
- initialCoordinates.longitude = longitude;
1941
-
1942
- resolve(initialCoordinates);
1943
- })
1944
- .catch(() => {
1945
- getCoordinateFromNavigator().then(resolve);
1946
- });
1947
- });
1948
- }
1949
-
1950
1856
  /**
1951
1857
  * Fetch service areas and cache them if not already cached.
1952
1858
  *
@@ -1976,30 +1882,4 @@ export default class LiveMapComponent extends Component {
1976
1882
  });
1977
1883
  });
1978
1884
  }
1979
-
1980
- /**
1981
- * Get the local latitude for the map view.
1982
- *
1983
- * @returns {number} The local latitude.
1984
- * @memberof LiveMapComponent
1985
- */
1986
- getLocalLatitude() {
1987
- const whois = this.currentUser.getOption('whois');
1988
- const latitude = this.appCache.get('map_latitude');
1989
-
1990
- return latitude || whois?.latitude || DEFAULT_LATITUDE;
1991
- }
1992
-
1993
- /**
1994
- * Get the local longitude for the map view.
1995
- *
1996
- * @returns {number} The local longitude.
1997
- * @memberof LiveMapComponent
1998
- */
1999
- getLocalLongitude() {
2000
- const whois = this.currentUser.getOption('whois');
2001
- const longitude = this.appCache.get('map_longitude');
2002
-
2003
- return longitude || whois?.longitude || DEFAULT_LONGITUDE;
2004
- }
2005
1885
  }
@@ -7,6 +7,7 @@ export default class ApplicationRoute extends Route {
7
7
  @service loader;
8
8
  @service fetch;
9
9
  @service intl;
10
+ @service location;
10
11
 
11
12
  @action loading(transition) {
12
13
  const resourceName = getResourceNameFromTransition(transition, { humanize: true });
@@ -15,6 +16,10 @@ export default class ApplicationRoute extends Route {
15
16
  });
16
17
  }
17
18
 
19
+ beforeModel() {
20
+ return this.location.getUserLocation();
21
+ }
22
+
18
23
  model() {
19
24
  return this.fetch.get('fleet-ops/settings/visibility');
20
25
  }
@@ -0,0 +1,163 @@
1
+ import Service, { inject as service } from '@ember/service';
2
+ import { tracked } from '@glimmer/tracking';
3
+ import { isBlank } from '@ember/utils';
4
+ import { isArray } from '@ember/array';
5
+ import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';
6
+
7
+ /**
8
+ * Service for managing and retrieving user location data.
9
+ * It interacts with various sources to provide the most accurate location information.
10
+ *
11
+ * @extends Service
12
+ */
13
+ export default class LocationService extends Service {
14
+ /**
15
+ * Default latitude used when location data is unavailable.
16
+ * @type {number}
17
+ * @static
18
+ */
19
+ static DEFAULT_LATITUDE = 1.369;
20
+
21
+ /**
22
+ * Default longitude used when location data is unavailable.
23
+ * @type {number}
24
+ * @static
25
+ */
26
+ static DEFAULT_LONGITUDE = 103.8864;
27
+
28
+ /**
29
+ * Service for accessing the current user's data.
30
+ * @type {CurrentUserService}
31
+ */
32
+ @service currentUser;
33
+
34
+ /**
35
+ * A service for managing application-wide events and states.
36
+ * @type {UniverseService}
37
+ */
38
+ @service universe;
39
+
40
+ /**
41
+ * Service for making HTTP requests, with support for caching responses.
42
+ * @type {FetchService}
43
+ */
44
+ @service fetch;
45
+
46
+ /**
47
+ * Current latitude of the user.
48
+ * @type {number}
49
+ */
50
+ @tracked latitude = this.DEFAULT_LATITUDE;
51
+
52
+ /**
53
+ * Current longitude of the user.
54
+ * @type {number}
55
+ */
56
+ @tracked longitude = this.DEFAULT_LONGITUDE;
57
+
58
+ /**
59
+ * Flag indicating whether the user's location has been located.
60
+ * @type {boolean}
61
+ */
62
+ @tracked located = false;
63
+
64
+ /**
65
+ * Retrieves the current latitude.
66
+ * @returns {number} The current latitude.
67
+ */
68
+ getLatitude() {
69
+ return this.latitude;
70
+ }
71
+
72
+ /**
73
+ * Retrieves the current longitude.
74
+ * @returns {number} The current longitude.
75
+ */
76
+ getLongitude() {
77
+ return this.longitude;
78
+ }
79
+
80
+ /**
81
+ * Attempts to fetch the user's location from various sources.
82
+ * Uses cached data, navigator geolocation, or WHOIS data as fallbacks.
83
+ * @returns {Promise<Object>} A promise that resolves to an object containing latitude and longitude.
84
+ */
85
+ getUserLocation() {
86
+ return this.fetch.cachedGet('fleet-ops/live/coordinates', {}, { expirationInterval: 1, expirationIntervalUnit: 'hour' }).then((coordinates) => {
87
+ if (isBlank(coordinates)) {
88
+ return this.getUserLocationFromNavigator().then((navigatorCoordinates) => {
89
+ this.updateLocation(navigatorCoordinates);
90
+ return navigatorCoordinates;
91
+ });
92
+ }
93
+
94
+ if (isArray(coordinates)) {
95
+ const validCoordinates = coordinates.filter((point) => point.coordinates[0] !== 0);
96
+ if (validCoordinates) {
97
+ const [longitude, latitude] = getWithDefault(validCoordinates, '0.coordinates', [0, 0]);
98
+ const userCoordinates = {
99
+ latitude,
100
+ longitude,
101
+ };
102
+
103
+ this.updateLocation(userCoordinates);
104
+ return userCoordinates;
105
+ }
106
+ }
107
+
108
+ return this.getUserLocationFromWhois();
109
+ });
110
+ }
111
+
112
+ /**
113
+ * Retrieves the user's location using the browser's navigator geolocation API.
114
+ * @returns {Promise<Object>} A promise that resolves to geolocation coordinates.
115
+ */
116
+ getUserLocationFromNavigator() {
117
+ return new Promise((resolve) => {
118
+ // eslint-disable-next-line no-undef
119
+ if (window.navigator && window.navigator.geolocation) {
120
+ // eslint-disable-next-line no-undef
121
+ return navigator.geolocation.getCurrentPosition(
122
+ ({ coords }) => {
123
+ this.updateLocation(coords);
124
+ return resolve(coords);
125
+ },
126
+ () => {
127
+ // If failed use user whois
128
+ return resolve(this.getUserLocationFromWhois());
129
+ }
130
+ );
131
+ }
132
+
133
+ // default to whois lookup coordinates
134
+ return resolve(this.getUserLocationFromWhois());
135
+ });
136
+ }
137
+
138
+ /**
139
+ * Retrieves the user's location based on WHOIS data associated with the user's account.
140
+ * @returns {Object} An object containing latitude and longitude from WHOIS data.
141
+ */
142
+ getUserLocationFromWhois() {
143
+ const whois = this.currentUser.getOption('whois');
144
+ const coordinates = {
145
+ latitude: getWithDefault(whois, 'latitude', this.DEFAULT_LATITUDE),
146
+ longitude: getWithDefault(whois, 'longitude', this.DEFAULT_LONGITUDE),
147
+ };
148
+
149
+ this.updateLocation(coordinates);
150
+ return coordinates;
151
+ }
152
+
153
+ /**
154
+ * Updates the service's tracked properties with the new location data and triggers an event.
155
+ * @param {Object} coordinates - An object containing the latitude and longitude.
156
+ */
157
+ updateLocation({ latitude, longitude }) {
158
+ this.latitude = latitude;
159
+ this.longitude = longitude;
160
+ this.located = true;
161
+ this.universe.trigger('user.located', { latitude, longitude });
162
+ }
163
+ }
@@ -0,0 +1 @@
1
+ export { default } from '@fleetbase/fleetops-engine/services/location';
package/composer.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fleetbase/fleetops-api",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
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.0",
25
+ "fleetbase/core-api": "^1.4.1",
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.6",
3
+ "version": "0.4.8",
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.6",
3
+ "version": "0.4.8",
4
4
  "description": "Fleet & Transport Management Extension for Fleetbase",
5
5
  "fleetbase": {
6
6
  "route": "fleet-ops"