Files
erika/components/realtime-refresh.tsx
T

73 lines
2.0 KiB
TypeScript

"use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { sse } from "@/lib/sse";
import {
startRealtimeRefresh,
type RealtimeRefreshHandlers,
} from "@/lib/realtime-refresh";
type FormRealtimeRefreshProps = {
topic: "forms" | "submissions";
formId?: string;
debounceMs?: number;
};
type LeaderboardRealtimeRefreshProps =
| {
topic: "leaderboards";
leaderboard: "xp";
channelId?: never;
debounceMs?: number;
}
| {
topic: "leaderboards";
leaderboard: "vc";
channelId?: string;
debounceMs?: number;
};
type RealtimeRefreshProps =
| FormRealtimeRefreshProps
| LeaderboardRealtimeRefreshProps;
export function RealtimeRefresh(props: RealtimeRefreshProps) {
const router = useRouter();
const topic = props.topic;
const formId = topic === "leaderboards" ? undefined : props.formId;
const leaderboard = topic === "leaderboards" ? props.leaderboard : undefined;
const channelId = topic === "leaderboards" ? props.channelId : undefined;
const debounceMs = props.debounceMs ?? (topic === "leaderboards" ? 500 : 150);
useEffect(() => {
const filter = topic === "leaderboards"
? leaderboard === "xp"
? { kind: "xp" as const }
: { kind: "vc" as const, channelId }
: { kind: "form" as const, formId };
return startRealtimeRefresh({
filter,
debounceMs,
refresh: () => router.refresh(),
subscribe(handlers: RealtimeRefreshHandlers) {
const options = { onopen: handlers.onOpen };
if (topic === "forms") {
return sse.forms.sub("update", handlers.onForm, options);
}
if (topic === "submissions") {
return sse.submissions.sub("update", handlers.onForm, options);
}
return sse.leaderboards.subMany({
xp: handlers.onXp,
vc: handlers.onVc,
}, options);
},
});
}, [channelId, debounceMs, formId, leaderboard, router, topic]);
return null;
}