From 123bc55b26b8115d6a3eb3ee0d3c7d3928615045 Mon Sep 17 00:00:00 2001 From: km2025 Date: Thu, 15 Jan 2026 17:14:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86=E5=92=8C=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stores/userStore.ts | 126 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 stores/userStore.ts diff --git a/stores/userStore.ts b/stores/userStore.ts new file mode 100644 index 0000000..1a9604c --- /dev/null +++ b/stores/userStore.ts @@ -0,0 +1,126 @@ +import { makeAutoObservable } from 'mobx' +import { useEffect } from 'react' + +import { signOut as authSignOut, useSession } from '@/lib/auth' + +// console.log('useSession---------------', useSession) + +interface User { + id: string + email: string + name?: string + image?: string | null + createdAt: Date + updatedAt: Date + emailVerified?: boolean + username?: string | null + banExpires?: Date | null + banReason?: string | null + banned?: boolean | null + displayUsername?: string | null + metadata?: any | null + phoneNumber?: string | null + phoneNumberVerified?: boolean | null + role?: string | null + stripeCustomerId?: string | null +} + +interface Session { + user?: User + session?: { + id: string + userId: string + expiresAt: Date + createdAt: Date + updatedAt: Date + activeOrganizationId?: string | null + activeTeamId?: string | null + impersonatedBy?: string | null + ipAddress?: string | null + token?: string | null + userAgent?: string | null + } +} + +class UserStore { + user: User | null = null + session: Session | null = null + isAuthenticated: boolean = false + isLoading: boolean = false + error: string | null = null + + constructor() { + // autoBind ensures methods keep `this`, and all fields become observable/actions + makeAutoObservable(this) + } + + // 设置用户信息 + setUser(user: User | null) { + this.user = user + this.isAuthenticated = !!user + } + + // 设置会话信息 + setSession(session: Session | null) { + this.session = session + this.user = session?.user || null + this.isAuthenticated = !!session?.user + } + + // 设置加载状态 + setLoading(loading: boolean) { + this.isLoading = loading + } + + // 设置错误信息 + setError(error: string | null) { + this.error = error + } + + // 登出方法 + signOut = async () => { + this.setLoading(true) + try { + await authSignOut() + this.reset() + // 登出时重置余额store + const { userBalanceStore } = await import('./userBalanceStore') + userBalanceStore.reset() + } catch (error) { + this.setError(error instanceof Error ? error.message : '登出失败') + console.error('登出失败:', error) + } finally { + this.setLoading(false) + } + } + + // 从session更新用户状态 + updateFromSession(sessionData: Session | null) { + this.setSession(sessionData) + } + + // 重置store状态 + reset() { + this.user = null + this.session = null + this.isAuthenticated = false + this.isLoading = false + this.error = null + } +} + +// 创建单例实例 +export const userStore = new UserStore() + +// 创建一个hook来使用session数据更新store +export const useUserSession = () => { + const session = useSession() + + // 使用useEffect在副作用中更新store状态,避免在render过程中修改 + useEffect(() => { + userStore.setLoading(session.isPending) + userStore.updateFromSession(session.data) + }, [session.isPending, session.data]) + + return session +}