Source

store/settings/index.js

import Vue from 'vue'
import { getQueryStringValue } from '@/utils/querystring'
import { getClientLogoAsBase64 } from '@/services/auth-service'
import {
  saveSettingsParamLocally,
  saveSettingsParamRemotely,
  getSettingsParamFromRemote,
} from '@/services/settings-service.js'
import i18n, { isValidLocaleCode } from '@/i18n'
import storage from '@/plugins/vue-local-storage.js'
import {
  getUserParameters,
  getUserParametersAsObject,
} from '@/services/user-service.js'

//Dummy promise to resolve when a sync is requested but there is already a sync in progress
let hasSyncFromCachePromise = null

let cacheBlacklist = ['osmLayers']

function newState() {
  return {
    //Used to PATCH settings parameters (thanks to ids)
    userParameters: [],

    hasSyncFromCache: false,

    clientLogoBase64: '',

    //Language will be decided during login action (default to fr)
    applicationLanguage: '',

    //Cartography

    //-- Predefined views
    //---- Default predefined view
    defaultMapPredefinedView: null,
    //-- Carto
    //---- Default zoom level
    defaultMapZoomLevel: null,
    //---- Zones
    //------ Client zones
    areClientZonesEnabledOnTheMap: false,
    //------ Client zone types
    enabledClientZones: [],
    clientBasemapItems: [],

    naturalGeocodingProvider: 'osm',

    //Base maps
    //Selected Leaflet base map
    wmsItem: {},
    googleLayers: [],
    areOSMLayersDisabled: false,
    osmLayers: [],
    userBaseLayer: null,

    //location
    autorefreshTimeInterval: 2,

    //User parameters (user client-side / database setting)
    userMaxMapPredefinedViewsCount: 999, //database name: maxvue

    //Events (client/user client-side setting)
    isAggregateEventGroupRoundEnabled: false,
    isAggregateEventGroupBinEnabled: false,
  }
}

/**
 *
 * @param {*} countryCode
 * @returns
 */
export function getComputedLanguageCodeFromCountryCode(countryCode) {
  let countryCodeNormalized = (countryCode || '').toString().toLowerCase()
  return isValidLocaleCode(countryCodeNormalized) ? countryCodeNormalized : ''
}

/**
 * @namespace Stores
 * @category Stores
 * @module settings-store
 * */
