Files
aplp.frontend.web/src/features/auth/store/authStore.ts
T
2026-08-11 23:10:00 +07:00

79 lines
2.3 KiB
TypeScript

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, refreshToken, user } = await authApi.login({ email, password });
tokenStorage.set(accessToken, refreshToken);
set({ user, isInitializing: false });
},
logout: async () => {
try {
await authApi.logout(tokenStorage.getRefreshToken() ?? '');
} catch {
// Best-effort: always clear the local session, even if the API call fails.
} finally {
tokenStorage.clear();
set({ user: null, isInitializing: false });
}
},
init: async () => {
const refreshToken = tokenStorage.getRefreshToken();
if (!refreshToken) {
tokenStorage.clear();
set({ user: null, isInitializing: false });
return;
}
try {
const { accessToken, refreshToken: nextRefreshToken, user } = await authApi.refresh(refreshToken);
tokenStorage.set(accessToken, nextRefreshToken);
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 () => {
const refreshToken = tokenStorage.getRefreshToken();
if (!refreshToken) return null;
try {
const { accessToken, refreshToken: nextRefreshToken } = await authApi.refresh(refreshToken);
tokenStorage.set(accessToken, nextRefreshToken);
return accessToken;
} catch {
return null;
}
},
() => {
tokenStorage.clear();
useAuthStore.setState({ user: null, isInitializing: false });
},
);