Files
meet/src/frontend/src/features/participants/hooks/useWaitingParticipants.ts
T
lebaudantoine 943b81676b (frontend) let authenticated users manage the lobby on trusted rooms
Frontend counterpart of the trusted-lobby backend feature: on
`trusted` rooms, any authenticated participant sees the waiting
notification and can accept or deny entry requests, not only admins
and owners.

Gating moves from role to capability: `useCanManageLobby` mirrors
the backend permission and derives from `useRoomData()`. Room
metadata is already synced into the query cache, so an access-level
change mid-meeting recomputes the capability on every client with no
new sync mechanism. It is only a UI gate; the backend re-checks
everything per request and fails closed.

Fetching moves into a single room-level `LobbyProvider`: the hook
was previously instantiated by two components and only worked
because React Query deduplicated their queries. The provider owns
one query and an explicit state machine - ways in (connection
established, ParticipantWaiting broadcast, panel opened, rights
regained while the panel is open) all arm and fetch; ways out
(rights lost, server 401/403) disarm and clear the cached list so
nothing stale can render.

Polling is tiered by audience since managers grow from a few admins
to potentially the whole room: 1s when acting (panel open),
10s when the notification is shown, and zero when the list is empty -
decided in the refetchInterval callback because structural sharing
suppresses data-keyed effects on identical empty responses. A quiet
room costs nothing; fetches are triggered by uncorrelated human
events, never synchronized across the room (the rights-regained
trigger is panel-gated for this reason).
2026-08-25 22:48:47 +02:00

69 lines
1.7 KiB
TypeScript

import { useMemo } from 'react'
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
import { useCanManageLobby } from '@/features/rooms/livekit/hooks/useCanManageLobby'
import { useEnterRoom } from '../api/enterRoom'
import {
useListWaitingParticipants,
type WaitingParticipant,
} from '../../participants/api/listWaitingParticipants'
import { reportError } from '@/features/analytics/telemetry'
export const useWaitingParticipants = () => {
const roomData = useRoomData()
const roomId = roomData?.id || '' // FIXME - bad practice
const canManageLobby = useCanManageLobby()
const { data: waitingData, refetch: refetchWaiting } =
useListWaitingParticipants(roomId, {
retry: false,
enabled: false,
})
const waitingParticipants = useMemo(
() => (canManageLobby ? waitingData?.participants || [] : []),
[waitingData, canManageLobby]
)
const { mutateAsync: enterRoom } = useEnterRoom()
const handleParticipantEntry = async (
participant: WaitingParticipant,
allowEntry: boolean
) => {
await enterRoom({
roomId: roomId,
allowEntry,
participantId: participant.id,
})
await refetchWaiting()
}
const handleParticipantsEntry = async (
allowEntry: boolean
): Promise<void> => {
try {
await Promise.all(
waitingParticipants.map((participant) =>
enterRoom({
roomId: roomId,
allowEntry,
participantId: participant.id,
})
)
)
await refetchWaiting()
} catch (e) {
reportError('generic_failure', e)
}
}
return {
waitingParticipants,
handleParticipantEntry,
handleParticipantsEntry,
}
}