mirror of
https://github.com/suitenumerique/meet.git
synced 2026-09-02 21:58:29 +00:00
943b81676b
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).
69 lines
1.7 KiB
TypeScript
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,
|
|
}
|
|
}
|