in projects/deliberation_at_scale/packages/frontend/hooks/useLobby.ts [16:132]
export default function useLobby() {
const { user, nickName } = useProfile();
const { id: userId } = user ?? {};
const [confirmingParticipantId, setConfirmingParticipantId] = useState<string | null>(null);
const [lastCreatedAt, setLastCreatedAt] = useState<Dayjs | null>(null);
const isConfirming = !!confirmingParticipantId;
const { data: participantData,
loading: participantsLoading,
refetch: rawRefetchParticipants,
} = useRealtimeQuery(useGetLobbyParticipantsQuery({
variables: {
userId,
},
}));
const refetchParticipants = useCallback(() => {
rawRefetchParticipants({
variables: {
userId,
},
});
}, [rawRefetchParticipants, userId]);
const [createParticipant, { loading: isCreatingParticipant }] = useCreateParticipantMutation();
const [enterRoomMutation, { loading: isEnteringRoom }] = useEnterRoomMutation();
const participants = useMemo(() => {
return participantData?.participantsCollection?.edges?.map((edge) => edge?.node) ?? [];
}, [participantData?.participantsCollection?.edges]);
const candidateParticipant = participants.find((participant) => {
return participant?.status === ParticipantStatusType.Queued || participant?.status === ParticipantStatusType.WaitingForConfirmation;
});
const candidateParticipantId = candidateParticipant?.id;
const candidateRoomId = candidateParticipant?.room_id;
const confirmingParticipant = participants.find((participant) => participant?.id === confirmingParticipantId);
const canEnterRoom = !!confirmingParticipantId && (confirmingParticipant?.status === ParticipantStatusType.WaitingForConfirmation);
const { push } = useLocalizedPush();
const enterRoom = useCallback(async () => {
const enterResult = await enterRoomMutation({
variables: {
participantId: candidateParticipantId,
},
});
const isEntered = (enterResult.data?.updateparticipantsCollection?.affectedCount ?? 0) > 0;
const roomId = enterResult.data?.updateparticipantsCollection.records[0]?.room_id;
if (!isEntered || !roomId) {
// TODO: handle not being able to enter room?
// eslint-disable-next-line no-console
console.error('Could not enter room for participant ID: ', candidateParticipantId);
return;
}
push(`/room/${roomId}`);
}, [candidateParticipantId, enterRoomMutation, push]);
// ping the participant entry to make sure it is still alive for the group slicer
usePingParticipant(candidateParticipant);
usePingParticipant(confirmingParticipant);
// create a queued participant when the user has none yet
// block this when no valid user is found OR when we are already waiting for a confirm
useEffect(() => {
const hasValidCandidate = !!candidateParticipant
&& candidateParticipant.status !== ParticipantStatusType.EndOfSession
&& candidateParticipant.active === true;
// && Math.abs(dayjs().diff(dayjs(lastCreatedAt), 'ms')) <= ONE_SECOND_MS * 60 * 2;
if (participantsLoading || hasValidCandidate || !userId || isConfirming || isCreatingParticipant) {
return;
}
// create new participant
setLastCreatedAt(dayjs());
createParticipant({
variables: {
userId,
nickName,
},
}).then(() => {
refetchParticipants();
});
}, [participantsLoading, candidateParticipant, createParticipant, userId, refetchParticipants, isConfirming, isCreatingParticipant, setLastCreatedAt, lastCreatedAt, nickName]);
// store the the participant ID when a confirm is requested
// this will help us redirect the user back to the timed out flow when not responding quickly enough
useEffect(() => {
if (candidateParticipant?.status === ParticipantStatusType.WaitingForConfirmation) {
setConfirmingParticipantId(candidateParticipantId);
}
}, [candidateParticipant, setConfirmingParticipantId, candidateParticipantId]);
// navigate to the page to mention the timeout
useEffect(() => {
// console.log('isConfirming', isConfirming);
// console.log('confirmingParticipantId', confirmingParticipantId);
// console.log('confirmingParticipant', confirmingParticipant);
// console.log('candidateParticipant', candidateParticipant);
// console.log('participants', participants);
if (isConfirming && (!confirmingParticipant || confirmingParticipant.status === ParticipantStatusType.EndOfSession)) {
push('/lobby/idle');
}
}, [confirmingParticipant, confirmingParticipantId, isConfirming, participants, candidateParticipant, push]);
// refetch participants when the user id changes
useEffect(() => {
refetchParticipants();
}, [userId, refetchParticipants]);
return {
candidateParticipant,
candidateRoomId,
canEnterRoom,
isConfirming,
confirmingParticipant,
isEnteringRoom,
enterRoom,
};
}