"use client"; import { useEffect, useMemo, useRef, useState } from "react"; import { Link, useTranslation } from "@/i18n/navigation"; import Footer from "@/app/components/Footer"; import { apiFetch } from "@/app/lib/api-client"; import { mediaUrl } from "@/app/lib/media"; import { avatarForIndex, avatarForName } from "@/app/data/avatars"; type TabType = "friends" | "dating" | "partner" | "roommate" | "cofounder" | "explore"; interface Profile { id: string; name: string; age: number; location: string; tags: string[]; bio: string; gradient: string; initial: string; avatarColor: string; photo: string; } interface MatchCard { id: string; name: string; location: string; timeAgo: string; initial: string; color: string; photo: string; } interface ProfileRecord { id: string; name?: string; age?: number; location?: string; tags?: string[]; bio?: string; photo?: string; } const FALLBACK_PROFILES: Profile[] = [ { id: "1", name: "林晓雨", age: 28, location: "大理", tags: ["本科学历", "远程工作者", "数字游民", "咖啡爱好者"], bio: "数字游民三年,目前在云南大理远程做产品设计。喜欢爬山、摄影,周末常去洱海边发呆。", gradient: "from-rose-400 via-pink-400 to-fuchsia-400", initial: "林", avatarColor: "bg-rose-500", photo: avatarForIndex(0) }, { id: "2", name: "陈浩然", age: 32, location: "成都", tags: ["硕士学历", "独立开发者", "自由职业者", "素食主义"], bio: "在成都住了两年,做独立开发。喜欢冲浪和冥想,寻找志同道合的旅伴一起探索世界。", gradient: "from-amber-400 via-orange-400 to-red-400", initial: "陈", avatarColor: "bg-amber-500", photo: avatarForIndex(4) }, { id: "3", name: "王思琪", age: 26, location: "深圳", tags: ["本科学历", "内容创作者", "数字游民", "环保主义者"], bio: "自由撰稿人,在深圳写写画画。热爱瑜伽和冥想,相信慢生活才是真正的奢侈。", gradient: "from-emerald-400 via-teal-400 to-cyan-400", initial: "王", avatarColor: "bg-emerald-500", photo: avatarForIndex(2) }, { id: "4", name: "张明远", age: 30, location: "杭州", tags: ["MBA学历", "创业中", "自由职业者", "徒步爱好者"], bio: "正在杭州创业,做远程团队协作工具。周末喜欢去西湖徒步,偶尔品鉴龙井茶。", gradient: "from-violet-400 via-purple-400 to-indigo-400", initial: "张", avatarColor: "bg-violet-500", photo: avatarForIndex(28) }, { id: "5", name: "李雅婷", age: 27, location: "厦门", tags: ["本科学历", "UI设计师", "数字游民", "摄影爱好者"], bio: "在厦门远程做UI设计,业余时间探索闽南美食。喜欢用相机记录生活,寻找一起探店的朋友。", gradient: "from-rose-500 via-red-400 to-orange-500", initial: "李", avatarColor: "bg-rose-500", photo: avatarForIndex(12) }, { id: "6", name: "刘子轩", age: 33, location: "昆明", tags: ["博士学历", "数据科学家", "远程工作者", "户外爱好者"], bio: "在昆明远程工作,热爱户外运动。正在探索云南各地,希望认识更多志同道合的朋友。", gradient: "from-blue-400 via-indigo-400 to-violet-500", initial: "刘", avatarColor: "bg-blue-500", photo: avatarForIndex(10) }, ]; const FALLBACK_MATCHES: MatchCard[] = [ { id: "m1", name: "周雨桐", location: "杭州", timeAgo: "2天前", initial: "周", color: "bg-pink-400", photo: avatarForIndex(6) }, { id: "m2", name: "吴俊杰", location: "成都", timeAgo: "1周前", initial: "吴", color: "bg-amber-400", photo: avatarForIndex(30) }, { id: "m3", name: "郑诗涵", location: "上海", timeAgo: "3周前", initial: "郑", color: "bg-emerald-400", photo: avatarForIndex(15) }, { id: "m4", name: "孙宇航", location: "深圳", timeAgo: "1月前", initial: "孙", color: "bg-violet-400", photo: avatarForIndex(18) }, { id: "m5", name: "赵梦琪", location: "厦门", timeAgo: "1年前", initial: "赵", color: "bg-rose-400", photo: avatarForIndex(24) }, ]; const TAB_ORDER: TabType[] = ["friends", "dating", "partner", "roommate", "cofounder", "explore"]; const PROFILE_GRADIENTS = [ "from-rose-400 via-pink-400 to-fuchsia-400", "from-amber-400 via-orange-400 to-red-400", "from-emerald-400 via-teal-400 to-cyan-400", "from-violet-400 via-purple-400 to-indigo-400", "from-blue-400 via-indigo-400 to-violet-500", ]; function mapProfile(record: ProfileRecord, index: number): Profile { const name = record.name || "数字游民"; const initial = name.slice(0, 1); return { id: record.id, name, age: Number(record.age || 28 + index), location: record.location || "远程", tags: Array.isArray(record.tags) ? record.tags : ["数字游民", "远程工作者"], bio: record.bio || "正在完善个人资料,期待结识同城和同路的远程工作伙伴。", gradient: PROFILE_GRADIENTS[index % PROFILE_GRADIENTS.length], initial, avatarColor: "bg-[#ff4d4f]", photo: record.photo || avatarForName(name), }; } function toMatch(profile: Profile, index: number): MatchCard { return { id: `m-${profile.id}`, name: profile.name, location: profile.location, timeAgo: index < 2 ? "刚刚活跃" : "本周活跃", initial: profile.initial, color: profile.avatarColor, photo: profile.photo, }; } export default function DatingPage() { const { t } = useTranslation("match"); const [activeTab, setActiveTab] = useState("friends"); const [currentIndex, setCurrentIndex] = useState(0); const [profiles, setProfiles] = useState(FALLBACK_PROFILES); const [dragX, setDragX] = useState(0); const [isDragging, setIsDragging] = useState(false); const [isAnimatingOut, setIsAnimatingOut] = useState<"left" | "right" | null>(null); const startXRef = useRef(0); useEffect(() => { apiFetch<{ items: ProfileRecord[] }>("/api/profiles") .then((data) => { if (data.items?.length) { setProfiles(data.items.map(mapProfile)); setCurrentIndex(0); } }) .catch(() => setProfiles(FALLBACK_PROFILES)); }, []); const matches = useMemo( () => (profiles.length ? profiles.slice(0, 5).map(toMatch) : FALLBACK_MATCHES), [profiles] ); const currentProfile = profiles[currentIndex] || profiles[0] || FALLBACK_PROFILES[0]; const hasMoreProfiles = currentIndex < profiles.length - 1; const saveSwipe = (action: "like" | "dislike") => { if (!currentProfile) return; apiFetch("/api/matches/swipes", { method: "POST", body: JSON.stringify({ profileId: currentProfile.id, action }), }).catch(() => {}); }; const nextProfile = () => { window.setTimeout(() => { setCurrentIndex((i) => (hasMoreProfiles ? i + 1 : 0)); setDragX(0); setIsAnimatingOut(null); }, 160); }; const handleLike = () => { saveSwipe("like"); setIsAnimatingOut("right"); setDragX(260); nextProfile(); }; const handleDislike = () => { saveSwipe("dislike"); setIsAnimatingOut("left"); setDragX(-260); nextProfile(); }; const beginDrag = (clientX: number) => { startXRef.current = clientX; setIsDragging(true); }; const moveDrag = (clientX: number) => { if (!isDragging) return; setDragX(Math.max(-180, Math.min(180, clientX - startXRef.current))); }; const endDrag = () => { if (!isDragging) return; setIsDragging(false); if (dragX > 90) { handleLike(); return; } if (dragX < -90) { handleDislike(); return; } setDragX(0); }; const badgeMap: Record = { friends: t("badgeFriends"), dating: t("badgeDating"), partner: t("badgePartner"), roommate: t("badgeRoommate"), cofounder: t("badgeCofounder"), explore: t("badgeExplore"), }; const badgeText = badgeMap[activeTab]; return (
{TAB_ORDER.map((tab) => ( ))}
{ if (e.key === "ArrowRight") handleLike(); if (e.key === "ArrowLeft") handleDislike(); }} onPointerDown={(e) => { e.currentTarget.setPointerCapture(e.pointerId); beginDrag(e.clientX); }} onPointerMove={(e) => moveDrag(e.clientX)} onPointerUp={endDrag} onPointerCancel={endDrag} >
45 ? "opacity-100" : "opacity-0"}`}> 喜欢
跳过
{badgeText} {t("report")}
{currentProfile.name}

{currentProfile.name},{currentProfile.age}

📍 {currentProfile.location}

{t("matchTags")}:

{currentProfile.tags.map((tag) => ( {tag} ))}

{currentProfile.bio}

{t("dislike")}
{t("like")}

{currentIndex + 1} / {profiles.length}

); }