// Ported from legacy henza_admin/src/store/auth/moduleAuth.js import { defineStore } from 'pinia'; import api from '../api/client'; import { iamAppUrl, tokenName, userName } from '../utils'; import { useUsersStore } from './users'; import type { UserInfo } from './users'; /** * LEGACY BUG, recorded in docs/ADMIN-PORT-PLAN.md (#3). * * Legacy declared these as FUNCTIONS in Vuex state, not values: * * const state = { * user: () => JSON.parse(localStorage.getItem(...)), * token: () => localStorage.getItem(...), * } * * so `store.state.auth.token` was a function object — always truthy, even when * logged out. The router guard's `store.state.auth.token && store.state.auth.user` * check was therefore dead code that always passed, and the real gate was the * separate `localStorage.getItem(token)` read in beforeEach. * * Here they are getters that return the actual value. The observable behaviour * is unchanged, because the real gate was — and still is — the localStorage read; * this only removes a permanently-true condition, it does not let anyone in. */ export const useAuthStore = defineStore('auth', { state: () => ({ userPermission: [] as string[], }), getters: { token: (): string | null => localStorage.getItem(tokenName), user: (): UserInfo | null => { const raw = localStorage.getItem(userName); if (!raw) return null; try { return JSON.parse(raw); } catch { return null; } }, isLoggedIn(): boolean { return Boolean(this.token); }, }, actions: { /** * Port of legacy action `login`. * * Legacy: POST 'admin-login', then * dispatch('users/getRoles', data.roles.map(x => x.rid)) * delete data.roles; delete data.ut * commit('INJECT', data) * * The endpoint name is translated by the mapping layer in api/endpoints.ts. */ async login(payload: { phone: string; password: string }) { const { data } = await api.post('admin-login', payload); const users = useUsersStore(); users.getRoles((data.roles ?? []).map((x: { rid: string }) => x.rid)); users.setSuperAdmin(data.is_super_admin); // Legacy stripped these before persisting the user blob. Kept: the panel // reads permissions from the store, never from the cached user object. const persisted = { ...data }; delete persisted.roles; delete persisted.ut; this.inject(persisted); if (data.iamBootstrapUrl) { window.location.assign(data.iamBootstrapUrl); } return persisted; }, /** Port of legacy mutation INJECT. */ inject(payload: UserInfo & { api_token: string }) { localStorage.setItem(tokenName, payload.api_token); // Consumed once by App.vue to show the welcome toast, then removed. localStorage.setItem('login', 'true'); localStorage.setItem(userName, JSON.stringify(payload)); }, /** * Not present in legacy — legacy had no logout action at all, which is why * its module-scoped `roles` survived a session change (bug #2). Clearing * both storage and the roles store is the fix for that. */ async logout(): Promise { let central: string | null = null; try { const { data } = await api.get('admin/auth/sso/logout-url', { params: { return_url: iamAppUrl('auth/login') }, }); central = data?.logout_url ?? null; } catch { central = null; } localStorage.removeItem(tokenName); localStorage.removeItem(userName); localStorage.removeItem('login'); sessionStorage.removeItem('gb_admin_iam_sso_checked'); const users = useUsersStore(); users.deleteRoles(); users.deleteUserInfo(); if (central) { window.location.assign(central); return true; } return false; }, }, });