import historyApi from '@/api/historyApi.js'
import { linestringsToPolylines } from '@/mixins/map'
import moment from 'moment'
import Vue from 'vue'
import { getFormattedAddress } from '@/utils/address'
import { getNestedValue } from '@/utils/object.js'
import { formatTimeWithSeconds } from '@/utils/dates.js'
import { isUnitTest } from '@/utils/unit.js'
import { APIV2RequestDatetimeFormat } from '@/config/simpliciti-apis.js'
import { normalizePositionV2 } from '@/services/entities/position-entity.js'
const scope = {
currentTripHistoryLoading: false,
}
/**
*
* @param {*} err
* @param {*} dispatch
* @returns {*}
*/
export async function dispatchAlertForAPIV2Error(err, dispatch) {
if (err.message.includes(`Vous n'avez pas accès aux véhicules fournis`)) {
return dispatch(
'alert/addAlert',
{
type: 'warning',
title: '403',
text: "Vous n'avez pas accès aux véhicules fournis",
},
{
root: true,
}
)
}
console.error(err)
}
export default {
state: {
currentTripHistory: [],
currentChartTripHistory: [],
},
getters: {
currentTripHistory(state) {
return state.currentTripHistory || []
},
},
mutations: {
currentTripHistory(state, tripHistory = []) {
state.currentTripHistory = tripHistory || []
},
currentChartTripHistory: (state, currentChartTripHistory = []) =>
(state.currentChartTripHistory = currentChartTripHistory),
},
actions: {
/**
* Updates simpliciti_map store position markers data from
* v2/historique/positions_capteurs
*
* @TODO Skip if positions already present
*/
async updateMapPositionMarkers({ dispatch, rootGetters }, options = {}) {
const { vehicleId, date } = options
if (!vehicleId) {
return
}
//TripHistoryTable.spec.js will fail due to unauthorized API call
if (!isUnitTest()) {
await dispatch(
'map_options/syncSensorConfig',
{
vehicleId,
},
{
root: true,
}
)
}
let shouldSkipPositionsFetch =
isUnitTest() && options.fakePositions && options.fakeSensorConfig
let response = shouldSkipPositionsFetch
? {}
: await historyApi.getVehiclePositionsV3(vehicleId, date, options)
if (response) {
let positions = []
;(response?.positions || []).forEach((item) => {
positions.push(normalizePositionV2(item))
})
//reComputeSensorsConfigActive: Otherwise, sensor config items remain grey out!
let config = rootGetters['map_options/sensorsConfig']
if (isUnitTest() && options.fakePositions && options.fakeSensorConfig) {
positions = options.fakePositions
config = options.fakeSensorConfig
}
;(config?.sensors || []).forEach((sensor) => {
sensor.active = positions.some(
(position) =>
position.code == sensor.code ||
position.code_capteurs.includes(sensor.code)
)
})
dispatch('map_options/setSensorsConfig', config, {
root: true,
})
dispatch(
'simpliciti_map/setDataset',
{
type: 'vehiclePositionMarkers',
data: positions,
},
{
root: true,
}
)
}
},
/**
* Used by Location - History details
*
* Commits normalized trip history from results
* Commits polylines from results
* @returns {Array} Non-normalized trip history (APIV2 troncons_details)
*/
async getTripHistoryFromVehicleDate(
{ dispatch, commit, rootGetters },
{ id, date }
) {
//@TODO: Refactor try catch into a reusable function trycatchAPIErrors(async()=>[1,2,3], [])
try {
scope.currentTripHistoryLoading = true
let tripHistoryData =
(await historyApi.getTripHistoryFromVehicleId(id, date)) || []
// Set trip history infos and linestring infos (polylines) separately
let tripHistory = tripHistoryData && tripHistoryData[0]
if (tripHistory) {
let currentTripHistory = tripHistory.troncons.map(
normalizeTripHistoryItem(id)
)
commit('currentTripHistory', currentTripHistory)
scope.currentTripHistoryLoading = false
let polylines = linestringsToPolylines(currentTripHistory, {
//If selected item has tripHistoryPolyline.color, use that color to render the trip history
...((rootGetters['location_module/selectedItem'] || {})
?.tripHistoryPolyline?.color
? {
color: (rootGetters['location_module/selectedItem'] || {})
?.tripHistoryPolyline?.color,
}
: {}),
})
dispatch(
'simpliciti_map/setDataset',
{
type: 'singleTripHistoryPolylines',
data: polylines,
},
{
root: true,
}
)
dispatch(
'simpliciti_map/setDataset',
{
type: 'speedPolylines',
data: currentTripHistory.reduce((acum, currTripHistory) => {
let linestrings = (currTripHistory.speedLinestring || []).map(
(linestringColor) => {
return {
...currTripHistory,
linestring: linestringColor.linestring,
color: linestringColor.couleur,
}
}
)
return acum.concat(linestringsToPolylines(linestrings))
}, []),
},
{
root: true,
}
)
dispatch('simpliciti_map/setTripStepMarkers', polylines, {
root: true,
})
} else {
commit('currentTripHistory', [])
dispatch(
'simpliciti_map/setDataset',
{
type: 'singleTripHistoryPolylines',
data: [],
},
{
root: true,
}
)
dispatch('simpliciti_map/setTripStepMarkers', [], {
root: true,
})
}
// non-normalized api response
return tripHistoryData
} catch (err) {
console.warn('ERR', err)
dispatchAlertForAPIV2Error(err, dispatch)
return []
}
},
/**
* Retrieves one vehicle trip history (normalized for a vertical chart)
*
* Updates the vehicle positions (To render trip positions markers)
* Updates the vehicle trip history linestring (To render trip polylines)
*
* @param {int} id Vehicle ID
* @param {string} date YYYY-MM-DD
*/
async getChartTripHistoryFromVehicleId(
{ dispatch, commit, state },
{ id, date }
) {
/*
//Re-use data from store
if (
!!state.currentChartTripHistory &&
state.currentChartTripHistory.length > 0
) {
return state.currentChartTripHistory;
}*/
//@TODO: Refactor try catch into a reusable function trycatchAPIErrors(async()=>[1,2,3], [])
try {
commit(
'currentChartTripHistory',
await historyApi.getChartTripHistoryFromVehicleId(
id,
date,
await dispatch('getTripHistoryFromVehicleDate', { id, date })
)
)
return state.currentChartTripHistory
} catch (err) {
console.warn('ERR', err)
dispatchAlertForAPIV2Error(err, dispatch)
return []
}
},
},
}
function getTime(item, field) {
return formatTimeWithSeconds(item[field], {
inputFormat: APIV2RequestDatetimeFormat,
})
}
function getMilli(item, field) {
return (
(item[field] &&
moment(item[field], APIV2RequestDatetimeFormat)._d.getTime()) ||
0
)
}
function getAddress(
item,
streetNumber,
streetAddress,
zipCode,
city,
useZone,
zone
) {
return getFormattedAddress(item, {
streetNumber,
streetAddress,
zipCode,
city,
useZone: item[useZone],
zone,
})
}
function getFormattedDurationFromSeconds(seconds) {
let d = moment.duration(seconds * 1000)
return (
Math.floor(d.asHours()) + moment.utc(seconds * 1000).format('[h]mm[m]ss[s]')
)
}
/**
* @TODO: Use getNestedValue helper function to normalize attributes
*/
function normalizeTripHistoryItem(vehicleId) {
return function (item, index) {
let mappedItem = {
number: parseInt(index + 1),
vehicleId: vehicleId,
distance: item.distance,
tripDuration: item.duree_trajet,
tripDurationFormatted: getFormattedDurationFromSeconds(item.duree_trajet),
date: moment(item.date, 'YYYY-MM-DD')._d,
stopDurationSeconds: item.duree_arret,
stopDuration: getFormattedDurationFromSeconds(item.duree_arret),
fromTimeMilli: getMilli(item, 'dh_trajet_deb'),
fromTime: getTime(item, 'dh_trajet_deb'),
fromAddress: getAddress(
item,
'',
'adresse_deb',
'cp_deb',
'ville_deb',
'in_zoneinterne_deb',
'zone_deb'
),
toTime: getTime(item, 'dh_trajet_fin'),
toTimeMilli: getMilli(item, 'dh_trajet_fin'),
toAddress: getAddress(
item,
'',
'adresse_fin',
'cp_fin',
'ville_fin',
'in_zoneinterne_fin',
'zone_fin'
),
datetimeContactON: getTime(item, 'dh_contact_on'),
datetimeContactONMilli: getMilli(item, 'dh_contact_on'),
datetimeContactOFF: getTime(item, 'dh_contact_off'),
datetimeContactOFFMilli: getMilli(item, 'dh_contact_off'),
linestring: item.linestring,
speedLinestring: getNestedValue(
item,
['linestring_mouvement', 'linestring_couleur'],
[]
),
}
mappedItem.id = require('object-hash')(mappedItem)
return mappedItem
}
}
function waitSomeTime(seconds) {
return new Promise((resolve) => {
setTimeout(() => resolve(), seconds * 1000)
})
}
Source