"use client"; import { useMemo, useState, useEffect } from "react"; import Link from "next/link"; import { api } from "@/lib/api"; import { useToast } from "@/lib/toast"; import { useAuth } from "@/lib/auth"; import { useI18n } from "@/lib/i18n"; import type { Meetup } from "@/lib/types"; import NewsletterSubscribe from "@/components/NewsletterSubscribe"; import RingNext from "@/components/RingNext"; import { useRingSteps } from "@/lib/rings"; const MODE_LABELS: Record = { online: "💻 线上", offline: "📍 线下", hybrid: "🔀 混合", }; interface Props { meetups: Meetup[]; } export default function MeetupsClient({ meetups }: Props) { const { t } = useI18n(); const rings = useRingSteps(); const { toast } = useToast(); const { token } = useAuth(); const [mode, setMode] = useState<"all" | Meetup["mode"]>("all"); const [rsvpIds, setRsvpIds] = useState>(new Set()); useEffect(() => { if (!token) return; api.getMyRsvps(token).then((r) => setRsvpIds(new Set(r.ids))).catch(() => {}); }, [token]); const filtered = useMemo(() => { if (mode === "all") return meetups; return meetups.filter((m) => m.mode === mode); }, [meetups, mode]); const handleRsvp = async (meetup: Meetup) => { if (rsvpIds.has(meetup.id)) { toast(t.meetups.alreadyRsvp, "info"); return; } try { const res = await api.rsvpMeetup(meetup.id, undefined, token || undefined); const next = new Set(rsvpIds).add(meetup.id); setRsvpIds(next); toast(res.message || t.meetups.rsvpOk, "success"); } catch { toast(t.meetups.rsvpFail, "error"); } }; return (
{t.meetups.tag}

{t.meetups.title}

{t.meetups.subtitle}

{t.meetups.hostBtn} {(["all", "online", "offline", "hybrid"] as const).map((m) => ( ))}
{filtered.map((m) => (
{m.emoji}

{m.title}

{MODE_LABELS[m.mode]} · {m.city} · {m.date} {m.time}

{m.description}

📍 {m.venue}

{m.tags.map((tag) => ( {tag} ))}
{m.rsvp_count}/{m.max_attendees} {t.meetups.rsvp} {m.organizer}
{(m.mode === "online" || m.mode === "hybrid") && ( {t.meetups.liveBtn} )}
{m.destination_slug && ( {t.meetups.viewCity} → )}
))}
{filtered.length === 0 && (

{t.meetups.empty}

)}
); }