feat: warn before leaving a form with unsaved changes

Drag-dropping page images then clicking a nav link silently discarded the
whole form. Add a reusable guardUnsavedChanges helper (SvelteKit beforeNavigate
confirm + native beforeunload) and wire it into the manga upload, manga edit,
and chapter upload forms. The dirty check returns false while submitting so the
post-save redirect isn't prompted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-11 15:16:40 +02:00
parent 3ca05dcb58
commit a47b6895c2
6 changed files with 145 additions and 1 deletions

View File

@@ -0,0 +1,36 @@
import { beforeNavigate } from '$app/navigation';
import { onMount } from 'svelte';
/**
* Warn before leaving a page with unsaved form state. Call once from a
* component's script (during init). `isDirty` is read live on each navigation,
* so pass a closure over the form's reactive state — and have it return `false`
* once a save has succeeded (or is in flight) so the post-save redirect doesn't
* prompt.
*
* Covers both in-app navigation (SvelteKit `beforeNavigate`, with a confirm) and
* full-page unload / tab close / reload (the native `beforeunload` prompt).
*/
export function guardUnsavedChanges(isDirty: () => boolean): void {
beforeNavigate((nav) => {
// `leave` (tab close / reload) can't show a custom confirm here — the
// beforeunload handler below covers it. Only guard in-app navigations.
if (nav.type === 'leave') return;
if (!isDirty()) return;
if (!confirm('You have unsaved changes. Leave this page and discard them?')) {
nav.cancel();
}
});
onMount(() => {
const handler = (e: BeforeUnloadEvent) => {
if (isDirty()) {
e.preventDefault();
// Legacy browsers require returnValue to be set.
e.returnValue = '';
}
};
window.addEventListener('beforeunload', handler);
return () => window.removeEventListener('beforeunload', handler);
});
}