@fleetbase/fleetops-engine 0.4.6 → 0.4.7
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.
- package/addon/components/layout/fleet-ops-sidebar/fleet-listing.js +2 -2
- package/addon/components/live-map.hbs +53 -47
- package/addon/components/live-map.js +24 -144
- package/addon/routes/application.js +5 -0
- package/addon/services/location.js +161 -0
- package/app/services/location.js +1 -0
- package/composer.json +1 -1
- package/extension.json +1 -1
- package/package.json +1 -1
|
@@ -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.
|
|
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.
|
|
113
|
+
this.fetchFleets.perform();
|
|
114
114
|
});
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -1,41 +1,42 @@
|
|
|
1
|
-
<div class="live-map-component {{@wrapperClass}}"
|
|
2
|
-
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
{{#
|
|
6
|
-
|
|
7
|
-
<marker.
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
85
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
417
|
-
|
|
418
|
-
|
|
390
|
+
this.latitude = latitude;
|
|
391
|
+
this.longitude = longitude;
|
|
392
|
+
this.ready();
|
|
419
393
|
|
|
420
|
-
|
|
421
|
-
|
|
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,161 @@
|
|
|
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
|
+
const [longitude, latitude] = getWithDefault(validCoordinates, '0.coordinates', [0, 0]);
|
|
97
|
+
const coordinates = {
|
|
98
|
+
latitude,
|
|
99
|
+
longitude,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
this.updateLocation(coordinates);
|
|
103
|
+
return coordinates;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return this.getUserLocationFromWhois();
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Retrieves the user's location using the browser's navigator geolocation API.
|
|
112
|
+
* @returns {Promise<Object>} A promise that resolves to geolocation coordinates.
|
|
113
|
+
*/
|
|
114
|
+
getUserLocationFromNavigator() {
|
|
115
|
+
return new Promise((resolve) => {
|
|
116
|
+
// eslint-disable-next-line no-undef
|
|
117
|
+
if (window.navigator && window.navigator.geolocation) {
|
|
118
|
+
// eslint-disable-next-line no-undef
|
|
119
|
+
return navigator.geolocation.getCurrentPosition(
|
|
120
|
+
({ coords }) => {
|
|
121
|
+
this.updateLocation(coords);
|
|
122
|
+
return resolve(coords);
|
|
123
|
+
},
|
|
124
|
+
() => {
|
|
125
|
+
// If failed use user whois
|
|
126
|
+
return resolve(this.getUserLocationFromWhois());
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// default to whois lookup coordinates
|
|
132
|
+
return resolve(this.getUserLocationFromWhois());
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Retrieves the user's location based on WHOIS data associated with the user's account.
|
|
138
|
+
* @returns {Object} An object containing latitude and longitude from WHOIS data.
|
|
139
|
+
*/
|
|
140
|
+
getUserLocationFromWhois() {
|
|
141
|
+
const whois = this.currentUser.getOption('whois');
|
|
142
|
+
const coordinates = {
|
|
143
|
+
latitude: getWithDefault(whois, 'latitude', this.DEFAULT_LATITUDE),
|
|
144
|
+
longitude: getWithDefault(whois, 'longitude', this.DEFAULT_LONGITUDE),
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
this.updateLocation(coordinates);
|
|
148
|
+
return coordinates;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Updates the service's tracked properties with the new location data and triggers an event.
|
|
153
|
+
* @param {Object} coordinates - An object containing the latitude and longitude.
|
|
154
|
+
*/
|
|
155
|
+
updateLocation({ latitude, longitude }) {
|
|
156
|
+
this.latitude = latitude;
|
|
157
|
+
this.longitude = longitude;
|
|
158
|
+
this.located = true;
|
|
159
|
+
this.universe.trigger('user.located', { latitude, longitude });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@fleetbase/fleetops-engine/services/location';
|
package/composer.json
CHANGED
package/extension.json
CHANGED