const SettingsStore = {
  namespaced: true,
  state: newState(),
  getters: {
    getParameter: (state) => (name) => state[name],
    /**
     * Retrieves the first available basemapId
     * API requires a valid client basemapId but use custom layers/basemaps (Google/OSM).
     **/
    getValidBasemapId: (state) =>
      (state.clientBasemapItems.find((c) => !!c.id) || {}).id || '',
  },
  mutations: {
    setParameters(state, data) {
      Object.assign(state, data)
    },
    resetStore(state) {
      state = {
        ...state,
        ...newState(),
      }
    },
  },
  actions: {
    resetStore({ commit }) {
      commit('resetStore')
    },
    /**
     * Some settings are stored in the server. This will check and overwrite client cache.
     * @function syncFromServer
     * @memberof SettingsStore
     */
    async syncFromServer({ commit, rootGetters, state, dispatch }) {
      let googleLayersString =
        (await Vue.$auth.getClientParameter('GeoredV3GoogleMap')) ||
        (!Vue.$env.isProduction() &&
          getQueryStringValue('GeoredV3GoogleMap')) ||
        ''
      const currentUserLogin = rootGetters['auth/loginName']

      let userParameters = Object.freeze(
        await getUserParameters(currentUserLogin)
      )
      /*console.log('syncFromServer::userParameters', {
        userParameters: userParameters,
      })*/

      //Clear current
      commit('setParameters', {
        clientLogoBase64: '',
      })

      let newState = {
        userParameters,
        clientLogoBase64: await getClientLogoAsBase64('default'),

        //The language choice at login view has priority over the client language
        applicationLanguage:
          state.applicationLanguage ||
          getComputedLanguageCodeFromCountryCode(
            rootGetters['auth/clientCountry']
          ) ||
          'fr',

        //Google basemaps
        googleLayers:
          state.googleLayers.length > 0
            ? state.googleLayers
            : googleLayersString.split(',').filter((str) => !!str),

        //OSM layer/s is/are enabled by default but it can be diasble for certain clients
        areOSMLayersDisabled: await Vue.$mapService.areOSMLayersDisabled(),

        osmLayers: await Vue.$mapService.getOSMLayers(),

        //Retrieve user parameters and merge them into state (userMaxMapPredefinedViewsCount, defaultMapZoomLevel, userBaseLayer)
        ...(await getUserParametersAsObject(
          currentUserLogin,
          state.userParameters
        )),

        //Retrieve other parameters from online persistance (defaultMapPredefinedView)
        ...(await getSettingsParamFromRemote()),
      }

      commit('setParameters', newState)

      dispatch('saveParameters')
      /*console.log('settings::syncFromServer', {
        newState: {
          ...newState,
        },
      })*/
    },
    /**
     * Retrieves settings from client-side cache. Call it before requesting parameters.
     * This should be called during app bootstrap
     * @param {Boolean} options.once Retrieves just once (default: true)
     */
    async syncFromCache({ commit, state, rootGetters }, options = {}) {
      if (options.once === undefined) {
        options.once = true
      }
      const { once } = options
      if (once && state.hasSyncFromCache) {
        return hasSyncFromCachePromise
      }

      let resolve = null
      hasSyncFromCachePromise = new Promise((r) => {
        resolve = r
      })
      let defaultState = newState()
      let keyPart = '_' + rootGetters['auth/loginNameClientIdEncoded']
      let data = {}
      let keys = await storage.keys()
      let cachedState = {}
      await Promise.all(
        Object.keys(state)
          .filter((stateKey) => !cacheBlacklist.includes(stateKey))
          .map((stateKey) => {
            return (async () => {
              let includesKey =
                keys.findIndex((key) => key.includes(stateKey)) !== -1

              //Hot-fix: Old version adds a '}' at the end of the cache key (bug)
              let value = includesKey
                ? (await storage.getItem(stateKey + keyPart)) ||
                  (await storage.getItem(stateKey + keyPart + '}'))
                : null

              cachedState[stateKey] = value
              data[stateKey] = value !== null ? value : defaultState[stateKey]
            })()
          })
      )
      data.hasSyncFromCache = true
      commit('setParameters', data)
      /*console.log('settings::syncFromCache', {
        cachedState,
      })*/
      resolve()
    },
    setParameter({ commit }, { name, value }) {
      commit('setParameters', {
        [name]: value,
      })
    },
    async setParameterAndSave({ dispatch }, { name, value }) {
      await dispatch('setParameter', { name, value })
      await dispatch('saveParameter', name)
    },
    /**
     * Persist a single parameter from state
     */
    async saveParameter({ state, rootGetters }, parameterName) {
      if (state[parameterName] !== undefined) {
        if (rootGetters['auth/isLogged']) {
          await saveSettingsParamRemotely(
            parameterName,
            state[parameterName],
            rootGetters['auth/isLoginAs'],
            state.userParameters
          )
          await saveSettingsParamLocally(
            getCacheKey(
              parameterName,
              rootGetters['auth/loginNameClientIdEncoded']
            ),
            state[parameterName]
          )
        }
      }
    },
    /**
     * Persist Vuex settings into client-side cache
     */
    async saveParameters({ state, rootGetters }) {
      await Promise.all(
        Object.keys(state).map((stateKey) => {
          return (async () => {
            if (rootGetters['auth/isLogged']) {
              await saveSettingsParamRemotely(
                stateKey,
                state[stateKey],
                rootGetters['auth/isLoginAs'],
                state.userParameters
              )
              await saveSettingsParamLocally(
                getCacheKey(
                  stateKey,
                  rootGetters['auth/loginNameClientIdEncoded']
                ),
                state[stateKey]
              )
            }
          })()
        })
      )
    },
  },
}

function getCacheKey(stateKey = '', segregationKey = '') {
  return `${stateKey}_${segregationKey}`
}

export default SettingsStore