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'; import { useAppStore } from 'src/stores/app.js'; const { t } = i18n.global; const { notify } = useNotify(); const TOKEN_MULTIMEDIA = 'tokenMultimedia'; const TOKEN = 'token'; export const useUserStore = defineStore('user', () => { const token = ref(''); const tokenMultimedia = 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; const loggedIn = computed(() => !!token.value); const userLocaleOption = computed(() => localeOptions.value?.find(l => l.value === user.value?.lang) ); const storage = computed(() => keepLogin.value ? localStorage : sessionStorage ); const init = async _router => { router = _router; isGuest.value = localStorage.getItem('hederaGuest') || false; await getToken(); if (!loggedIn.value) { const autoLoginStatus = await tryAutoLogin(); if (!autoLoginStatus) { router.push({ name: 'login' }); } } await fetchTokenConfig(); await fetchUser(); await supplantInit(); updateSiteLocale(); startInterval(); }; const getToken = () => { const tokenValue = sessionStorage.getItem(TOKEN) || localStorage.getItem(TOKEN); token.value = tokenValue; return tokenValue; }; const getTokenMultimedia = () => { const tokenMultimediaValue = sessionStorage.getItem(TOKEN_MULTIMEDIA) || localStorage.getItem(TOKEN_MULTIMEDIA); tokenMultimedia.value = tokenMultimediaValue; return tokenMultimediaValue; }; const setToken = ({ _token, _tokenMultimedia }) => { storage.value.setItem(TOKEN, _token); storage.value.setItem(TOKEN_MULTIMEDIA, _tokenMultimedia); token.value = _token; tokenMultimedia.value = _tokenMultimedia; }; 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 => { setToken({ _token: data.token, _tokenMultimedia: data.tokenMultimedia }); storage.value.setItem('hederaLastUser', data.username); storage.value.setItem('created', data.created); storage.value.setItem('ttl', data.ttl); localStorage.setItem('keepLogin', keepLogin.value); }; const fetchMultimediaToken = async data => { const { data: { multimediaToken } } = await api.get('VnUsers/ShareToken', { headers: { Authorization: data.token } }); return multimediaToken; }; const login = async (username, password, remember) => { const params = { user: username, password }; const { data } = await api.post('Accounts/login', params); const multimediaToken = await fetchMultimediaToken(data); if (!multimediaToken) return; keepLogin.value = remember; setSession({ created: Date.now(), tokenMultimedia: multimediaToken.id, username, ...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 } }); const _tokenMultimedia = getTokenMultimedia(); const tokenMultimedia = await api.post('VnUsers/renewToken', { headers: { Authorization: _tokenMultimedia } }); setToken({ _token: tokenData.data.id, _tokenMultimedia: tokenMultimedia.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(); 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'); 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), { immediate: true } ); return { token, isGuest, user, supplantedUser, mainUser, localeOptions, keepLogin, intervalId, isCheckingToken, tokenConfig, loggedIn, userLocaleOption, storage, getToken, getTokenMultimedia, setToken, destroyToken, destroy, setSession, login, tryAutoLogin, logout, fetchTokenConfig, renewToken, checkValidity, stopRenewer, startInterval, fetchUser, supplantUser, supplantInit, logoutSupplantedUser, updateSiteLocale, updateUserLang, init, $reset }; });