Skip to content

Extract the beforeunload guard out of useActivityTimer #572

Description

@gaidheal1

Summary

useActivityTimer is otherwise a clean, portable timer hook — local tick loop, optimistic state, server sync, auto-stop-at-limit logic. Its one browser dependency is a beforeunload listener that warns the user before closing the tab mid-activity. Extract that into a separate web-only hook so the timer logic itself is platform-neutral.

Part of #569.

Relevant code

frontend/src/hooks/useActivityTimer.ts:336-342:

// Block tab close / refresh / external navigation while timer is active
useEffect(() => {
  if (status !== 'active') return;
  const handler = (e: BeforeUnloadEvent): void => { e.preventDefault(); e.returnValue = ''; };
  window.addEventListener('beforeunload', handler);
  return () => window.removeEventListener('beforeunload', handler);
}, [status]);

Proposed fix

Move this into its own hook (e.g. hooks/useUnloadWarning.ts) taking an active: boolean, and call it from the component that owns the timer UI rather than from inside useActivityTimer. This leaves useActivityTimer with zero window references.

Acceptance criteria

  • No window reference remains in useActivityTimer.ts
  • The browser still warns on tab close / refresh while an activity timer is active, and does not warn when it isn't
  • The extracted hook is a no-op (not a crash) in an environment without window
  • useActivityTimer.test.tsx still passes

Notes

There's no native equivalent of beforeunload — protecting an in-progress timer on Android is an AppState / background-task concern and will need designing separately. Extracting the web behaviour now keeps the two concerns from being conflated later.

⚠️ Touches the timer hook, so coordinate with the in-progress timer redesign to avoid conflicting edits. The change is small and additive, but it's in a file that redesign work is likely to be moving around.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions