Files
juwan-frontend/store/auth.ts
T

157 lines
4.4 KiB
TypeScript

import type { User, UserRole, VerificationStatus } from "@/lib/types"
import { create } from "zustand"
interface NotificationPrefs {
order: boolean
community: boolean
system: boolean
}
const defaultNotificationPrefs: NotificationPrefs = {
order: true,
community: true,
system: false,
}
export type ThemePreference = "light" | "dark" | "system"
interface AuthState {
isAuthenticated: boolean
currentRole: UserRole
verifiedRoles: UserRole[]
verificationStatus: Partial<Record<UserRole, VerificationStatus>>
verificationReasons: Partial<Record<UserRole, string>>
notificationPrefs: NotificationPrefs
themePreference: ThemePreference
user: User | null
switchRole: (role: UserRole) => void
submitVerification: (role: UserRole) => void
approveVerification: (role: UserRole) => void
rejectVerification: (role: UserRole, reason: string) => void
setNotificationPref: (type: keyof NotificationPrefs, enabled: boolean) => void
setThemePreference: (theme: ThemePreference) => void
updateProfile: (patch: { nickname?: string; bio?: string; avatar?: string }) => void
login: (user: User, verifiedRoles?: UserRole[], themePreference?: ThemePreference) => void
logout: () => void
}
export const useAuthStore = create<AuthState>((set, get) => ({
isAuthenticated: false,
currentRole: "consumer",
verifiedRoles: ["consumer"],
verificationStatus: { consumer: "approved" },
verificationReasons: {},
notificationPrefs: defaultNotificationPrefs,
themePreference: "system",
user: null,
switchRole: (role) => {
const { verifiedRoles } = get()
if (verifiedRoles.includes(role)) {
set({ currentRole: role })
}
},
submitVerification: (role) =>
set((state) => {
if (state.verifiedRoles.includes(role)) {
return state
}
const nextReasons = { ...state.verificationReasons }
delete nextReasons[role]
return {
verificationStatus: {
...state.verificationStatus,
[role]: "pending",
},
verificationReasons: nextReasons,
}
}),
approveVerification: (role) =>
set((state) => {
if (state.verifiedRoles.includes(role) && state.verificationStatus[role] === "approved") {
return state
}
const nextReasons = { ...state.verificationReasons }
delete nextReasons[role]
return {
verifiedRoles: state.verifiedRoles.includes(role)
? state.verifiedRoles
: [...state.verifiedRoles, role],
verificationStatus: {
...state.verificationStatus,
[role]: "approved",
},
verificationReasons: nextReasons,
}
}),
rejectVerification: (role, reason) =>
set((state) => {
if (state.verifiedRoles.includes(role)) {
return state
}
return {
verificationStatus: {
...state.verificationStatus,
[role]: "rejected",
},
verificationReasons: {
...state.verificationReasons,
[role]: reason.trim() || "认证资料不完整,请补充后重试",
},
}
}),
setNotificationPref: (type, enabled) =>
set((state) => ({
notificationPrefs: {
...state.notificationPrefs,
[type]: enabled,
},
})),
setThemePreference: (theme) => set({ themePreference: theme }),
updateProfile: (patch) =>
set((state) => {
if (!state.user) return state
return {
user: {
...state.user,
nickname: patch.nickname ?? state.user.nickname,
bio: patch.bio ?? state.user.bio,
avatar: patch.avatar ?? state.user.avatar,
},
}
}),
login: (user, verifiedRoles = ["consumer"], themePreference) =>
set((state) => ({
isAuthenticated: true,
user,
currentRole: user.role,
verifiedRoles,
verificationStatus: verifiedRoles.reduce<Partial<Record<UserRole, VerificationStatus>>>(
(acc, role) => {
acc[role] = "approved"
return acc
},
{},
),
verificationReasons: {},
notificationPrefs: state.notificationPrefs,
themePreference: themePreference ?? state.themePreference,
})),
logout: () =>
set({
isAuthenticated: false,
currentRole: "consumer",
verifiedRoles: ["consumer"],
verificationStatus: { consumer: "approved" },
verificationReasons: {},
notificationPrefs: defaultNotificationPrefs,
themePreference: "system",
user: null,
}),
}))