Files
aplp.frontend.web/src/features/auth/store/authStore.ts
T

71 lines
1.9 KiB
TypeScript
Raw Normal View History

2026-08-11 21:09:32 +07:00
import { create } from 'zustand';
import { registerAuthHandlers } from '@/api/client';
import { tokenStorage } from '@/api/tokenStorage';
import { authApi } from '../api/authApi';
import type { AuthUser } from '../types';
interface AuthState {
/** Authenticated user, or null when signed out. */
user: AuthUser | null;
/** Whether a session bootstrap is in progress. */
isInitializing: boolean;
login: (email: string, password: string) => Promise<void>;
logout: () => Promise<void>;
/** Bootstrap session: try refresh on app start. */
init: () => Promise<void>;
}
export const useAuthStore = create<AuthState>()((set) => ({
user: null,
isInitializing: true,
login: async (email, password) => {
const { accessToken, user } = await authApi.login({ email, password });
tokenStorage.set(accessToken);
set({ user, isInitializing: false });
},
logout: async () => {
try {
await authApi.logout();
} catch {
// Best-effort: always clear the local session, even if the API call fails.
} finally {
tokenStorage.clear();
set({ user: null, isInitializing: false });
}
},
init: async () => {
try {
const { accessToken, user } = await authApi.refresh();
tokenStorage.set(accessToken);
set({ user, isInitializing: false });
} catch {
tokenStorage.clear();
set({ user: null, isInitializing: false });
}
},
}));
/**
* Wire the API client to this store: refresh access token and clear session on
* hard 401 (unrecoverable). Keeps the auth concern centralized, not scattered.
*/
registerAuthHandlers(
async () => {
try {
const { accessToken } = await authApi.refresh();
tokenStorage.set(accessToken);
return accessToken;
} catch {
return null;
}
},
() => {
tokenStorage.clear();
useAuthStore.setState({ user: null, isInitializing: false });
},
);