64 lines
1.8 KiB
TypeScript
64 lines
1.8 KiB
TypeScript
export type RealtimeRefreshFilter =
|
|
| { kind: "form"; formId?: string }
|
|
| { kind: "uploads" }
|
|
| { kind: "profile" }
|
|
| { kind: "xp" }
|
|
| { kind: "vc"; channelId?: string };
|
|
|
|
export type RealtimeRefreshEvent =
|
|
| { kind: "open" }
|
|
| { kind: "form"; formId: string }
|
|
| { kind: "upload" }
|
|
| { kind: "xp" }
|
|
| { kind: "vc"; channelId: string };
|
|
|
|
export type RealtimeRefreshSubscription = { clean: () => void };
|
|
|
|
export function matchesRealtimeRefresh(
|
|
filter: RealtimeRefreshFilter,
|
|
event: Exclude<RealtimeRefreshEvent, { kind: "open" }>,
|
|
) {
|
|
if (filter.kind === "form") {
|
|
return event.kind === "form" && (!filter.formId || event.formId === filter.formId);
|
|
}
|
|
if (filter.kind === "uploads") return event.kind === "upload";
|
|
if (filter.kind === "xp") return event.kind === "xp";
|
|
if (filter.kind === "profile") return event.kind === "xp" || event.kind === "vc";
|
|
return event.kind === "vc" && (!filter.channelId || event.channelId === filter.channelId);
|
|
}
|
|
|
|
export function startRealtimeRefresh({
|
|
filter,
|
|
debounceMs,
|
|
refresh,
|
|
subscribe,
|
|
}: {
|
|
filter: RealtimeRefreshFilter;
|
|
debounceMs: number;
|
|
refresh: () => void;
|
|
subscribe: (emit: (event: RealtimeRefreshEvent) => void) => RealtimeRefreshSubscription;
|
|
}) {
|
|
let connectedOnce = false;
|
|
let refreshTimer: ReturnType<typeof setTimeout> | undefined;
|
|
|
|
const scheduleRefresh = () => {
|
|
if (refreshTimer) clearTimeout(refreshTimer);
|
|
refreshTimer = setTimeout(refresh, debounceMs);
|
|
};
|
|
|
|
const subscription = subscribe((event) => {
|
|
if (event.kind === "open") {
|
|
if (connectedOnce) scheduleRefresh();
|
|
connectedOnce = true;
|
|
return;
|
|
}
|
|
|
|
if (matchesRealtimeRefresh(filter, event)) scheduleRefresh();
|
|
});
|
|
|
|
return () => {
|
|
if (refreshTimer) clearTimeout(refreshTimer);
|
|
subscription.clean();
|
|
};
|
|
}
|