import { useCallback, useRef } from 'react'; import type { ThreadClaimState } from '../utils/messaging/threadClaim'; /** The server's claim lasts 5 minutes; renewing once a minute keeps an active claim well inside it. */ const RENEW_EVERY_MS = 60_000; /** * Keeps MY claim on a pooled conversation alive while I work in it. * * The server expects this: its claim lapses after five minutes, on the understanding that "the client * refreshes by re-claiming while the receptionist is active". Call the returned function on activity * (typing, sending). It renews only a claim I already hold, so activity never takes a conversation, and * the server's answer, a lapse or a 409 naming a colleague included, is what the screen then shows. */ export const useClaimKeepAlive = ({ claim, viewerAccountId, renew, onChanged, }: { claim: ThreadClaimState | undefined; viewerAccountId: string | undefined; renew: (threadId: string) => Promise; onChanged: (claim: ThreadClaimState) => void; }): (() => void) => { const lastRenewedAt = useRef(0); const heldByMe = Boolean(claim?.claimed && viewerAccountId && claim.claimedByAccountId === viewerAccountId); const threadId = claim?.threadId; return useCallback(() => { if (!heldByMe || !threadId) return; const now = Date.now(); if (now - lastRenewedAt.current < RENEW_EVERY_MS) return; lastRenewedAt.current = now; renew(threadId) .then(onChanged) .catch(() => { // A failed renewal changes nothing on screen; the claim simply runs its course and the strip // shows it lapsing. The next activity after the throttle tries again. }); }, [heldByMe, threadId, renew, onChanged]); };