"use client"; import { useMemo, useState } from "react"; import { MATCH, AI_PREDICTIONS, CROWD, LANDING_URL } from "@/lib/mockData"; import { outcomeLabel, pct } from "@/lib/format"; import type { Outcome, CrowdStats, ModelName } from "@/lib/types"; type Step = "pick" | "form" | "done"; const MODEL_COLOR: Record = { GPT: "var(--gpt)", Claude: "var(--claude)", Gemini: "var(--gemini)", }; const MODEL_ICON: Record = { GPT: "/icons/gpt.png", Claude: "/icons/claude.jpg", Gemini: "/icons/gemini.jpeg", }; export default function Arena() { const [outcome, setOutcome] = useState(null); const [scoreA, setScoreA] = useState(2); const [scoreB, setScoreB] = useState(1); const [step, setStep] = useState("pick"); const [nickname, setNickname] = useState(""); const [email, setEmail] = useState(""); const [notify, setNotify] = useState(true); const [crowd, setCrowd] = useState(CROWD); const [copied, setCopied] = useState(false); const locked = Date.now() >= new Date(MATCH.lockAt).getTime(); const matched = useMemo(() => { if (!outcome) return []; return AI_PREDICTIONS.filter((p) => p.outcome === outcome).map((p) => ({ model: p.model, exact: p.scoreA === scoreA && p.scoreB === scoreB, })); }, [outcome, scoreA, scoreB]); const submitPick = () => { if (!outcome) return; setStep("form"); }; const confirmSubmit = () => { if (nickname.trim().length < 2) return; setCrowd((c) => ({ ...c, total: c.total + 1, teamAWin: c.teamAWin + (outcome === "TEAM_A_WIN" ? 1 : 0), draw: c.draw + (outcome === "DRAW" ? 1 : 0), teamBWin: c.teamBWin + (outcome === "TEAM_B_WIN" ? 1 : 0), })); setStep("done"); }; const shareText = useMemo(() => { if (!outcome) return ""; const me = `${MATCH.teamA.shortName} ${scoreA}-${scoreB} ${MATCH.teamB.shortName}`; const sameAI = matched.map((m) => m.model).join("·"); return sameAI ? `나는 ${me}. ${sameAI}와 같은 선택! 너는? — TriplePick` : `나는 ${me}. AI 셋과 다 다른 선택! 너는? — TriplePick`; }, [outcome, scoreA, scoreB, matched]); const copyLink = async () => { try { await navigator.clipboard.writeText(`${shareText}\n${LANDING_URL}`); setCopied(true); setTimeout(() => setCopied(false), 1800); } catch { setCopied(false); } }; const nativeShare = async () => { if (navigator.share) { try { await navigator.share({ text: shareText, url: LANDING_URL }); } catch { /* cancelled */ } } else copyLink(); }; return ( <> {/* ===== 레이어드 화이트 시트 (002) ===== */}

AI의 예측

{AI_PREDICTIONS.map((p) => (
{p.model}
{p.model}
Confidence
{p.scoreA} - {p.scoreB}
{p.confidencePct}%

{p.reasonShort}

))}
{/* 당신의 선택 */}
Your Pick · 내 예측 당신의 선택
{( [ ["TEAM_A_WIN", `${MATCH.teamA.shortName} 승`], ["DRAW", "무승부"], ["TEAM_B_WIN", `${MATCH.teamB.shortName} 승`], ] as [Outcome, string][] ).map(([val, label]) => ( ))}
:
{/* ===== CTA 민트 #85FCA8 ===== */} {step === "pick" && ( )} {step === "form" && (
setNickname(e.target.value)} maxLength={16} placeholder="닉네임 (2~16자)" className="w-full rounded-lg border border-[var(--line-d)] bg-[#0f1217] px-3 py-3 text-[15px] text-white outline-none focus:border-[var(--green)]" /> setEmail(e.target.value)} placeholder="이메일 (선택 · 결과 알림)" className="w-full rounded-lg border border-[var(--line-d)] bg-[#0f1217] px-3 py-3 text-[15px] text-white outline-none focus:border-[var(--green)]" />
)} {step === "done" && outcome && (
내 예측
{MATCH.teamA.shortName} {scoreA}-{scoreB} {MATCH.teamB.shortName} {outcomeLabel(MATCH, outcome)}

{matched.length > 0 ? ( <> 당신은 {matched.map((m) => m.model).join("·")}와 같은 선택입니다.{matched.some((m) => m.exact) ? " 스코어까지 일치! " : " "} 나머지 AI는 생각이 다릅니다. ) : ( <>당신은 AI 셋 모두와 다른 선택! 소신 픽 🔥 )}

)} {/* ===== 골드 상금 (003) ===== */}
₩1,000,000 Final Challenge

NEW 정확한 스코어까지 맞히면 100만원 상금에 도전하세요

{/* ===== Crowd Pick (003) ===== */}
Crowd Pick{" "} | 참여자들의 선택
{crowd.total.toLocaleString()}명 참여
); } function Stepper({ label, value, onChange, disabled, }: { label: string; value: number; onChange: (n: number) => void; disabled?: boolean; }) { return (
onChange(Math.max(0, value - 1))}> −
{value} {label}
= 9} onClick={() => onChange(Math.min(9, value + 1))}> +
); } function StepBtn({ children, onClick, disabled, }: { children: React.ReactNode; onClick: () => void; disabled?: boolean; }) { return ( ); } function CrowdSeg({ flag, cze, value, tone, }: { flag?: string; cze?: boolean; value: number; tone: "kor" | "draw" | "cze"; }) { const bg = tone === "draw" ? "#2b313c" : tone === "kor" ? "rgba(62,224,138,0.22)" : "#222831"; return (
{flag && KOR} {cze && ( )} {value}%
); }