import { useState, useEffect, useRef } from 'react'; import { useParams, Link, useSearchParams } from 'react-router-dom'; import { Video, User, Lock, Shield, ArrowRight, Loader2, Users, Radio, AlertCircle, FileText, Clock, X } from 'lucide-react'; import BrandLogo from '../components/BrandLogo'; import api from '../services/api'; import toast from 'react-hot-toast'; import { useLanguage } from '../contexts/LanguageContext'; import { useAuth } from '../contexts/AuthContext'; import { useBranding } from '../contexts/BrandingContext'; export default function GuestJoin() { const { uid } = useParams(); const [searchParams] = useSearchParams(); const { t } = useLanguage(); const { user } = useAuth(); const { imprintUrl, privacyUrl } = useBranding(); const isLoggedIn = !!user; const [roomInfo, setRoomInfo] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [joining, setJoining] = useState(false); const [name, setName] = useState(user?.name || ''); const [accessCode, setAccessCode] = useState(searchParams.get('ac') || ''); const [moderatorCode, setModeratorCode] = useState(''); const [status, setStatus] = useState({ running: false }); const [recordingConsent, setRecordingConsent] = useState(false); const [waiting, setWaiting] = useState(false); const prevRunningRef = useRef(false); const joinMeeting = async () => { setJoining(true); try { const res = await api.post(`/rooms/${uid}/guest-join`, { name: name.trim(), access_code: accessCode || undefined, moderator_code: moderatorCode || undefined, }); if (res.data.joinUrl) { window.location.href = res.data.joinUrl; } } catch (err) { const errStatus = err.response?.status; if (errStatus === 403) { toast.error(t('room.guestWrongAccessCode')); setWaiting(false); } else { toast.error(t('room.guestJoinFailed')); setWaiting(false); } } finally { setJoining(false); } }; useEffect(() => { const fetchRoom = async () => { try { const res = await api.get(`/rooms/${uid}/public`); setRoomInfo(res.data.room); setStatus({ running: res.data.running }); prevRunningRef.current = res.data.running; } catch (err) { const status = err.response?.status; if (status === 403) { setError(t('room.guestAccessNotEnabled')); } else if (status === 404) { setError(t('room.guestRoomNotFound')); } else { setError(t('room.guestRoomNotFound')); } } finally { setLoading(false); } }; fetchRoom(); const interval = setInterval(async () => { try { const res = await api.get(`/rooms/${uid}/status`); setStatus(res.data); } catch { // ignore } }, 5000); return () => clearInterval(interval); }, [uid]); // Auto-join when meeting starts while waiting useEffect(() => { if (!prevRunningRef.current && status.running && waiting) { new Audio('/sounds/meeting-started.mp3').play().catch(() => {}); toast.success(t('room.guestMeetingStartedJoining')); joinMeeting(); } prevRunningRef.current = status.running; }, [status.running]); const handleJoin = async (e) => { e.preventDefault(); if (!name.trim()) { toast.error(t('room.guestNameRequired')); return; } if (roomInfo?.allow_recording && !recordingConsent) { toast.error(t('room.guestRecordingConsent')); return; } if (!status.running && !roomInfo?.anyone_can_start) { setWaiting(true); return; } await joinMeeting(); }; if (loading) { return (
{error}
{t('auth.login')}{t('room.guestCreatedBy')} {roomInfo.owner_name}
{t('room.guestWaitingTitle')}
{t('room.guestWaitingHint')}