import { useEffect, useRef } from 'react'; /** How often an open list reads itself again while it is seen. */ export const REREAD_WHILE_SEEN_MS = 30_000; /** * Reads a list again by itself while the page showing it is seen, and once when it is seen again. * * FOR WHAT NOTHING ANNOUNCES. A patient ending a helper's access tells the helper's open page nothing, and the * page kept the person (and "Switch into their account") for as long as it stayed open - measured over five * minutes on staging. The server refused the switch, so this is about the list saying what is true, not the * boundary. * * One read at a time: a read still in the air when the next is due is not doubled (`reread` bounds its own * read). Nothing while hidden; a page seen again reads once, however many events say so. Its read is aborted * when the page goes. */ export const useRereadWhileSeen = (enabled: boolean, reread: (signal: AbortSignal) => Promise): void => { const rereadRef = useRef(reread); rereadRef.current = reread; useEffect(() => { if (!enabled) return undefined; let inFlight: AbortController | null = null; const run = () => { if (inFlight) return; const controller = new AbortController(); inFlight = controller; void rereadRef.current(controller.signal) .catch(() => undefined) .finally(() => { controller.abort(); if (inFlight === controller) inFlight = null; }); }; let wasHidden = document.visibilityState === 'hidden'; const onSeen = () => { const hidden = document.visibilityState === 'hidden'; if (!hidden && wasHidden) run(); wasHidden = hidden; }; // Hidden is noticed on the timer too: a page that went away without an event still reads once on return. const tick = () => { if (document.visibilityState === 'hidden') { wasHidden = true; return; } run(); }; const timer = window.setInterval(tick, REREAD_WHILE_SEEN_MS); document.addEventListener('visibilitychange', onSeen); window.addEventListener('focus', onSeen); return () => { window.clearInterval(timer); document.removeEventListener('visibilitychange', onSeen); window.removeEventListener('focus', onSeen); inFlight?.abort(); inFlight = null; }; }, [enabled]); };