"use client"; import { useState, useRef, useEffect, type FormEvent, type ChangeEvent } from "react"; import Link from "next/link"; import { getPayEnv, redirectToPay, getDeviceFromEnv, } from "@/app/lib/payment"; import { usePayStatusPoll } from "@/app/lib/payment/usePayStatusPoll"; import AuthModal from "@/app/components/AuthModal"; const genderOptions = ["男", "女"]; const singleOptions = ["单身", "恋爱中", "已婚"]; const educationOptions = ["高中及以下", "大专", "本科", "硕士", "博士"]; const graduationYears = Array.from({ length: 41 }, (_, i) => String(2026 - i)); interface FormData { nickname: string; gender: string; single: string; profession: string; intro: string; wechat: string; education: string; graduationYear: string; phone: string; } interface MediaInfo { preview: string; url: string; type: "image" | "video"; } export default function JoinPage() { const [form, setForm] = useState({ nickname: "", gender: "", single: "", profession: "", intro: "", wechat: "", education: "", graduationYear: "", phone: "", }); const [media, setMedia] = useState(null); const [uploading, setUploading] = useState(false); const fileRef = useRef(null); const [submitted, setSubmitted] = useState(false); const [isVipSubmit, setIsVipSubmit] = useState(false); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); const [payRedirecting, setPayRedirecting] = useState(false); const [authOpen, setAuthOpen] = useState(false); const [pendingSubmit, setPendingSubmit] = useState(false); const [isAlreadyRecorded, setIsAlreadyRecorded] = useState(false); const [checkingStatus, setCheckingStatus] = useState(true); useEffect(() => { if (typeof window !== "undefined" && new URLSearchParams(window.location.search).get("paid") === "1") { setSubmitted(true); setCheckingStatus(false); return; } const checkExisting = async () => { const meRes = await fetch("/api/auth/me", { credentials: "include" }); const meData = await meRes.json(); if (!meData?.user) { setCheckingStatus(false); return; } const statusRes = await fetch("/api/join/status", { credentials: "include", cache: "no-store" }); const statusData = await statusRes.json(); if (statusData?.hasRecord && statusData?.isComplete) { setIsAlreadyRecorded(true); setSubmitted(true); } setCheckingStatus(false); }; checkExisting(); }, []); usePayStatusPoll((orderId) => { if (typeof window === "undefined") return; const paidPath = "/join/paid"; const url = orderId ? `${paidPath}?order_id=${encodeURIComponent(orderId)}` : paidPath; window.location.replace(url); }); const set = (key: keyof FormData, value: string) => setForm((prev) => ({ ...prev, [key]: value })); const doSubmit = async () => { setError(null); setSubmitting(true); try { const res = await fetch("/api/join", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...form, media: media?.url }), credentials: "include", }); const data = await res.json(); if (!res.ok || !data?.ok) { throw new Error(data?.error || "提交失败,请稍后重试"); } const userId = data.user_id; if (!userId) { setSubmitted(true); return; } const vipRes2 = await fetch("/api/vip/check", { credentials: "include", cache: "no-store" }); const vipData2 = await vipRes2.json(); if (vipData2?.vip) { setIsVipSubmit(true); setSubmitted(true); setSubmitting(false); return; } setSubmitting(false); setPayRedirecting(true); const returnUrl = `${window.location.origin}/join/paid`; const env = getPayEnv(); const channel = "wxpay"; const device = getDeviceFromEnv(env); redirectToPay({ user_id: userId, return_url: returnUrl, channel, device, useJoinConfig: true, }); return; } catch (err) { setError(err instanceof Error ? err.message : "网络错误,请重试"); } finally { setSubmitting(false); } }; const handleSubmit = async (e: FormEvent) => { e.preventDefault(); const meRes = await fetch("/api/auth/me", { credentials: "include" }); const meData = await meRes.json(); if (!meData?.user) { setPendingSubmit(true); setAuthOpen(true); return; } const vipRes = await fetch("/api/vip/check", { credentials: "include", cache: "no-store" }); const vipData = await vipRes.json(); if (vipData?.vip) { setIsVipSubmit(true); } await doSubmit(); }; const handleAuthSuccess = () => { setAuthOpen(false); if (pendingSubmit) { setPendingSubmit(false); doSubmit(); } }; if (submitted) { return (

{isAlreadyRecorded ? "资料已录入" : isVipSubmit ? "提交成功" : "支付成功"}

{isAlreadyRecorded ? "您的报名信息已录入,无需重复提交" : isVipSubmit ? "感谢您的参与" : "感谢您的支持"}

← 返回首页
); } if (checkingStatus) { return (
加载中…
); } return (
🌍
数字游民社区

🌍 数字游民社区报名

{"💼 结识志同道合的伙伴\n📍 线下聚会 + 线上分享\n🤝 互助成长,资源共享"}

set("nickname", e.target.value)} required className="form-input" />
set("profession", e.target.value)} required className="form-input" />
set("wechat", e.target.value)} required className="form-input" /> { const v = e.target.value.replace(/\D/g, "").slice(0, 11); set("phone", v); }} required className="form-input" />