diff --git a/frontend/src/lib/components/TranscriptionEditView.svelte.spec.ts b/frontend/src/lib/components/TranscriptionEditView.svelte.spec.ts index 11a4d29b..d537de83 100644 --- a/frontend/src/lib/components/TranscriptionEditView.svelte.spec.ts +++ b/frontend/src/lib/components/TranscriptionEditView.svelte.spec.ts @@ -2,6 +2,7 @@ import { describe, it, expect, vi, afterEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page } from 'vitest/browser'; import TranscriptionEditView from './TranscriptionEditView.svelte'; +import { createConfirmService, CONFIRM_KEY } from '$lib/services/confirm.svelte.js'; afterEach(cleanup); @@ -24,17 +25,23 @@ const block2 = { version: 0 }; -function renderView(overrides: Record = {}) { - return render(TranscriptionEditView, { - documentId: 'doc-1', - blocks: [block1, block2], - canComment: true, - currentUserId: 'user-1', - onBlockFocus: vi.fn(), - onSaveBlock: vi.fn(), - onDeleteBlock: vi.fn(), - ...overrides - }); +function renderView(overrides: Record = {}, service = createConfirmService()) { + return { + ...render(TranscriptionEditView, { + props: { + documentId: 'doc-1', + blocks: [block1, block2], + canComment: true, + currentUserId: 'user-1', + onBlockFocus: vi.fn(), + onSaveBlock: vi.fn(), + onDeleteBlock: vi.fn(), + ...overrides + }, + context: new Map([[CONFIRM_KEY, service]]) + }), + service + }; } describe('TranscriptionEditView — rendering', () => { @@ -200,25 +207,27 @@ describe('TranscriptionEditView — flush on blur', () => { describe('TranscriptionEditView — delete block', () => { it('calls onDeleteBlock with correct blockId when delete is confirmed', async () => { const onDeleteBlock = vi.fn().mockResolvedValue(undefined); - vi.spyOn(window, 'confirm').mockReturnValue(true); - renderView({ onDeleteBlock }); + const { service } = renderView({ onDeleteBlock }); - const deleteBtn = page.getByRole('button', { name: 'Löschen' }).first(); - await deleteBtn.click(); + const deleteBtn = document.querySelector('button[aria-label="Löschen"]') as HTMLButtonElement; + deleteBtn.click(); + await vi.waitFor(() => expect(service.options).not.toBeNull()); + service.settle(true); + await vi.waitFor(() => expect(service.options).toBeNull()); expect(onDeleteBlock).toHaveBeenCalledWith('b1'); - vi.restoreAllMocks(); }); it('does not call onDeleteBlock when deletion is cancelled', async () => { const onDeleteBlock = vi.fn(); - vi.spyOn(window, 'confirm').mockReturnValue(false); - renderView({ onDeleteBlock }); + const { service } = renderView({ onDeleteBlock }); - const deleteBtn = page.getByRole('button', { name: 'Löschen' }).first(); - await deleteBtn.click(); + const deleteBtn = document.querySelector('button[aria-label="Löschen"]') as HTMLButtonElement; + deleteBtn.click(); + await vi.waitFor(() => expect(service.options).not.toBeNull()); + service.settle(false); + await vi.waitFor(() => expect(service.options).toBeNull()); expect(onDeleteBlock).not.toHaveBeenCalled(); - vi.restoreAllMocks(); }); }); diff --git a/frontend/src/routes/admin/users/[id]/+page.svelte b/frontend/src/routes/admin/users/[id]/+page.svelte index 377a9864..c0e8f8db 100644 --- a/frontend/src/routes/admin/users/[id]/+page.svelte +++ b/frontend/src/routes/admin/users/[id]/+page.svelte @@ -2,17 +2,29 @@ import { enhance } from '$app/forms'; import { beforeNavigate, goto } from '$app/navigation'; import { m } from '$lib/paraglide/messages.js'; +import { getConfirmService } from '$lib/services/confirm.svelte.js'; import UserProfileSection from '$lib/components/user/UserProfileSection.svelte'; import UserGroupsSection from '$lib/components/user/UserGroupsSection.svelte'; import UserPasswordSection from '$lib/components/user/UserPasswordSection.svelte'; let { data, form } = $props(); +const { confirm } = getConfirmService(); + const selectedGroupIds = $derived(data.editUser.groups?.map((g: { id: string }) => g.id) ?? []); let isDirty = $state(false); let showUnsavedWarning = $state(false); let discardTarget: string | null = $state(null); +let deleteFormEl = $state(null); + +async function handleDelete() { + const confirmed = await confirm({ + title: m.admin_user_delete_confirm({ username: data.editUser.username }), + destructive: true + }); + if (confirmed) deleteFormEl!.requestSubmit(); +} beforeNavigate(({ cancel, to }) => { if (isDirty) { @@ -51,20 +63,10 @@ $effect(() => {

{m.admin_user_edit_heading({ username: data.editUser.username })}

-
{ - if (!confirm(m.admin_user_delete_confirm({ username: data.editUser.username }))) { - cancel(); - } - return async ({ update }) => { - await update(); - }; - }} - > +