feat(ui): refine account pages

This commit is contained in:
zetaloop
2026-04-25 20:24:18 +08:00
parent 151fabe8c2
commit b0cecd58b0
4 changed files with 253 additions and 155 deletions
+33 -47
View File
@@ -11,6 +11,7 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
import { StatusBadge } from "@/components/ui/status-badge"
import {
applyCurrentUserVerification,
getCurrentUserForLogin,
@@ -21,7 +22,7 @@ import { toApiError } from "@/lib/errors"
import { notifyInfo, notifySuccess } from "@/lib/toast"
import type { UserRole } from "@/lib/types"
import { useAuthStore } from "@/store/auth"
import { CheckCircle, Clock, ShieldCheck, Upload } from "lucide-react"
import { CheckCircle, ShieldCheck, Upload } from "lucide-react"
import { useEffect, useState } from "react"
type MaterialKey = "idCardFront" | "idCardBack" | "gameScreenshot"
@@ -38,7 +39,7 @@ function MaterialUpload({
onSelect: (file: File) => Promise<void>
}) {
return (
<label 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">
<label className="h-24 w-24 rounded-lg border border-border/60 bg-muted/20 flex flex-col items-center justify-center gap-1.5 text-muted-foreground cursor-pointer hover:bg-accent/50 hover:border-border transition-colors">
<input
type="file"
accept="image/*"
@@ -52,10 +53,10 @@ function MaterialUpload({
target.value = ""
}}
/>
<Upload className="h-5 w-5" />
<span className="text-[10px]">{uploading ? "上传中..." : label}</span>
<Upload className="h-5 w-5 opacity-70" />
<span className="text-[10px] font-medium">{uploading ? "上传中..." : label}</span>
{value && (
<Badge variant="secondary" className="text-[10px] px-1.5 py-0">
<Badge variant="success" className="text-[10px] px-1.5 py-0 mt-0.5">
</Badge>
)}
@@ -155,14 +156,12 @@ export default function VerifyPage() {
}
return (
<div className="container mx-auto max-w-2xl px-4 py-8 space-y-6">
<div className="container mx-auto max-w-2xl px-4 py-8 space-y-8">
<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">
<section className="space-y-4">
<h2 className="text-base font-semibold"></h2>
<div className="rounded-xl border border-border/60 bg-muted/10 p-4 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>
@@ -171,64 +170,51 @@ export default function VerifyPage() {
<CheckCircle className="h-4 w-4 shrink-0 mt-0.5 text-primary" />
<span></span>
</div>
</CardContent>
</Card>
</div>
</section>
<Card>
<CardHeader>
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent className="space-y-3">
<section className="space-y-4">
<h2 className="text-base font-semibold"></h2>
<div className="rounded-xl border border-border/60 divide-y divide-border/60">
{roleMeta.map((item) => {
const status = statusFor(item.role)
const reason = reasonFor(item.role)
return (
<Card key={item.role} className="p-3 space-y-2 shadow-none">
<div key={item.role} className="flex flex-col gap-2 p-4">
<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>
<StatusBadge status="success"></StatusBadge>
) : status === "pending" ? (
<Badge variant="outline">
<Clock className="mr-1 h-3.5 w-3.5" />
</Badge>
<StatusBadge status="info"></StatusBadge>
) : status === "rejected" ? (
<Badge variant="outline" className="text-red-700 border-red-200 bg-red-50">
</Badge>
<StatusBadge status="destructive"></StatusBadge>
) : (
<Badge variant="secondary"></Badge>
<StatusBadge status="neutral"></StatusBadge>
)}
</div>
{status === "rejected" && (
<p className="text-xs text-muted-foreground">{reason}</p>
<div className="flex items-center justify-between mt-2">
<p className="text-xs text-muted-foreground">{reason}</p>
<Button variant="outline" size="sm" onClick={() => setVerifyRole(item.role)}>
</Button>
</div>
)}
{status === "rejected" && (
<Button variant="outline" size="sm" onClick={() => setVerifyRole(item.role)}>
</Button>
)}
</Card>
</div>
)
})}
</CardContent>
</Card>
</div>
</section>
<Card>
<Card className="border-border/60 shadow-sm">
<CardHeader>
<CardTitle className="text-base"></CardTitle>
</CardHeader>
<CardContent className="space-y-6">
<div className="space-y-2">
<div className="space-y-3">
<Label></Label>
<Select value={verifyRole} onValueChange={(value) => setVerifyRole(value as UserRole)}>
<SelectTrigger>
@@ -241,9 +227,9 @@ export default function VerifyPage() {
</Select>
</div>
<div className="space-y-2">
<div className="space-y-3">
<Label></Label>
<div className="flex gap-2">
<div className="flex flex-wrap gap-3">
<MaterialUpload
label="身份证正面"
value={idCardFront}