79 lines
2.3 KiB
TypeScript
79 lines
2.3 KiB
TypeScript
'use client';
|
|
|
|
import { create } from 'zustand';
|
|
import { loginWithPassword, logoutRequest, type TokenPair } from '@/lib/api/auth';
|
|
import { registerTokenBridge } from '@/lib/api/client';
|
|
import { broadcastLogout } from '@/lib/sync/logout-broadcast';
|
|
|
|
const STORAGE_KEY = 'smart_auth_tokens';
|
|
|
|
function loadFromSession(): Pick<AuthState, 'accessToken' | 'refreshToken'> {
|
|
if (typeof window === 'undefined') {
|
|
return { accessToken: null, refreshToken: null };
|
|
}
|
|
try {
|
|
const raw = sessionStorage.getItem(STORAGE_KEY);
|
|
if (!raw) {
|
|
return { accessToken: null, refreshToken: null };
|
|
}
|
|
const p = JSON.parse(raw) as { accessToken?: string; refreshToken?: string };
|
|
return { accessToken: p.accessToken ?? null, refreshToken: p.refreshToken ?? null };
|
|
} catch {
|
|
return { accessToken: null, refreshToken: null };
|
|
}
|
|
}
|
|
|
|
type AuthState = {
|
|
accessToken: string | null;
|
|
refreshToken: string | null;
|
|
setTokens: (access: string | null, refresh: string | null) => void;
|
|
login: (userName: string, password: string, tenantId?: string) => Promise<void>;
|
|
logout: () => Promise<void>;
|
|
};
|
|
|
|
export const useAuthStore = create<AuthState>((set) => {
|
|
const initial = loadFromSession();
|
|
|
|
const persist = (accessToken: string | null, refreshToken: string | null) => {
|
|
set({ accessToken, refreshToken });
|
|
if (typeof window !== 'undefined') {
|
|
if (accessToken || refreshToken) {
|
|
sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ accessToken, refreshToken }));
|
|
} else {
|
|
sessionStorage.removeItem(STORAGE_KEY);
|
|
}
|
|
}
|
|
};
|
|
|
|
return {
|
|
accessToken: initial.accessToken,
|
|
refreshToken: initial.refreshToken,
|
|
|
|
setTokens: (access, refresh) => {
|
|
persist(access, refresh);
|
|
},
|
|
|
|
login: async (userName, password, tenantId) => {
|
|
const pair: TokenPair = await loginWithPassword({ userName, password, tenantId });
|
|
persist(pair.accessToken, pair.refreshToken);
|
|
},
|
|
|
|
logout: async () => {
|
|
try {
|
|
await logoutRequest();
|
|
} finally {
|
|
persist(null, null);
|
|
broadcastLogout();
|
|
}
|
|
},
|
|
};
|
|
});
|
|
|
|
registerTokenBridge(
|
|
() => ({
|
|
accessToken: useAuthStore.getState().accessToken,
|
|
refreshToken: useAuthStore.getState().refreshToken,
|
|
}),
|
|
(access, refresh) => useAuthStore.getState().setTokens(access, refresh)
|
|
);
|