"use client"; import { useState, useEffect, type FormEvent } from "react"; import { useParams, useRouter } from "next/navigation"; import WaitingRoom from "@/components/lobby/WaitingRoom"; type RoomInfo = { id: string; name: string; code: string; status: string; hostId: string; lobbyEnabled: boolean; hasPin: boolean; webinarMode: boolean; }; export default function JoinCodePage() { const params = useParams<{ code: string }>(); const router = useRouter(); const [room, setRoom] = useState(null); const [displayName, setDisplayName] = useState(""); const [pin, setPin] = useState(""); const [error, setError] = useState(""); const [loading, setLoading] = useState(true); const [joining, setJoining] = useState(false); const [inLobby, setInLobby] = useState(false); const [sessionId] = useState(() => crypto.randomUUID()); const [sessionFingerprint] = useState(() => { // Generate a persistent fingerprint based on browser characteristics const nav = typeof navigator !== "undefined" ? navigator : null; const raw = [ nav?.userAgent ?? "", nav?.language ?? "", screen?.width ?? "", screen?.height ?? "", Intl.DateTimeFormat().resolvedOptions().timeZone ?? "", ].join("|"); // Simple hash let hash = 0; for (let i = 0; i < raw.length; i++) { hash = ((hash << 5) - hash + raw.charCodeAt(i)) | 0; } return Math.abs(hash).toString(36); }); useEffect(() => { async function fetchRoom() { try { const res = await fetch(`/api/rooms/by-code/${params.code}`); if (!res.ok) { setError("Комната не найдена"); return; } const roomData = await res.json(); setRoom(roomData); } catch { setError("Ошибка загрузки комнаты"); } finally { setLoading(false); } } fetchRoom(); }, [params.code]); async function handleJoin(e: FormEvent) { e.preventDefault(); if (!room) return; setError(""); setJoining(true); try { const res = await fetch(`/api/rooms/${room.id}/join`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ displayName, pin: pin || undefined, sessionId, sessionFingerprint, }), }); const data = await res.json(); if (!res.ok) { setError(data.error ?? "Ошибка при подключении"); setJoining(false); return; } if (data.status === "lobby") { setInLobby(true); } else if (data.status === "approved" && data.token) { router.push(`/room/${room.code}?token=${encodeURIComponent(data.token)}`); } } catch { setError("Произошла ошибка. Попробуйте ещё раз."); setJoining(false); } } function handleApproved(token: string) { if (room) { router.push(`/room/${room.code}?token=${encodeURIComponent(token)}`); } } if (loading) { return (

Загрузка...

); } if (inLobby && room) { return ( ); } const statusLabel: Record = { active: { text: "Активна", color: "bg-success/10 text-success border-success/20" }, waiting: { text: "Ожидание", color: "bg-warning/10 text-warning border-warning/20" }, finished: { text: "Завершена", color: "bg-surface-3/50 text-text-muted border-border-default" }, }; return (
{room ? ( <> {/* Room info header */}

{room.name}

{statusLabel[room.status] && ( {statusLabel[room.status].text} )}
{room.code}
{error && (
{error}
)}
setDisplayName(e.target.value)} className="w-full bg-surface-2 border border-border-default rounded-lg px-4 py-3 text-white placeholder:text-text-muted focus:border-accent focus:ring-1 focus:ring-accent outline-none transition" placeholder="Иван" />
{room.hasPin && (
setPin(e.target.value)} className="w-full bg-surface-2 border border-border-default rounded-lg px-4 py-3 text-white text-center font-mono tracking-widest placeholder:text-text-muted focus:border-accent focus:ring-1 focus:ring-accent outline-none transition" placeholder="1234" maxLength={8} />
)}
) : (

{error || "Комната не найдена"}

Проверьте код и попробуйте снова

)}
); }