Skip to content

Commit

Permalink
Merge pull request #71 from fleetbase/dev-v0.4.7
Browse files Browse the repository at this point in the history
v0.4.7
  • Loading branch information
roncodes authored Feb 8, 2024
2 parents 7083b3e + 8133aa0 commit 9ce45d0
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 196 deletions.
4 changes: 2 additions & 2 deletions addon/components/layout/fleet-ops-sidebar/fleet-listing.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,12 @@ export default class LayoutFleetOpsSidebarFleetListingComponent extends Componen
listenForChanges() {
// when a vehicle is assigned/ or unassigned reload
this.universe.on('fleet.vehicle.assigned', () => {
this.loadFleetsWithVehicles();
this.fetchFleets.perform();
});

// when a vehicle is assigned/ or unassigned reload
this.universe.on('fleet.vehicle.unassigned', () => {
this.loadFleetsWithVehicles();
this.fetchFleets.perform();
});
}

Expand Down
100 changes: 53 additions & 47 deletions addon/components/live-map.hbs
Original file line number Diff line number Diff line change
@@ -1,41 +1,42 @@
<div class="live-map-component {{@wrapperClass}}" {{did-insert this.setupComponent}}>
<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|>
<layers.tile @url={{this.tileSourceUrl}} />
{{#if this.visibilityControls.drivers}}
{{#each this.drivers as |driver|}}
<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|>
<marker.popup @maxWidth="500" @minWidth="225">
<DriverCard @driver={{driver}} @showCoordinates={{true}} @textClass="text-gray-900 dark:text-gray-100" />
</marker.popup>
<marker.tooltip @permanent={{false}} @sticky={{true}}>{{driver.name}}</marker.tooltip>
</layers.drift-marker>
{{/each}}
{{/if}}
<div class="live-map-component {{@wrapperClass}}">
{{#if this.isReady}}
<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|>
<layers.tile @url={{this.tileSourceUrl}} />
{{#if this.visibilityControls.drivers}}
{{#each this.drivers as |driver|}}
<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|>
<marker.popup @maxWidth="500" @minWidth="225">
<DriverCard @driver={{driver}} @showCoordinates={{true}} @textClass="text-gray-900 dark:text-gray-100" />
</marker.popup>
<marker.tooltip @permanent={{false}} @sticky={{true}}>{{driver.name}}</marker.tooltip>
</layers.drift-marker>
{{/each}}
{{/if}}

{{#if this.visibilityControls.vehicles}}
{{#each this.vehicles as |vehicle|}}
<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|>
<marker.tooltip @permanent={{false}} @sticky={{true}}>
<div>{{vehicle.displayName}}</div>
<div>{{if vehicle.online "Online" "Offline"}}</div>
</marker.tooltip>
</layers.drift-marker>
{{/each}}
{{/if}}
{{#if this.visibilityControls.vehicles}}
{{#each this.vehicles as |vehicle|}}
<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|>
<marker.tooltip @permanent={{false}} @sticky={{true}}>
<div>{{vehicle.displayName}}</div>
<div>{{if vehicle.online "Online" "Offline"}}</div>
</marker.tooltip>
</layers.drift-marker>
{{/each}}
{{/if}}

{{#if this.visibilityControls.places}}
{{#each this.places as |place|}}
<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|>
<marker.popup>
<div>{{place.address}}</div>
<div>{{format-point place.location}}</div>
</marker.popup>
<marker.tooltip @permanent={{false}} @sticky={{true}} @direction="bottom">{{place.name}}</marker.tooltip>
</layers.marker>
{{/each}}
{{/if}}
{{#if this.visibilityControls.places}}
{{#each this.places as |place|}}
<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|>
<marker.popup>
<div>{{place.address}}</div>
<div>{{format-point place.location}}</div>
</marker.popup>
<marker.tooltip @permanent={{false}} @sticky={{true}} @direction="bottom">{{place.name}}</marker.tooltip>
</layers.marker>
{{/each}}
{{/if}}

{{!-- {{#if this.isRoutesVisible}}
{{!-- {{#if this.isRoutesVisible}}
{{#each this.routes as |route|}}
<layers.polyline @locations={{route.details.coordinates}} />
Expand Down Expand Up @@ -67,22 +68,27 @@
{{/each}}
{{/if}} --}}

<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"}} />
<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"}} />

{{#each this.activeServiceAreas as |serviceArea|}}
<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|>
<polygon.tooltip @permanent={{true}} @sticky={{true}}>{{serviceArea.name}} {{t "fleet-ops.component.live-map.service-area"}}</polygon.tooltip>
</layers.polygon>

{{#each serviceArea.zones as |zone|}}
<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|>
<polygon.tooltip @permanent={{true}} @sticky={{true}}>{{zone.name}} {{t "fleet-ops.component.live-map.zone"}}</polygon.tooltip>
{{#each this.activeServiceAreas as |serviceArea|}}
<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|>
<polygon.tooltip @permanent={{true}} @sticky={{true}}>{{serviceArea.name}} {{t "fleet-ops.component.live-map.service-area"}}</polygon.tooltip>
</layers.polygon>

{{#each serviceArea.zones as |zone|}}
<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|>
<polygon.tooltip @permanent={{true}} @sticky={{true}}>{{zone.name}} {{t "fleet-ops.component.live-map.zone"}}</polygon.tooltip>
</layers.polygon>
{{/each}}
{{/each}}
{{/each}}

{{yield layers}}
</LeafletMap>
{{yield layers}}
</LeafletMap>
{{else}}
<div class="flex w-full h-full items-center justify-center">
<Spinner />
</div>
{{/if}}
</div>

{{#if this.isDataLoaded}}
Expand Down
168 changes: 24 additions & 144 deletions addon/components/live-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@ import { action, set } from '@ember/object';
import { isArray } from '@ember/array';
import { dasherize, camelize, classify } from '@ember/string';
import { singularize } from 'ember-inflector';
import { alias } from '@ember/object/computed';
import { later } from '@ember/runloop';
import { allSettled } from 'rsvp';
import getWithDefault from '@fleetbase/ember-core/utils/get-with-default';

const DEFAULT_LATITUDE = 1.369;
const DEFAULT_LONGITUDE = 103.8864;

/**
* Component which displays live activity.
*
Expand Down Expand Up @@ -66,6 +62,13 @@ export default class LiveMapComponent extends Component {
*/
@service serviceAreas;

/**
* Inject the `location` service.
*
* @memberof LiveMapComponent
*/
@service location;

/**
* Inject the `appCache` service.
*
Expand Down Expand Up @@ -240,14 +243,14 @@ export default class LiveMapComponent extends Component {
* @type {number}
* @memberof LiveMapComponent
*/
@tracked latitude = DEFAULT_LATITUDE;
@tracked latitude = this.location.getLatitude();

/**
* The longitude for the map view.
* @type {number}
* @memberof LiveMapComponent
*/
@tracked longitude = DEFAULT_LONGITUDE;
@tracked longitude = this.location.getLongitude();

/**
* Indicates if coordinate setting should be skipped.
Expand All @@ -263,33 +266,21 @@ export default class LiveMapComponent extends Component {
*/
originalResources = {};

/**
* The user's latitude from the currentUser.
* @type {number}
* @memberof LiveMapComponent
*/
@alias('currentUser.latitude') userLatitude;

/**
* The user's longitude from the currentUser.
* @type {number}
* @memberof LiveMapComponent
*/
@alias('currentUser.longitude') userLongitude;

/**
* Creates an instance of LiveMapComponent.
* @memberof LiveMapComponent
*/
constructor() {
constructor(owner, { zoom = 12, tileSourceUrl = 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', darkMode }) {
super(...arguments);
this.skipSetCoordinates = getWithDefault(this.args, 'skipSetCoordinates', false);
this.zoom = getWithDefault(this.args, 'zoom', 12);
this.tileSourceUrl = getWithDefault(this.args, 'tileSourceUrl', 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png');

if (this.args.darkMode === true) {
this.zoom = zoom;
this.tileSourceUrl = tileSourceUrl;
if (darkMode === true) {
this.tileSourceUrl = 'https://{s}.tile.jawg.io/jawg-matrix/{z}/{x}/{y}{r}.png?access-token=';
}

this.ready();
this.setupComponent();
}

/**
Expand All @@ -300,7 +291,7 @@ export default class LiveMapComponent extends Component {
* @action
* @function
*/
@action setupComponent() {
setupComponent() {
// trigger that initial coordinates have been set
this.universe.trigger('fleet-ops.live-map.loaded', this);

Expand Down Expand Up @@ -394,36 +385,15 @@ export default class LiveMapComponent extends Component {
* if available, or null if the function is skipped.
*/
async setInitialCoordinates() {
if (this.skipSetCoordinates === false) {
if (this.appCache.has(['map_latitude', 'map_longitude'])) {
this.latitude = this.appCache.get('map_latitude');
this.longitude = this.appCache.get('map_longitude');
this.isReady = true;

// trigger that initial coordinates is set to livemap component
this.universe.trigger('fleet-ops.live-map.has_coordinates', { latitude: this.latitude, longitude: this.longitude });

return [this.latitude, this.longitude];
}

const { latitude, longitude } = await this.getInitialCoordinates();

if (this.appCache.doesntHave(['map_latitude', 'map_longitude'])) {
this.appCache.set('map_latitude', latitude);
this.appCache.set('map_longitude', longitude);
}
const { latitude, longitude } = await this.location.getUserLocation();

this.latitude = latitude;
this.longitude = longitude;
this.isReady = true;
this.latitude = latitude;
this.longitude = longitude;
this.ready();

// trigger that initial coordinates is set to livemap component
this.universe.trigger('fleet-ops.live-map.has_coordinates', { latitude: this.latitude, longitude: this.longitude });

return [this.latitude, this.longitude];
}

return null;
// trigger that initial coordinates is set to livemap component
this.universe.trigger('fleet-ops.live-map.has_coordinates', { latitude: this.latitude, longitude: this.longitude });
return [this.latitude, this.longitude];
}

/**
Expand Down Expand Up @@ -1883,70 +1853,6 @@ export default class LiveMapComponent extends Component {
}
}

/**
* Retrieve the initial coordinates for the map view.
*
* @returns {Promise} A promise that resolves to an object containing latitude and longitude.
* @memberof LiveMapComponent
*/
getInitialCoordinates() {
const initialCoordinates = {
latitude: DEFAULT_LATITUDE,
longitude: DEFAULT_LONGITUDE,
};

const getCoordinateFromNavigator = () => {
return new Promise((resolve) => {
// eslint-disable-next-line no-undef
if (window.navigator && window.navigator.geolocation) {
// eslint-disable-next-line no-undef
return navigator.geolocation.getCurrentPosition(
({ coords }) => {
const { latitude, longitude } = coords;

initialCoordinates.latitude = latitude;
initialCoordinates.longitude = longitude;

resolve(initialCoordinates);
},
() => {
// if failed use default user lat/lng
initialCoordinates.latitude = this.getLocalLatitude();
initialCoordinates.longitude = this.getLocalLongitude();

resolve(initialCoordinates);
}
);
}
});
};

return new Promise((resolve) => {
// get location from active orders
this.fetch
.get('fleet-ops/live/coordinates')
.then((coordinates) => {
if (!coordinates) {
return getCoordinateFromNavigator().then((navigatorCoordinates) => {
resolve(navigatorCoordinates);
});
}

// from the `get-active-order-coordinates` the responded coordinates will always be [longitude, latitude]
const validCoordinates = coordinates.filter((point) => point.cordinates[0] !== 0);
const [longitude, latitude] = getWithDefault(validCoordinates, '0.coordiantes', [0, 0]);

initialCoordinates.latitude = latitude;
initialCoordinates.longitude = longitude;

resolve(initialCoordinates);
})
.catch(() => {
getCoordinateFromNavigator().then(resolve);
});
});
}

/**
* Fetch service areas and cache them if not already cached.
*
Expand Down Expand Up @@ -1976,30 +1882,4 @@ export default class LiveMapComponent extends Component {
});
});
}

/**
* Get the local latitude for the map view.
*
* @returns {number} The local latitude.
* @memberof LiveMapComponent
*/
getLocalLatitude() {
const whois = this.currentUser.getOption('whois');
const latitude = this.appCache.get('map_latitude');

return latitude || whois?.latitude || DEFAULT_LATITUDE;
}

/**
* Get the local longitude for the map view.
*
* @returns {number} The local longitude.
* @memberof LiveMapComponent
*/
getLocalLongitude() {
const whois = this.currentUser.getOption('whois');
const longitude = this.appCache.get('map_longitude');

return longitude || whois?.longitude || DEFAULT_LONGITUDE;
}
}
5 changes: 5 additions & 0 deletions addon/routes/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default class ApplicationRoute extends Route {
@service loader;
@service fetch;
@service intl;
@service location;

@action loading(transition) {
const resourceName = getResourceNameFromTransition(transition, { humanize: true });
Expand All @@ -15,6 +16,10 @@ export default class ApplicationRoute extends Route {
});
}

beforeModel() {
return this.location.getUserLocation();
}

model() {
return this.fetch.get('fleet-ops/settings/visibility');
}
Expand Down
Loading

0 comments on commit 9ce45d0

Please sign in to comment.