104 lines
3.0 KiB
TypeScript
104 lines
3.0 KiB
TypeScript
/**
|
||
* 用户全局状态 Store (Zustand)
|
||
*
|
||
* 与 NextAuth Session 互补:
|
||
* - Session 由 next-auth 管理,负责认证流程
|
||
* - 此 Store 管理客户端侧的用户偏好和 UI 状态
|
||
* - 通过 syncFromSession 将 session 数据同步到 store
|
||
*/
|
||
|
||
import { create } from "zustand";
|
||
import type { Session } from "next-auth";
|
||
|
||
// ── 类型定义 ────────────────────────────────────────────────────────────────────
|
||
|
||
export interface UserPreferences {
|
||
/** 侧边栏是否折叠 */
|
||
sidebarCollapsed: boolean;
|
||
/** 默认查询频率偏好 */
|
||
defaultFrequency: "daily" | "weekly" | "monthly";
|
||
/** 主题偏好(预留) */
|
||
theme: "light" | "dark" | "system";
|
||
}
|
||
|
||
export interface UserState {
|
||
/** 当前用户 ID(从 session 同步) */
|
||
userId: string | null;
|
||
/** 用户名 */
|
||
userName: string | null;
|
||
/** 用户邮箱 */
|
||
userEmail: string | null;
|
||
/** 是否管理员 */
|
||
isAdmin: boolean;
|
||
/** 是否已认证 */
|
||
isAuthenticated: boolean;
|
||
/** 用户偏好设置 */
|
||
preferences: UserPreferences;
|
||
}
|
||
|
||
export interface UserActions {
|
||
/** 从 NextAuth session 同步用户信息 */
|
||
syncFromSession: (session: Session | null) => void;
|
||
/** 清除用户状态(登出时调用) */
|
||
clear: () => void;
|
||
/** 更新偏好设置(部分更新) */
|
||
updatePreferences: (patch: Partial<UserPreferences>) => void;
|
||
/** 切换侧边栏折叠状态 */
|
||
toggleSidebar: () => void;
|
||
}
|
||
|
||
// ── 默认值 ──────────────────────────────────────────────────────────────────────
|
||
|
||
const DEFAULT_PREFERENCES: UserPreferences = {
|
||
sidebarCollapsed: false,
|
||
defaultFrequency: "weekly",
|
||
theme: "light",
|
||
};
|
||
|
||
const INITIAL_STATE: UserState = {
|
||
userId: null,
|
||
userName: null,
|
||
userEmail: null,
|
||
isAdmin: false,
|
||
isAuthenticated: false,
|
||
preferences: DEFAULT_PREFERENCES,
|
||
};
|
||
|
||
// ── Store ───────────────────────────────────────────────────────────────────────
|
||
|
||
export const useUserStore = create<UserState & UserActions>()((set) => ({
|
||
...INITIAL_STATE,
|
||
|
||
syncFromSession: (session) => {
|
||
if (!session || !session.user) {
|
||
set(INITIAL_STATE);
|
||
return;
|
||
}
|
||
set({
|
||
userId: session.user.id,
|
||
userName: session.user.name ?? null,
|
||
userEmail: session.user.email ?? null,
|
||
isAdmin: session.user.is_admin ?? false,
|
||
isAuthenticated: true,
|
||
});
|
||
},
|
||
|
||
clear: () => {
|
||
set(INITIAL_STATE);
|
||
},
|
||
|
||
updatePreferences: (patch) => {
|
||
set((state) => ({
|
||
preferences: { ...state.preferences, ...patch },
|
||
}));
|
||
},
|
||
|
||
toggleSidebar: () => {
|
||
set((state) => ({
|
||
preferences: {
|
||
...state.preferences,
|
||
sidebarCollapsed: !state.preferences.sidebarCollapsed,
|
||
},
|
||
}));
|
||
},
|
||
})); |