207 lines
7.9 KiB
TypeScript
207 lines
7.9 KiB
TypeScript
"use client"
|
||
|
||
import { Badge } from "@/components/ui/badge"
|
||
import { Button } from "@/components/ui/button"
|
||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||
import { Input } from "@/components/ui/input"
|
||
import { Label } from "@/components/ui/label"
|
||
import {
|
||
Select,
|
||
SelectContent,
|
||
SelectItem,
|
||
SelectTrigger,
|
||
SelectValue,
|
||
} from "@/components/ui/select"
|
||
import { Separator } from "@/components/ui/separator"
|
||
import { Textarea } from "@/components/ui/textarea"
|
||
import type { UserRole } from "@/lib/types"
|
||
import { useAuthStore } from "@/store/auth"
|
||
import { CheckCircle, Clock, ShieldCheck, Upload } from "lucide-react"
|
||
import { useEffect, useRef, useState } from "react"
|
||
|
||
export default function VerifyPage() {
|
||
const [verifyRole, setVerifyRole] = useState<UserRole | "">("")
|
||
const verificationStatus = useAuthStore((state) => state.verificationStatus)
|
||
const verificationReasons = useAuthStore((state) => state.verificationReasons)
|
||
const verifiedRoles = useAuthStore((state) => state.verifiedRoles)
|
||
const submitVerification = useAuthStore((state) => state.submitVerification)
|
||
const approveVerification = useAuthStore((state) => state.approveVerification)
|
||
const timersRef = useRef<Map<UserRole, ReturnType<typeof setTimeout>>>(new Map())
|
||
|
||
useEffect(
|
||
() => () => {
|
||
timersRef.current.forEach((timer) => {
|
||
clearTimeout(timer)
|
||
})
|
||
timersRef.current.clear()
|
||
},
|
||
[],
|
||
)
|
||
|
||
const submitWithMockApproval = (role: UserRole) => {
|
||
submitVerification(role)
|
||
const oldTimer = timersRef.current.get(role)
|
||
if (oldTimer) {
|
||
clearTimeout(oldTimer)
|
||
}
|
||
const timer = setTimeout(() => {
|
||
approveVerification(role)
|
||
timersRef.current.delete(role)
|
||
}, 3000)
|
||
timersRef.current.set(role, timer)
|
||
}
|
||
|
||
const roleMeta: { role: UserRole; label: string }[] = [
|
||
{ role: "player", label: "打手认证" },
|
||
{ role: "owner", label: "店主认证" },
|
||
]
|
||
|
||
return (
|
||
<div className="container mx-auto max-w-2xl px-4 py-8 space-y-6">
|
||
<h1 className="text-2xl font-bold">身份认证</h1>
|
||
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle className="text-base">认证说明</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="space-y-3 text-sm text-muted-foreground">
|
||
<div className="flex items-start gap-2">
|
||
<ShieldCheck className="h-4 w-4 shrink-0 mt-0.5 text-primary" />
|
||
<span>通过身份认证后,你可以成为打手或店主,开始接单或经营店铺</span>
|
||
</div>
|
||
<div className="flex items-start gap-2">
|
||
<CheckCircle className="h-4 w-4 shrink-0 mt-0.5 text-primary" />
|
||
<span>认证信息仅用于平台审核,不会对外展示</span>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle className="text-base">认证状态</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="space-y-3">
|
||
{roleMeta.map((item) => {
|
||
const status = verificationStatus[item.role]
|
||
const reason = verificationReasons[item.role]
|
||
|
||
return (
|
||
<Card key={item.role} className="p-3 space-y-2 shadow-none">
|
||
<div className="flex items-center justify-between">
|
||
<span className="text-sm font-medium">{item.label}</span>
|
||
{status === "approved" || verifiedRoles.includes(item.role) ? (
|
||
<Badge
|
||
variant="outline"
|
||
className="text-green-700 border-green-200 bg-green-50"
|
||
>
|
||
已通过
|
||
</Badge>
|
||
) : status === "pending" ? (
|
||
<Badge variant="outline">
|
||
<Clock className="mr-1 h-3.5 w-3.5" />
|
||
审核中
|
||
</Badge>
|
||
) : status === "rejected" ? (
|
||
<Badge variant="outline" className="text-red-700 border-red-200 bg-red-50">
|
||
未通过
|
||
</Badge>
|
||
) : (
|
||
<Badge variant="secondary">未申请</Badge>
|
||
)}
|
||
</div>
|
||
|
||
{status === "rejected" && (
|
||
<p className="text-xs text-muted-foreground">驳回原因:{reason}</p>
|
||
)}
|
||
|
||
{status === "rejected" && (
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
onClick={() => submitWithMockApproval(item.role)}
|
||
>
|
||
重新提交
|
||
</Button>
|
||
)}
|
||
</Card>
|
||
)
|
||
})}
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle className="text-base">申请认证</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="space-y-6">
|
||
<div className="space-y-2">
|
||
<Label>认证类型</Label>
|
||
<Select value={verifyRole} onValueChange={(value) => setVerifyRole(value as UserRole)}>
|
||
<SelectTrigger>
|
||
<SelectValue placeholder="选择认证类型" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem value="player">打手认证</SelectItem>
|
||
<SelectItem value="owner">店主认证</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
|
||
<div className="space-y-2">
|
||
<Label htmlFor="real-name">真实姓名</Label>
|
||
<Input id="real-name" placeholder="请输入真实姓名" />
|
||
</div>
|
||
|
||
<div className="space-y-2">
|
||
<Label htmlFor="id-number">身份证号</Label>
|
||
<Input id="id-number" placeholder="请输入身份证号" />
|
||
</div>
|
||
|
||
<Separator />
|
||
|
||
<div className="space-y-2">
|
||
<Label>游戏资质(打手认证)</Label>
|
||
<Textarea placeholder="请描述你的游戏经历、段位、擅长游戏等" rows={3} />
|
||
</div>
|
||
|
||
<div className="space-y-2">
|
||
<Label>证明材料</Label>
|
||
<div className="flex gap-2">
|
||
<div className="h-24 w-24 rounded-md border-2 border-dashed border-muted-foreground/25 flex flex-col items-center justify-center gap-1 text-muted-foreground cursor-pointer hover:border-muted-foreground/50 transition-colors">
|
||
<Upload className="h-5 w-5" />
|
||
<span className="text-[10px]">身份证正面</span>
|
||
</div>
|
||
<div className="h-24 w-24 rounded-md border-2 border-dashed border-muted-foreground/25 flex flex-col items-center justify-center gap-1 text-muted-foreground cursor-pointer hover:border-muted-foreground/50 transition-colors">
|
||
<Upload className="h-5 w-5" />
|
||
<span className="text-[10px]">身份证反面</span>
|
||
</div>
|
||
<div className="h-24 w-24 rounded-md border-2 border-dashed border-muted-foreground/25 flex flex-col items-center justify-center gap-1 text-muted-foreground cursor-pointer hover:border-muted-foreground/50 transition-colors">
|
||
<Upload className="h-5 w-5" />
|
||
<span className="text-[10px]">游戏截图</span>
|
||
</div>
|
||
</div>
|
||
<p className="text-xs text-muted-foreground">支持 JPG、PNG 格式,单张不超过 5MB</p>
|
||
</div>
|
||
|
||
<Button
|
||
className="w-full"
|
||
disabled={
|
||
!verifyRole ||
|
||
verificationStatus[verifyRole] === "pending" ||
|
||
verificationStatus[verifyRole] === "approved"
|
||
}
|
||
onClick={() => {
|
||
if (!verifyRole) return
|
||
submitWithMockApproval(verifyRole)
|
||
}}
|
||
>
|
||
{verifyRole && verificationStatus[verifyRole] === "rejected"
|
||
? "重新提交认证申请"
|
||
: "提交认证申请"}
|
||
</Button>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
)
|
||
}
|