diff --git a/apps/web/src/stores/auth.ts b/apps/web/src/stores/auth.ts index 266b1fb..b95ab80 100644 --- a/apps/web/src/stores/auth.ts +++ b/apps/web/src/stores/auth.ts @@ -1,21 +1,31 @@ import { create } from 'zustand'; import { login as apiLogin, logout as apiLogout, type UserInfo } from '../api/auth'; -// Synchronously restore auth state from localStorage at store creation time. -// This eliminates the flash-of-login-page on refresh because isAuthenticated -// is already `true` before the first render. -function restoreInitialState(): { user: UserInfo | null; isAuthenticated: boolean } { +function extractPermissions(): string[] { + const token = localStorage.getItem('access_token'); + if (!token) return []; + try { + const parts = token.split('.'); + if (parts.length !== 3) return []; + const payload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/'))); + return Array.isArray(payload.permissions) ? payload.permissions : []; + } catch { + return []; + } +} + +function restoreInitialState(): { user: UserInfo | null; isAuthenticated: boolean; permissions: string[] } { const token = localStorage.getItem('access_token'); const userStr = localStorage.getItem('user'); if (token && userStr) { try { const user = JSON.parse(userStr) as UserInfo; - return { user, isAuthenticated: true }; + return { user, isAuthenticated: true, permissions: extractPermissions() }; } catch { localStorage.removeItem('user'); } } - return { user: null, isAuthenticated: false }; + return { user: null, isAuthenticated: false, permissions: [] }; } const initial = restoreInitialState(); @@ -24,6 +34,7 @@ interface AuthState { user: UserInfo | null; isAuthenticated: boolean; loading: boolean; + permissions: string[]; login: (username: string, password: string) => Promise; logout: () => Promise; loadFromStorage: () => void; @@ -33,6 +44,7 @@ export const useAuthStore = create((set) => ({ user: initial.user, isAuthenticated: initial.isAuthenticated, loading: false, + permissions: initial.permissions, login: async (username, password) => { set({ loading: true }); @@ -41,7 +53,7 @@ export const useAuthStore = create((set) => ({ localStorage.setItem('access_token', resp.access_token); localStorage.setItem('refresh_token', resp.refresh_token); localStorage.setItem('user', JSON.stringify(resp.user)); - set({ user: resp.user, isAuthenticated: true, loading: false }); + set({ user: resp.user, isAuthenticated: true, loading: false, permissions: extractPermissions() }); } catch (error) { set({ loading: false }); throw error; @@ -57,13 +69,11 @@ export const useAuthStore = create((set) => ({ localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); localStorage.removeItem('user'); - set({ user: null, isAuthenticated: false }); + set({ user: null, isAuthenticated: false, permissions: [] }); }, - // Kept for backward compatibility but no longer needed since - // initial state is restored synchronously at store creation. loadFromStorage: () => { const state = restoreInitialState(); - set({ user: state.user, isAuthenticated: state.isAuthenticated }); + set({ user: state.user, isAuthenticated: state.isAuthenticated, permissions: state.permissions }); }, }));