import { useEffect } from 'react' import { useLocalParticipant } from '@livekit/components-react' import { useToast } from '@/components/ui/ToastProvider' import type { ForcedMuteEvent } from '@/hooks/useChat' /** * Уведомляет ЛОКАЛЬНОГО участника тостом, когда организатор принудительно * выключил его микрофон/камеру (задача B2). Рендерится безусловно внутри * `` — `useLocalParticipant` недоступен снаружи (`RoomPage` * сам вне контекста LiveKit, см. докстринг `useIsOrganizer`). * * Само выключение трека организатор делает СЕРВЕРНЫМ вызовом LiveKit API * (`services/room_control.py`) — тулбарные кнопки (useTrackToggle) сами * отразят новое состояние по родному событию LiveKit `TrackMuted`, этот * компонент только поясняет ПОЧЕМУ: без тоста человек не отличил бы * действие организатора от случайного глюка. Участник может включить себя * обратно сразу тем же тулбаром — сервер это не блокирует (см. докстринг B2 * в CHANGELOG/коммите). */ export function ForcedMuteWatcher({ event }: { event: ForcedMuteEvent | null }) { const { localParticipant } = useLocalParticipant() const toast = useToast() useEffect(() => { if (!event || event.identity !== localParticipant.identity) return toast.show( event.source === 'microphone' ? 'Организатор выключил ваш микрофон' : 'Организатор выключил вашу камеру', 'info', ) // `event` (включая `nonce`) — единственная зависимость, которая должна // повторно показывать тост; `localParticipant`/`toast` стабильны в // рамках подключения и намеренно не входят в список, чтобы их // пересоздание (если когда-нибудь случится) не дублировало уведомление. // eslint-disable-next-line react-hooks/exhaustive-deps }, [event]) return null }