'data'
This commit is contained in:
154
app/components/MyRegistrationStatus.tsx
Normal file
154
app/components/MyRegistrationStatus.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
const WECHAT_STORAGE_KEY = "salon_join_wechat";
|
||||
|
||||
interface RecordData {
|
||||
id?: string;
|
||||
wechatId?: string;
|
||||
nickname?: string;
|
||||
media?: string;
|
||||
is_volunteer?: boolean;
|
||||
}
|
||||
|
||||
interface UserRecord {
|
||||
hasRecord: boolean;
|
||||
record: RecordData | null;
|
||||
isComplete: boolean;
|
||||
isApproved: boolean;
|
||||
isRejected: boolean;
|
||||
vip: boolean;
|
||||
}
|
||||
|
||||
function getStatusLabel(data: UserRecord): string {
|
||||
if (data.isComplete || (data.vip && data.hasRecord)) return "报名成功";
|
||||
if (data.isRejected) return "审核拒绝";
|
||||
if (data.isApproved) return "审核通过";
|
||||
return "审核中";
|
||||
}
|
||||
|
||||
function getStatusColor(status: string): string {
|
||||
if (status === "报名成功") return "bg-emerald-50 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300";
|
||||
if (status === "审核通过") return "bg-emerald-50 dark:bg-emerald-900/30 text-emerald-600 dark:text-emerald-400";
|
||||
if (status === "审核拒绝") return "bg-red-50 dark:bg-red-900/30 text-red-600 dark:text-red-400";
|
||||
return "bg-amber-50 dark:bg-amber-900/30 text-amber-600 dark:text-amber-400";
|
||||
}
|
||||
|
||||
export default function MyRegistrationStatus() {
|
||||
const [data, setData] = useState<UserRecord | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const fetchStatus = () => {
|
||||
if (typeof window === "undefined") return;
|
||||
try {
|
||||
const stored = localStorage.getItem(WECHAT_STORAGE_KEY);
|
||||
const wechatId = (stored || "").trim();
|
||||
if (!wechatId) {
|
||||
setLoading(false);
|
||||
setData(null);
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
fetch(`/api/join/by-wechat?wechat_id=${encodeURIComponent(wechatId)}`)
|
||||
.then((r) => r.json())
|
||||
.then((d) => {
|
||||
if (d?.hasRecord) {
|
||||
const rec = d.record ?? null;
|
||||
setData({
|
||||
hasRecord: !!d.hasRecord,
|
||||
record: rec ? { ...rec, wechatId: rec.wechatId || wechatId } : null,
|
||||
isComplete: !!d.isComplete,
|
||||
isApproved: !!d.isApproved,
|
||||
isRejected: !!d.isRejected,
|
||||
vip: !!d.vip,
|
||||
});
|
||||
} else {
|
||||
setData(null);
|
||||
}
|
||||
})
|
||||
.catch(() => setData(null))
|
||||
.finally(() => setLoading(false));
|
||||
} catch {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined") return;
|
||||
let cancelled = false;
|
||||
fetchStatus();
|
||||
const onUpdate = () => {
|
||||
if (!cancelled) fetchStatus();
|
||||
};
|
||||
window.addEventListener("vip:updated", onUpdate);
|
||||
return () => {
|
||||
cancelled = true;
|
||||
window.removeEventListener("vip:updated", onUpdate);
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (loading || !data?.hasRecord || !data.record) return null;
|
||||
|
||||
const rec = data.record;
|
||||
const status = getStatusLabel(data);
|
||||
const statusColor = getStatusColor(status);
|
||||
|
||||
return (
|
||||
<section className="mb-8 sm:mb-10">
|
||||
<div className="rounded-xl sm:rounded-2xl bg-white dark:bg-stone-900/80 border border-stone-200/80 dark:border-stone-700/80 p-4 sm:p-6 overflow-hidden">
|
||||
<h3 className="text-sm font-medium text-stone-500 dark:text-stone-400 mb-3 flex items-center gap-2">
|
||||
<span>👤</span> 我的报名
|
||||
</h3>
|
||||
<div className="flex items-center gap-3 sm:gap-4">
|
||||
<div className="relative shrink-0">
|
||||
<div className="relative w-12 h-12 sm:w-14 sm:h-14 rounded-full overflow-hidden border-2 border-stone-200 dark:border-stone-600">
|
||||
{rec.media ? (
|
||||
<Image
|
||||
src={rec.media}
|
||||
alt=""
|
||||
fill
|
||||
sizes="56px"
|
||||
className="object-cover"
|
||||
unoptimized
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full h-full flex items-center justify-center bg-amber-100 dark:bg-amber-900/40 text-xl sm:text-2xl">
|
||||
👤
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{rec.is_volunteer && (
|
||||
<span className="absolute -bottom-1 left-1/2 -translate-x-1/2 px-1.5 py-0.5 rounded text-[10px] font-medium bg-amber-500 text-white whitespace-nowrap">
|
||||
志愿者
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="font-semibold text-stone-800 dark:text-stone-100 truncate">
|
||||
{rec.nickname || "—"}
|
||||
</p>
|
||||
{rec.wechatId && (
|
||||
<p className="text-xs text-stone-500 dark:text-stone-400 font-mono truncate mt-0.5">
|
||||
微信号: {rec.wechatId}
|
||||
</p>
|
||||
)}
|
||||
<span
|
||||
className={`inline-block mt-2 px-2.5 py-1 rounded-lg text-xs font-medium ${statusColor}`}
|
||||
>
|
||||
{status}
|
||||
</span>
|
||||
</div>
|
||||
<Link
|
||||
href="/join"
|
||||
className="shrink-0 text-sm font-medium text-amber-600 dark:text-amber-400 hover:text-amber-700 dark:hover:text-amber-300"
|
||||
>
|
||||
查看详情 →
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user