"use client"; import { useState, useRef, useCallback } from "react"; import { useAnimation } from "framer-motion"; import confetti from "canvas-confetti"; import type { DrawnIdea } from "@/components/BlindboxDrawnHistory"; import type { RoomInfo } from "@/hooks/useBlindboxRoom"; import type { UserProfile } from "@/types"; type Phase = "pool" | "shaking" | "reveal" | "time_select" | "planning" | "plan_reveal"; export function useBlindboxDraw( room: RoomInfo | null, profile: UserProfile | null, poolCount: number, setPoolCount: React.Dispatch>, setDrawnHistory: React.Dispatch>, setError: (e: string) => void, setPhase: (p: Phase) => void, ) { const [revealedIdea, setRevealedIdea] = useState(null); const [showShareCard, setShowShareCard] = useState(false); const boxControls = useAnimation(); const confettiAliveRef = useRef(false); const timersRef = useRef[]>([]); const fireConfetti = useCallback(() => { const colors = ["#a855f7", "#6366f1", "#ec4899", "#f59e0b", "#10b981"]; confetti({ particleCount: 100, spread: 120, origin: { y: 0.4 }, colors, startVelocity: 45, ticks: 250 }); confettiAliveRef.current = true; const end = Date.now() + 3000; const frame = () => { if (Date.now() > end || !confettiAliveRef.current) return; confetti({ particleCount: 3, angle: 60, spread: 55, origin: { x: 0, y: 0.6 }, colors, startVelocity: 35, ticks: 150 }); confetti({ particleCount: 3, angle: 120, spread: 55, origin: { x: 1, y: 0.6 }, colors, startVelocity: 35, ticks: 150 }); requestAnimationFrame(frame); }; timersRef.current.push(setTimeout(frame, 200)); }, []); const handleDraw = async () => { if (poolCount === 0 || !profile || !room) { setError("盒子是空的,先往里面塞点想法吧!"); return; } setPhase("shaking"); setError(""); await boxControls.start({ rotate: [0, -8, 8, -10, 10, -12, 12, -8, 8, -4, 4, 0], scale: [1, 1.05, 0.95, 1.08, 0.92, 1.1, 0.9, 1.05, 0.95, 1], transition: { duration: 2.5, ease: "easeInOut" }, }); try { const res = await fetch("/api/blindbox/draw", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ roomId: room.id, userId: profile.id }), }); if (!res.ok) { const data = await res.json(); throw new Error(data.error || "抽取失败"); } const idea = await res.json(); setRevealedIdea(idea); setPhase("reveal"); setPoolCount((c) => Math.max(0, c - 1)); setDrawnHistory((prev) => [idea, ...prev]); fireConfetti(); } catch (e) { setError(e instanceof Error ? e.message : "抽取失败"); setPhase("pool"); } }; const handleContinue = useCallback(() => { setPhase("pool"); setRevealedIdea(null); setShowShareCard(false); }, [setPhase]); return { revealedIdea, showShareCard, setShowShareCard, boxControls, fireConfetti, handleDraw, handleContinue, }; }