/** * 用户全局状态 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) => 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()((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, }, })); }, }));