fix(timeline): gate event delete behind the confirm dialog
The delete <form> combined onsubmit={confirmDelete} with use:enhance.
SvelteKit's enhance ignores event.defaultPrevented, so the DELETE fired on
the bare click — before the dialog was answered — and the post-DELETE
redirect ran regardless of the user's choice. Reading getConfirmService()
lazily inside the handler also threw (Svelte context is init-only), so the
dialog never appeared even with <ConfirmDialog> mounted.
Capture confirm at init and run the gate inside the enhance submit phase,
calling cancel() on "no". Clear dirty in the result callback so the
beforeNavigate guard no longer prompts "unsaved changes" on the post-delete
redirect.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -82,6 +82,10 @@ let selectedDocuments = $state<DocumentOption[]>(
|
||||
|
||||
const isEdit = $derived(event !== undefined);
|
||||
|
||||
// Captured at init — Svelte context is init-only, so reading it lazily inside an
|
||||
// event handler throws even when <ConfirmDialog> is mounted. Gates the delete.
|
||||
const { confirm } = getConfirmService();
|
||||
|
||||
let titleTouched = $state(false);
|
||||
let submitting = $state(false);
|
||||
let dirty = $state(false);
|
||||
@@ -109,18 +113,6 @@ beforeNavigate(({ cancel }) => {
|
||||
function markDirty() {
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
async function confirmDelete(e: SubmitEvent) {
|
||||
e.preventDefault();
|
||||
const { confirm } = getConfirmService();
|
||||
const ok = await confirm({
|
||||
title: m.event_editor_delete_confirm_title(),
|
||||
body: m.event_editor_delete_confirm_body(),
|
||||
destructive: true,
|
||||
confirmLabel: m.event_editor_delete()
|
||||
});
|
||||
if (ok) (e.target as HTMLFormElement).requestSubmit();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="mx-auto max-w-5xl px-4 py-8">
|
||||
@@ -309,9 +301,32 @@ async function confirmDelete(e: SubmitEvent) {
|
||||
|
||||
{#if isEdit}
|
||||
<!-- Delete lives in its own form so it posts to the dedicated ?/delete action.
|
||||
getConfirmService() is read lazily inside the handler so the component
|
||||
mounts cleanly outside a layout (tests) where no confirm context exists. -->
|
||||
<form method="POST" action="?/delete" onsubmit={confirmDelete} use:enhance class="mt-4">
|
||||
The confirm gate runs inside the enhance submit phase: enhance ignores an
|
||||
onsubmit preventDefault(), so awaiting confirm() and calling cancel() is the
|
||||
only thing that actually stops the destructive POST. -->
|
||||
<form
|
||||
method="POST"
|
||||
action="?/delete"
|
||||
use:enhance={async ({ cancel }) => {
|
||||
const ok = await confirm({
|
||||
title: m.event_editor_delete_confirm_title(),
|
||||
body: m.event_editor_delete_confirm_body(),
|
||||
destructive: true,
|
||||
confirmLabel: m.event_editor_delete()
|
||||
});
|
||||
if (!ok) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
return async ({ update }) => {
|
||||
// Clear dirtiness so beforeNavigate doesn't prompt "unsaved changes"
|
||||
// on the post-delete redirect.
|
||||
dirty = false;
|
||||
await update();
|
||||
};
|
||||
}}
|
||||
class="mt-4"
|
||||
>
|
||||
<input type="hidden" name="originPersonId" value={originPersonId} />
|
||||
<button
|
||||
type="submit"
|
||||
|
||||
Reference in New Issue
Block a user