fix: sync verification state with auth guards

This commit is contained in:
zetaloop
2026-02-21 15:53:46 +08:00
parent 6469811382
commit 6ed8620ca6
5 changed files with 70 additions and 7 deletions
+15 -3
View File
@@ -16,9 +16,14 @@ import {
} from "@/components/ui/select" } from "@/components/ui/select"
import { Separator } from "@/components/ui/separator" import { Separator } from "@/components/ui/separator"
import { Textarea } from "@/components/ui/textarea" import { Textarea } from "@/components/ui/textarea"
import type { UserRole } from "@/lib/types"
import { useAuthStore } from "@/store/auth"
export default function VerifyPage() { export default function VerifyPage() {
const [submitted, setSubmitted] = useState(false) const [verifyRole, setVerifyRole] = useState<UserRole | "">("")
const verificationStatus = useAuthStore((state) => state.verificationStatus)
const submitVerification = useAuthStore((state) => state.submitVerification)
const submitted = Object.values(verificationStatus).includes("pending")
if (submitted) { if (submitted) {
return ( return (
@@ -68,7 +73,7 @@ export default function VerifyPage() {
<CardContent className="space-y-6"> <CardContent className="space-y-6">
<div className="space-y-2"> <div className="space-y-2">
<Label></Label> <Label></Label>
<Select> <Select value={verifyRole} onValueChange={(value) => setVerifyRole(value as UserRole)}>
<SelectTrigger> <SelectTrigger>
<SelectValue placeholder="选择认证类型" /> <SelectValue placeholder="选择认证类型" />
</SelectTrigger> </SelectTrigger>
@@ -115,7 +120,14 @@ export default function VerifyPage() {
<p className="text-xs text-muted-foreground"> JPGPNG 5MB</p> <p className="text-xs text-muted-foreground"> JPGPNG 5MB</p>
</div> </div>
<Button className="w-full" onClick={() => setSubmitted(true)}> <Button
className="w-full"
disabled={!verifyRole}
onClick={() => {
if (!verifyRole) return
submitVerification(verifyRole)
}}
>
</Button> </Button>
</CardContent> </CardContent>
+19 -1
View File
@@ -1,8 +1,16 @@
"use client"
import Link from "next/link"
import { AuthGuard } from "@/components/auth-guard" import { AuthGuard } from "@/components/auth-guard"
import { DashboardSidebar } from "@/components/dashboard-sidebar" import { DashboardSidebar } from "@/components/dashboard-sidebar"
import { Header } from "@/components/header" import { Header } from "@/components/header"
import { Button } from "@/components/ui/button"
import { useAuthStore } from "@/store/auth"
export default function DashboardLayout({ children }: { children: React.ReactNode }) { export default function DashboardLayout({ children }: { children: React.ReactNode }) {
const isAuthenticated = useAuthStore((state) => state.isAuthenticated)
const currentRole = useAuthStore((state) => state.currentRole)
return ( return (
<div className="flex min-h-screen flex-col"> <div className="flex min-h-screen flex-col">
<Header /> <Header />
@@ -11,7 +19,17 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
<DashboardSidebar /> <DashboardSidebar />
</div> </div>
<main className="flex-1 p-6"> <main className="flex-1 p-6">
<AuthGuard>{children}</AuthGuard> <AuthGuard>
{isAuthenticated && currentRole === "consumer" ? (
<div className="flex min-h-[50vh] items-center justify-center">
<Button asChild>
<Link href="/"></Link>
</Button>
</div>
) : (
children
)}
</AuthGuard>
</main> </main>
</div> </div>
</div> </div>
+8 -2
View File
@@ -1,6 +1,6 @@
"use client" "use client"
import { useEffect } from "react" import { useEffect, useRef } from "react"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { useAuthStore } from "@/store/auth" import { useAuthStore } from "@/store/auth"
import { useLoginDialogStore } from "@/store/login-dialog" import { useLoginDialogStore } from "@/store/login-dialog"
@@ -12,9 +12,15 @@ interface AuthGuardProps {
export function AuthGuard({ children }: AuthGuardProps) { export function AuthGuard({ children }: AuthGuardProps) {
const isAuthenticated = useAuthStore((s) => s.isAuthenticated) const isAuthenticated = useAuthStore((s) => s.isAuthenticated)
const openLoginDialog = useLoginDialogStore((s) => s.openLoginDialog) const openLoginDialog = useLoginDialogStore((s) => s.openLoginDialog)
const hasTriggered = useRef(false)
useEffect(() => { useEffect(() => {
if (!isAuthenticated) { if (isAuthenticated) {
hasTriggered.current = false
return
}
if (!hasTriggered.current) {
hasTriggered.current = true
openLoginDialog() openLoginDialog()
} }
}, [isAuthenticated, openLoginDialog]) }, [isAuthenticated, openLoginDialog])
+3
View File
@@ -1,4 +1,5 @@
export type UserRole = "consumer" | "player" | "owner" export type UserRole = "consumer" | "player" | "owner"
export type VerificationStatus = "pending" | "approved" | "rejected"
export interface User { export interface User {
id: string id: string
@@ -6,6 +7,8 @@ export interface User {
nickname: string nickname: string
avatar: string avatar: string
role: UserRole role: UserRole
verifiedRoles?: UserRole[]
verificationStatus?: Partial<Record<UserRole, VerificationStatus>>
phone?: string phone?: string
bio?: string bio?: string
createdAt: string createdAt: string
+25 -1
View File
@@ -1,12 +1,14 @@
import { create } from "zustand" import { create } from "zustand"
import type { User, UserRole } from "@/lib/types" import type { User, UserRole, VerificationStatus } from "@/lib/types"
interface AuthState { interface AuthState {
isAuthenticated: boolean isAuthenticated: boolean
currentRole: UserRole currentRole: UserRole
verifiedRoles: UserRole[] verifiedRoles: UserRole[]
verificationStatus: Partial<Record<UserRole, VerificationStatus>>
user: User | null user: User | null
switchRole: (role: UserRole) => void switchRole: (role: UserRole) => void
submitVerification: (role: UserRole) => void
login: (user: User, verifiedRoles?: UserRole[]) => void login: (user: User, verifiedRoles?: UserRole[]) => void
logout: () => void logout: () => void
} }
@@ -15,6 +17,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
isAuthenticated: false, isAuthenticated: false,
currentRole: "consumer", currentRole: "consumer",
verifiedRoles: ["consumer"], verifiedRoles: ["consumer"],
verificationStatus: { consumer: "approved" },
user: null, user: null,
switchRole: (role) => { switchRole: (role) => {
const { verifiedRoles } = get() const { verifiedRoles } = get()
@@ -22,18 +25,39 @@ export const useAuthStore = create<AuthState>((set, get) => ({
set({ currentRole: role }) set({ currentRole: role })
} }
}, },
submitVerification: (role) =>
set((state) => {
if (state.verifiedRoles.includes(role)) {
return state
}
return {
verificationStatus: {
...state.verificationStatus,
[role]: "pending",
},
}
}),
login: (user, verifiedRoles = ["consumer"]) => login: (user, verifiedRoles = ["consumer"]) =>
set({ set({
isAuthenticated: true, isAuthenticated: true,
user, user,
currentRole: user.role, currentRole: user.role,
verifiedRoles, verifiedRoles,
verificationStatus: verifiedRoles.reduce<Partial<Record<UserRole, VerificationStatus>>>(
(acc, role) => {
acc[role] = "approved"
return acc
},
{},
),
}), }),
logout: () => logout: () =>
set({ set({
isAuthenticated: false, isAuthenticated: false,
currentRole: "consumer", currentRole: "consumer",
verifiedRoles: ["consumer"], verifiedRoles: ["consumer"],
verificationStatus: { consumer: "approved" },
user: null, user: null,
}), }),
})) }))