diff --git a/src/App.vue b/src/App.vue index 1e865e99..2771cb35 100644 --- a/src/App.vue +++ b/src/App.vue @@ -2,11 +2,14 @@ import { useAppStore } from 'stores/app'; import { useUserStore } from 'stores/user'; import { onBeforeMount } from 'vue'; +import { useRouter } from 'vue-router'; + const appStore = useAppStore(); const userStore = useUserStore(); +const router = useRouter(); onBeforeMount(async () => { - await userStore.init(); + await userStore.init(router); await appStore.init(); }); diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index 94daa6f8..228a342c 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -13,7 +13,7 @@ const appStore = useAppStore(); const hiddenMenuItems = new Set(['Reports']); const refreshContentKey = ref(0); -const { user, supplantedUser } = storeToRefs(userStore); +const { mainUser, supplantedUser } = storeToRefs(userStore); const { menuEssentialLinks, title, subtitle, useRightDrawer, rightDrawerOpen } = storeToRefs(appStore); const actions = ref(null); @@ -82,7 +82,7 @@ const logoutSupplantedUser = async () => {
- {{ user?.nickname }} + {{ mainUser?.nickname }}
diff --git a/src/stores/app.js b/src/stores/app.js index ed16085e..8f480997 100644 --- a/src/stores/app.js +++ b/src/stores/app.js @@ -68,7 +68,6 @@ export const useAppStore = defineStore('hedera', { }, async init() { - // this.router.push({ name: 'login' }); this.getBasketOrderId(); this.getLocaleDates(); }, @@ -155,6 +154,10 @@ export const useAppStore = defineStore('hedera', { isTablet() { const $q = useQuasar(); return $q?.screen?.width <= 1024; + }, + isDesktop() { + const $q = useQuasar(); + return $q?.screen?.width > 1024; } } }); diff --git a/src/stores/user.js b/src/stores/user.js index 11ec29c6..0042fe41 100644 --- a/src/stores/user.js +++ b/src/stores/user.js @@ -1,4 +1,5 @@ import { defineStore } from 'pinia'; +import { ref, computed, watch } from 'vue'; import { api, jApi } from 'boot/axios'; import { i18n } from 'src/boot/i18n'; import useNotify from 'src/composables/useNotify.js'; @@ -7,254 +8,308 @@ import { useAppStore } from 'src/stores/app.js'; const { t } = i18n.global; const { notify } = useNotify(); -export const useUserStore = defineStore('user', { - state: () => { - return { - token: '', - isGuest: false, - user: null, - supplantedUser: null, - localeOptions: [ - { label: t('langs.en'), lang: 'en-US', value: 'en' }, - { label: t('langs.es'), lang: 'es-ES', value: 'es' }, - { label: t('langs.ca'), lang: 'ca-ES', value: 'ca' }, - { label: t('langs.fr'), lang: 'fr-FR', value: 'fr' }, - { label: t('langs.pt'), lang: 'pt-PT', value: 'pt' } - ], - keepLogin: false, - intervalId: null, - isCheckingToken: false, - tokenConfig: null - }; - }, +export const useUserStore = defineStore('user', () => { + const token = ref(''); + const isGuest = ref(false); + const user = ref(null); // Usuario en uso => supplantedUser || mainUser + const supplantedUser = ref(null); // Usuario suplantado + const mainUser = ref(null); // Usuario principal logueado + const localeOptions = ref([ + { label: t('langs.en'), lang: 'en-US', value: 'en' }, + { label: t('langs.es'), lang: 'es-ES', value: 'es' }, + { label: t('langs.ca'), lang: 'ca-ES', value: 'ca' }, + { label: t('langs.fr'), lang: 'fr-FR', value: 'fr' }, + { label: t('langs.pt'), lang: 'pt-PT', value: 'pt' } + ]); + const keepLogin = ref(false); + const intervalId = ref(null); + const isCheckingToken = ref(false); + const tokenConfig = ref(null); + let router; - getters: { - loggedIn: state => !!state.token, - userLocaleOption: state => - state.localeOptions?.find(l => l.value === state?.user?.lang), - storage: state => (state.keepLogin ? localStorage : sessionStorage) - }, + const loggedIn = computed(() => !!token.value); + const userLocaleOption = computed(() => + localeOptions.value?.find(l => l.value === user.value?.lang) + ); + const storage = computed(() => + keepLogin.value ? localStorage : sessionStorage + ); - actions: { - async init() { - this.isGuest = localStorage.getItem('hederaGuest') || false; - await this.getToken(); - if (!this.loggedIn) { - const autoLoginStatus = await this.tryAutoLogin(); - if (!autoLoginStatus) { - this.router.push({ name: 'login' }); - } - return; + const init = async _router => { + router = _router; + isGuest.value = localStorage.getItem('hederaGuest') || false; + console.log('isGuest.value', isGuest.value); + await getToken(); + if (!loggedIn.value) { + const autoLoginStatus = await tryAutoLogin(); + if (!autoLoginStatus) { + router.push({ name: 'login' }); } - await this.fetchTokenConfig(); - await this.fetchUser(); - await this.supplantInit(); - this.updateSiteLocale(); - this.startInterval(); - }, - - getToken() { - const token = - sessionStorage.getItem('vnToken') || - localStorage.getItem('vnToken'); - this.token = token; - return token; - }, - - setToken(token) { - this.storage.setItem('vnToken', token); - this.token = token; - }, - - async destroyToken(url, storage, key) { - if (storage.getItem(key)) { - try { - await api.post(url, null, { - headers: { Authorization: storage.getItem(key) } - }); - } catch (error) { - notify('errors.statusUnauthorized', 'negative'); - } finally { - storage.removeItem(key); - } - } - }, - - async destroy(destroyTokens = true) { - const tokens = { - tokenMultimedia: 'Accounts/logout', - token: 'VnUsers/logout' - }; - let destroyTokenPromises = []; - try { - if (destroyTokens) { - const { data: isValidToken } = await api.get( - 'VnUsers/validateToken' - ); - if (isValidToken) - destroyTokenPromises = Object.entries(tokens).map( - ([key, url]) => - this.destroyToken(url, this.storage, key) - ); - } - } finally { - localStorage.clear(); - sessionStorage.clear(); - await Promise.allSettled(destroyTokenPromises); - this.user = null; - this.stopRenewer(); - } - }, - - isLoggedIn() { - const token = this.getToken(); - return !!token; - }, - - setSession(data) { - this.storage.setItem('created', data.created); - this.storage.setItem('ttl', data.ttl); - localStorage.setItem('keepLogin', this.keepLogin); - }, - - async login(user, password, remember) { - const params = { user, password }; - const { data } = await api.post('Accounts/login', params); - this.name = user; - this.keepLogin = remember; - this.setToken(data.token); - this.setSession({ created: Date.now(), ...data }); - await this.fetchTokenConfig(); - this.startInterval(); - }, - - async tryAutoLogin() { - const guest = localStorage.getItem('hederaGuest'); - - if (this.isGuest || guest) { - localStorage.setItem('hederaGuest', true); - return true; - } - - if (!this.token) this.getToken(); - - if (this.token) return true; - - return false; - }, - - async logout() { - try { - await api.post('Accounts/logout'); - } catch (e) {} - this.destroy(); - this.$reset(); - useAppStore().onLogout(); - }, - - async fetchTokenConfig() { - try { - const { data } = await api.get('AccessTokenConfigs/findOne', { - filter: { fields: ['renewInterval', 'renewPeriod'] } - }); - if (!data) return; - this.tokenConfig = data; - this.storage.setItem('renewPeriod', data.renewPeriod); - return data; - } catch (error) { - notify('errors.tokenConfig', 'negative'); - console.error('Error fetching token config:', error); - } - }, - - async renewToken() { - const _token = this.getToken(); - const token = await api.post('VnUsers/renewToken', { - headers: { Authorization: _token } - }); - - this.setToken(token.data.id); - }, - - async checkValidity() { - const created = +this.storage.getItem('created'); - const ttl = +this.storage.getItem('ttl'); - - if (this.isCheckingToken || !created) return; - this.isCheckingToken = true; - - const renewPeriodInSeconds = - Math.min(ttl, this.tokenConfig?.renewPeriod) * 1000; - const maxDate = created + renewPeriodInSeconds; - const now = new Date().getTime(); - - if (isNaN(renewPeriodInSeconds) || now <= maxDate) { - return (this.isCheckingToken = false); - } - - await this.renewToken(); - this.isCheckingToken = false; - }, - - stopRenewer() { - clearInterval(this.intervalId); - }, - - startInterval() { - this.stopRenewer(); - const renewPeriod = +this.storage.getItem('renewPeriod'); - if (!renewPeriod) return; - this.intervalId = setInterval( - () => this.checkValidity(), - renewPeriod * 1000 - ); - }, - - async fetchUser(userType = 'user') { - try { - const userData = await jApi.getObject( - 'SELECT id, nickname, name, lang FROM account.myUser' - ); - this.$patch({ [userType]: userData }); - } catch (error) { - console.error('Error fetching user: ', error); - } - }, - - async supplantUser(supplantUser) { - const json = await jApi.send('client/supplant', { - supplantUser - }); - this.token = json; - sessionStorage.setItem('supplantUser', supplantUser); - await this.fetchUser('supplantedUser'); - }, - - async supplantInit() { - const user = sessionStorage.getItem('supplantUser'); - if (user == null) return; - await this.supplantUser(user); - }, - - async logoutSupplantedUser() { - sessionStorage.removeItem('supplantUser'); - this.supplantedUser = null; - await api.post('Accounts/logout'); - this.getToken(); - await this.fetchUser(); - }, - - updateSiteLocale(locale = null) { - i18n.global.locale.value = - locale || this.userLocaleOption.lang || 'en-US'; - }, - - async updateUserLang(lang) { - if (!this.user || this.user.lang === lang) return; - - this.user.lang = lang; - this.updateSiteLocale(); - notify(t('dataSaved'), 'positive'); } - } + await fetchTokenConfig(); + await fetchUser(); + await supplantInit(); + updateSiteLocale(); + startInterval(); + }; + + const getToken = () => { + const tokenValue = + sessionStorage.getItem('vnToken') || + localStorage.getItem('vnToken'); + token.value = tokenValue; + return tokenValue; + }; + + const setToken = _token => { + storage.value.setItem('vnToken', _token); + token.value = _token; + }; + + const destroyToken = async (url, storageType, key) => { + if (storageType.getItem(key)) { + try { + await api.post(url, null, { + headers: { Authorization: storageType.getItem(key) } + }); + } catch (error) { + notify('errors.statusUnauthorized', 'negative'); + } finally { + storageType.removeItem(key); + } + } + }; + + const destroy = async (destroyTokens = true) => { + const tokens = { + tokenMultimedia: 'Accounts/logout', + token: 'VnUsers/logout' + }; + let destroyTokenPromises = []; + try { + if (destroyTokens) { + const { data: isValidToken } = await api.get( + 'VnUsers/validateToken' + ); + if (isValidToken) { + destroyTokenPromises = Object.entries(tokens).map( + ([key, url]) => destroyToken(url, storage.value, key) + ); + } + } + } finally { + localStorage.clear(); + sessionStorage.clear(); + await Promise.allSettled(destroyTokenPromises); + user.value = null; + stopRenewer(); + } + }; + + const setSession = data => { + storage.value.setItem('created', data.created); + storage.value.setItem('ttl', data.ttl); + localStorage.setItem('keepLogin', keepLogin.value); + }; + + const login = async (username, password, remember) => { + const params = { user: username, password }; + const { data } = await api.post('Accounts/login', params); + keepLogin.value = remember; + storage.value.setItem('hederaLastUser', username); + setToken(data.token); + setSession({ created: Date.now(), ...data }); + await fetchTokenConfig(); + startInterval(); + }; + + const tryAutoLogin = async () => { + if (isGuest.value) { + localStorage.setItem('hederaGuest', true); + return true; + } + + if (!token.value) getToken(); + + if (token.value) return true; + + return false; + }; + + const logout = async () => { + try { + await api.post('Accounts/logout'); + } catch (e) {} + destroy(); + $reset(); + useAppStore().onLogout(); + }; + + const fetchTokenConfig = async () => { + try { + const { data } = await api.get('AccessTokenConfigs/findOne', { + filter: { fields: ['renewInterval', 'renewPeriod'] } + }); + if (!data) return; + tokenConfig.value = data; + storage.value.setItem('renewPeriod', data.renewPeriod); + return data; + } catch (error) { + notify('errors.tokenConfig', 'negative'); + console.error('Error fetching token config:', error); + } + }; + + const renewToken = async () => { + const _token = getToken(); + const tokenData = await api.post('VnUsers/renewToken', { + headers: { Authorization: _token } + }); + setToken(tokenData.data.id); + }; + + const checkValidity = async () => { + const created = +storage.value.getItem('created'); + const ttl = +storage.value.getItem('ttl'); + + if (isCheckingToken.value || !created) return; + isCheckingToken.value = true; + + const renewPeriodInSeconds = + Math.min(ttl, tokenConfig.value?.renewPeriod) * 1000; + const maxDate = created + renewPeriodInSeconds; + const now = new Date().getTime(); + console.log('renewPeriodInSeconds', renewPeriodInSeconds); + console.log('maxDate', maxDate); + console.log('now', now); + + if (isNaN(renewPeriodInSeconds) || now <= maxDate) { + isCheckingToken.value = false; + return; + } + + await renewToken(); + isCheckingToken.value = false; + }; + + const stopRenewer = () => { + clearInterval(intervalId.value); + }; + + const startInterval = () => { + stopRenewer(); + // const renewPeriod = +storage.value.getItem('renewPeriod'); + const renewPeriod = 5; + if (!renewPeriod) return; + intervalId.value = setInterval( + () => checkValidity(), + renewPeriod * 1000 + ); + }; + + const fetchUser = async (userType = 'user') => { + try { + const userData = await jApi.getObject( + 'SELECT id, nickname, name, lang FROM account.myUser' + ); + if (userType === 'user') mainUser.value = userData; + else supplantedUser.value = userData; + } catch (error) { + console.error('Error fetching user: ', error); + } + }; + + const supplantUser = async supplantUser => { + const json = await jApi.send('client/supplant', { supplantUser }); + token.value = json; + sessionStorage.setItem('supplantUser', supplantUser); + await fetchUser('supplantedUser'); + }; + + const supplantInit = async () => { + const user = sessionStorage.getItem('supplantUser'); + if (!user) return; + await supplantUser(user); + }; + + const logoutSupplantedUser = async () => { + sessionStorage.removeItem('supplantUser'); + supplantedUser.value = null; + await api.post('Accounts/logout'); + getToken(); + await fetchUser(); + }; + + const updateSiteLocale = (locale = null) => { + i18n.global.locale.value = + locale || userLocaleOption.value?.lang || 'en-US'; + }; + + const updateUserLang = async lang => { + if (!user.value || user.value.lang === lang) return; + + user.value.lang = lang; + updateSiteLocale(); + notify(t('dataSaved'), 'positive'); + }; + + const $reset = () => { + token.value = ''; + isGuest.value = false; + user.value = null; + supplantedUser.value = null; + mainUser.value = null; + keepLogin.value = false; + intervalId.value = null; + isCheckingToken.value = false; + tokenConfig.value = null; + }; + + watch( + [mainUser, supplantedUser], + () => { + user.value = supplantedUser.value || mainUser.value; + console.log('mainUser.value', mainUser.value); + console.log('supplantedUser.value', supplantedUser.value); + console.log('user.value', user.value); + }, + { immediate: true } + ); + + return { + token, + isGuest, + user, + supplantedUser, + mainUser, + localeOptions, + keepLogin, + intervalId, + isCheckingToken, + tokenConfig, + loggedIn, + userLocaleOption, + storage, + getToken, + setToken, + destroyToken, + destroy, + setSession, + login, + tryAutoLogin, + logout, + fetchTokenConfig, + renewToken, + checkValidity, + stopRenewer, + startInterval, + fetchUser, + supplantUser, + supplantInit, + logoutSupplantedUser, + updateSiteLocale, + updateUserLang, + init, + $reset + }; });