projects/deliberation_at_scale/packages/frontend/hooks/usePingParticipant.ts (41 lines of code) (raw):
import { useEffect, useState } from "react";
import { FullParticipantFragment, usePingParticipantMutation } from "@/generated/graphql";
import { PARTICIPANT_PING_INTERVAL_DELAY_MS } from "@/utilities/constants";
import useLocalizedPush from "./useLocalizedPush";
import { supabaseClient } from "@/state/supabase";
const MAX_FAILED_PINGS = 10;
export function usePingParticipant(candidateParticipant?: FullParticipantFragment) {
const participantId = candidateParticipant?.id;
const participantActive = candidateParticipant?.active;
const participantStatus = candidateParticipant?.status;
const [ping, { loading, error, data }] = usePingParticipantMutation();
const { push } = useLocalizedPush();
const [failedPings, setFailedPings] = useState(0);
useEffect(() => {
// guard check if the ID is valid and only ping when queued
// this prevent in confirmation participants to be updated as well
if (!participantId || participantActive !== true) {
return;
}
const pingInterval = setInterval(async () => {
const { data, error } = await supabaseClient.rpc('ping_participant', {
participant_id: participantId,
});
const affectedCount = data ? 1 : 0;
if (error || affectedCount <= 0) {
setFailedPings((currentFailedPings) => {
return currentFailedPings + 1;
});
} else {
setFailedPings(0);
}
}, PARTICIPANT_PING_INTERVAL_DELAY_MS);
return (() => {
clearInterval(pingInterval);
});
}, [participantId, participantStatus, participantActive, ping, push]);
// reload the page when the participant got deactivated somehow
useEffect(() => {
if (failedPings >= MAX_FAILED_PINGS) {
document.location.reload();
}
}, [failedPings]);
return { loading, error, data };
}