import { useEffect, useRef, useState } from 'react' import { Hand, ListOrdered } from 'lucide-react' import { useLocalParticipant } from '@livekit/components-react' import { useIsOrganizer } from '@/hooks/useIsOrganizer' import type { HandQueueEntry } from '@/hooks/useChat' interface HandQueueMenuProps { queue: HandQueueEntry[] onLower: (identity: string) => void } /** * Кнопка «Очередь» в тулбаре с поповером над ней — видна ВСЕМ участникам * (сессия «28-hand-queue-for-all»: раньше очередь видел только организатор). * Опустить чужую запись может по-прежнему только организатор — обычный * участник видит кнопку «Опустить» только напротив СВОЕЙ записи (или не * видит её вовсе, если сам руку не поднимал): сервер (`api/chat.py`) всё * равно отклонит попытку опустить чужую руку кодом `forbidden`, но мёртвая * кнопка, которая молча не работает, хуже отсутствующей. * * Тот же самодостаточный паттерн, что и `StageViewMenu` («Вид»): * собственное состояние открытия, закрытие по клику вне/Escape, поповер * `.tb-menu` над кнопкой — а не боковая панель на весь экран (как чат): * очередь рук — короткий список, а не история переписки, разворачивать её * во весь экран незачем и на мобильном. * * Размер поповера подстраивается под число записей — `.hand-queue-list` * растёт вместе со списком и не даёт пустого места при 1–2 поднятых руках, * но не бесконечно: после ~10 строк список упирается в `max-height` и дальше * скроллится (см. room.css) — иначе участник на энергичной встрече получил * бы поповер выше экрана. */ export function HandQueueMenu({ queue, onLower }: HandQueueMenuProps) { const isOrganizer = useIsOrganizer() const { localParticipant } = useLocalParticipant() const [open, setOpen] = useState(false) const wrapRef = useRef(null) useEffect(() => { if (!open) return function handlePointerDown(event: MouseEvent) { if (wrapRef.current && !wrapRef.current.contains(event.target as Node)) { setOpen(false) } } function handleKeydown(event: KeyboardEvent) { if (event.key === 'Escape') setOpen(false) } document.addEventListener('mousedown', handlePointerDown) document.addEventListener('keydown', handleKeydown) return () => { document.removeEventListener('mousedown', handlePointerDown) document.removeEventListener('keydown', handleKeydown) } }, [open]) return (
{open && (
{queue.length === 0 ? (

Пока никто не поднял руку

) : (
    {queue.map((entry, index) => { const isOwn = entry.identity === localParticipant.identity const canLower = isOrganizer || isOwn return (
  1. {index + 1} {canLower && ( )}
  2. ) })}
)}
)}
) }