projects/deliberation_at_scale/packages/frontend/hooks/useRoom.ts (123 lines of code) (raw):

import { useParams } from 'next/navigation'; import { alphabetical } from 'radash'; import { OutcomeType, ParticipantStatusType, RoomStatusType, useGetRoomOutcomesQuery, useGetRoomParticipantsQuery, useGetRoomsQuery } from "@/generated/graphql"; import useRealtimeQuery from "./useRealtimeQuery"; import { RoomId } from "@/state/slices/room"; import useRoomMessages from "./useRoomMessages"; import useProfile from './useProfile'; import { ENABLE_TEST_ROOM, ONE_SECOND_MS, TEST_EXTERNAL_ROOM_ID } from '@/utilities/constants'; import { useCallback, useMemo } from 'react'; export interface UseRoomOptions { roomId?: RoomId; } /** * A convenience function that will only return the external room id, so we * don't cause unnecessary re-renders in video outputs, leading to flickers. */ export function useExternalRoomId() { // Parse the roomId from the params const params = useParams(); const roomId = params?.roomId as RoomId; // Retrieve the room from Supabase const { data: roomData } = useGetRoomsQuery({ variables: { roomId, } }); // Find the correct node and room const roomNode = roomData?.roomsCollection?.edges?.find((roomEdge) => { return roomEdge?.node?.id === roomId; }); const room = roomNode?.node; // Return the room Id return ENABLE_TEST_ROOM ? TEST_EXTERNAL_ROOM_ID : room?.external_room_id; } export default function useRoom(options?: UseRoomOptions) { const params = useParams(); const paramsRoomId = params?.roomId as RoomId; const { roomId = paramsRoomId } = options ?? {}; const hasRoom = !!roomId; const { data: roomData, loading: loadingRooms, error: roomError } = useRealtimeQuery(useGetRoomsQuery({ variables: { roomId, }, })); const { data: participantsData, loading: loadingParticipants, error: participantsError } = useRealtimeQuery(useGetRoomParticipantsQuery({ variables: { roomId, }, }), { autoRefetch: hasRoom, autoRefetchIntervalMs: ONE_SECOND_MS * 5, }); const participants = !hasRoom ? [] : participantsData?.participantsCollection?.edges?.map(participant => participant.node); const participantIds = participants?.map(participant => participant.id); const { data: outcomesData } = useRealtimeQuery(useGetRoomOutcomesQuery({ variables: { roomId, }, }), { autoRefetch: hasRoom, autoRefetchIntervalMs: ONE_SECOND_MS * 10, tableEventsLookup: { opinions: { listenFilters: { INSERT: `participant_id=in.(${participantIds?.join(',')})`, } }, outcomes: { listenFilters: { INSERT: `room_id=in.(${roomId})`, } }, }, }); const { user } = useProfile(); const userId = user?.id; const roomNode = roomData?.roomsCollection?.edges?.find((roomEdge) => { return roomEdge?.node?.id === roomId; }); const room = roomNode?.node; const roomStatus = room?.status_type; const externalRoomId = ENABLE_TEST_ROOM ? TEST_EXTERNAL_ROOM_ID : room?.external_room_id; const departedParticipants = participants?.filter(participant => participant.status === ParticipantStatusType.EndOfSession) ?? []; const inactiveParticipants = participants?.filter(participant => participant.active === false) ?? []; const joiningParticipants = participants?.filter(participant => participant.status === ParticipantStatusType.WaitingForConfirmation) ?? []; const participant = participants?.find(participant => participant.user_id === userId); const participantId = participant?.id; const outcomes = useMemo(() => { const nodes = outcomesData?.outcomesCollection?.edges?.map((outcome) => outcome.node) ?? []; const sortedNodes = alphabetical(nodes, (outcome) => outcome.created_at, 'desc'); return sortedNodes; }, [outcomesData]); const lastOutcome = outcomes?.[0]; const roomMessagesTuple = useRoomMessages({ roomId, participants, userId }); const topic = room?.topics; const topicId = topic?.id; const isRoomEnded = (RoomStatusType.End === roomStatus); const getOutcomeByType = useCallback((type: OutcomeType) => { const outcome = outcomes?.find((outcome) => { return outcome.type === type; }); return outcome; }, [outcomes]); const hasOutcomeType = useCallback((type: OutcomeType) => { return !!getOutcomeByType(type); }, [getOutcomeByType]); return { // room room, externalRoomId, loadingRooms, roomError, roomId, roomStatus, isRoomEnded, // topic topic, topicId, // participants participants, participant, departedParticipants, inactiveParticipants, joiningParticipants, participantId, loadingParticipants, participantsError, // outcomes outcomes, lastOutcome, getOutcomeByType, hasOutcomeType, // messages ...roomMessagesTuple, }; }