"use client"; import { useState, useEffect, type FormEvent } from "react"; import Link from "next/link"; import SessionCoverImage from "../components/SessionCoverImage"; import { SESSIONS } from "@/config/home.config"; import CitySelect from "../components/CitySelect"; import ThemeToggle from "../components/ThemeToggle"; const ageOptions = ["18-24", "25-30", "31-35", "36-40", "40+"]; const statusOptions = [ { value: "student", label: "学生" }, { value: "working", label: "上班" }, { value: "freelance", label: "自由职业" }, { value: "startup", label: "创业" }, { value: "other", label: "其他" }, ]; const activityTypeOptions = [ { value: "loft", label: "loft民宿" }, { value: "side-hustle", label: "轻副业交流" }, { value: "any", label: "都可以" }, ]; const firstTimeOptions = ["是,第一次参加", "否,参加过类似活动"]; const availableTimeOptions = [ { value: "sat-pm", label: "周六下午" }, { value: "sun-pm", label: "周日下午" }, { value: "both", label: "都可以" }, ]; const REGIONS: Record = { 深圳: ["南山区", "福田区", "罗湖区", "宝安区", "龙岗区", "其他"], }; interface FormData { city: string; session: string; ageRange: string; status: string; activityType: string; intro: string; whyJoin: string; nickname: string; wechatOrPhone: string; xiaohongshuUrl: string; region: string; firstTime: string; availableTime: string; agreeRules: boolean; } function getSessionFromUrl(): string { if (typeof window === "undefined") return ""; return new URLSearchParams(window.location.search).get("session") || ""; } function getSessionInfo(sessionId: string) { return SESSIONS.find((s) => s.id === sessionId); } export default function JoinPage() { const [step, setStep] = useState<1 | 2>(1); const [form, setForm] = useState({ city: "", session: "", ageRange: "", status: "", activityType: "", intro: "", whyJoin: "", nickname: "", wechatOrPhone: "", xiaohongshuUrl: "", region: "", firstTime: "", availableTime: "", agreeRules: false, }); const [submitted, setSubmitted] = useState(false); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); useEffect(() => { const sid = getSessionFromUrl(); if (sid) { const s = SESSIONS.find((x) => x.id === sid); setForm((prev) => ({ ...prev, session: sid, city: s?.city || prev.city, })); } }, []); const set = (key: keyof FormData, value: string | boolean) => setForm((prev) => ({ ...prev, [key]: value })); const canProceedStep1 = form.city && form.session && form.ageRange && form.status && form.activityType && form.intro.trim() && form.whyJoin.trim(); const handleSubmit = async (e: FormEvent) => { e.preventDefault(); setError(null); setSubmitting(true); try { const reasonParts = [ form.intro, form.whyJoin, form.status && `状态: ${statusOptions.find((o) => o.value === form.status)?.label || form.status}`, form.activityType && `活动偏好: ${activityTypeOptions.find((o) => o.value === form.activityType)?.label || form.activityType}`, form.region && `常活动区域: ${form.region}`, form.availableTime && `可参加时间: ${availableTimeOptions.find((o) => o.value === form.availableTime)?.label || form.availableTime}`, ].filter(Boolean); const res = await fetch("/api/join", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ city: form.city, session: form.session, nickname: form.nickname, age_range: form.ageRange, wechat_or_phone: form.wechatOrPhone, xiaohongshu_url: form.xiaohongshuUrl.trim(), intro: reasonParts.join(" | "), first_time: form.firstTime, agree_rules: form.agreeRules, status: form.status, activity_type: form.activityType, why_join: form.whyJoin, region: form.region, available_time: form.availableTime, }), }); const data = await res.json(); if (!res.ok || !data?.ok) { throw new Error(data?.error || "提交失败,请稍后重试"); } setSubmitted(true); } catch (err) { setError(err instanceof Error ? err.message : "网络错误,请重试"); } finally { setSubmitting(false); } }; const selectedSession = getSessionInfo(form.session); const regions = form.city ? (REGIONS[form.city] || []) : []; if (submitted) { return (

报名成功

我们会尽快通过您留下的联系方式与您确认。不是所有报名都会自动确认,我们会根据场次与匹配度联系合适报名者。

← 返回首页
); } return (
{/* 顶部栏 */}
← 返回
{/* Trust bar */}
📍 公开场地 👥 6–8 人小组 🆓 不收费 🤝 尊重边界
📍 深圳

报名参加

填个表,我们会根据场次联系你~

不是所有报名都会确认,看场次匹配

{/* 进度提示 */}
{step === 1 ? "第一步" : "第二步"}
{selectedSession && (
{selectedSession.coverImage && (
)}

已选场次

{selectedSession.title}

{selectedSession.date} {selectedSession.time} · {selectedSession.place}

)}
{step === 1 ? (

基本信息

set("city", v)} required />

简单介绍

set("intro", e.target.value)} required className="form-input" /> set("whyJoin", e.target.value)} required className="form-input" />
) : (

联系方式与确认

set("nickname", e.target.value)} required className="form-input" />
set("wechatOrPhone", e.target.value)} required className="form-input" />

仅用于活动确认,不会公开给其他报名者

set("xiaohongshuUrl", e.target.value)} required className="form-input" />

用于展示头像与昵称,提交前会校验

提交后我们会根据场次与匹配度联系合适报名者,通过微信/短信确认地点与时间。若当前场次不匹配,不会反复打扰。

{error && (

{error}

)}
)}
← 返回首页
); } function Field({ label, children, }: { label: string; children: React.ReactNode; }) { return (
{children}
); }