feat(frontend): stop three editors losing unsaved work (#410) #463
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/410-unsaved-changes-guard"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Partial for #410 (MEDIUM) — three of four acceptance criteria. The in-app navigation half is deliberately excluded; reasoning below, agreed with the issue's author.
What ships
The Shelf's tonight-notes saved only on
onBlur.Ctrl+Wwith focus still in the field never firesonBlur, so everything typed since the last accidental blur was lost — during live play, on the app's primary at-the-table writing surface. Now debounced at 1.5s, and still committed on blur so leaving the field doesn't wait out the timer.Beat Planner's own session dropdown overwrote the draft unconditionally. Not an external navigation a GM might expect to cost them something — the tool's own control, silently discarding what they were mid-typing. It asks now.
useUnsavedChangesWarningcovers tab close and reload on the summary/transcript editors, the Beat Planner and the Shelf. It arms only while dirty and detaches on unmount: a leaked listener would nag on pages the user never typed into, which is exactly how a warning becomes noise people click through.Why in-app navigation blocking is not here
useBlockercallsuseDataRouterContext, whichinvariant-throws without a data router. This app mounts<BrowserRouter>, notcreateBrowserRouter/RouterProvider. Getting router-level blocking means migrating every route — a large, risky refactor that has nothing to do with unsaved-changes handling and shouldn't ride along inside it.The hook is therefore named for what it does rather than what one might wish it did, and says so in its own docstring. Two further limits documented there:
Acceptance criteria
#410 stays open for that last one.
Verification
Mutation-checked: reverting the debounce fails the two tests that type without ever blurring — the
Ctrl+W-during-play case that motivated the change. A blur-only implementation passes every other shelf test, so those two are the ones carrying the fix.The hook's own tests cover disarming when clean and on unmount, so it cannot pass by simply warning always.
465 frontend tests pass (was 457). Eslint clean on every touched file.
🤖 Generated with Claude Code