fix(ui): use styled confirm dialog for salary and recurring-invoice destructive actions (#1036)

* fix(ui): use styled confirm dialog for salary and recurring-invoice destructive actions

Replace native window.confirm() with the existing DestructiveConfirmDialog
/ useDestructiveConfirm() primitive at the six sites from #839: recurring
invoice schedule delete, employee deactivation, salary run draft delete,
remove employee from run, salary calendar bulk delete (all variant
'destructive'), and the nollkorning-to-review guard (variant 'warning').
Confirmation copy is preserved as the dialog description; new title keys
added to both messages/sv.json and messages/en.json.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ui): lock delete and deactivate actions while the request is in flight

The styled confirm dialog resolves before the DELETE settles, so the
trigger button could be clicked again and fire a duplicate request.
Add an in-flight guard (deletingId / deactivating) and disable the
button until the request completes, mirroring the runNow pattern.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-07-16 18:14:34 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent a95872928e
commit f8611f2e89
6 changed files with 112 additions and 21 deletions
+14 -1
View File
@@ -29,6 +29,10 @@ import {
} from 'lucide-react'
import { useLocale, useTranslations } from 'next-intl'
import { Button } from '@/components/ui/button'
import {
DestructiveConfirmDialog,
useDestructiveConfirm,
} from '@/components/ui/destructive-confirm-dialog'
import {
Dialog,
DialogContent,
@@ -123,6 +127,7 @@ export function SalaryCalendar({
}: SalaryCalendarProps) {
const t = useTranslations('salary_calendar')
const locale = useLocale()
const { dialogProps, confirm: confirmAction } = useDestructiveConfirm()
const dateLocale = locale === 'en' ? enUS : sv
const isHourly = salaryType === 'hourly'
const periodStartDate = useMemo(() => parseISO(periodStart), [periodStart])
@@ -277,7 +282,13 @@ export function SalaryCalendar({
const handleBulkDelete = async () => {
if (selected.size === 0 || readOnly) return
if (!confirm(t('confirm_bulk_delete', { count: selected.size }))) return
const ok = await confirmAction({
title: t('confirm_bulk_delete_title'),
description: t('confirm_bulk_delete', { count: selected.size }),
confirmLabel: t('delete'),
variant: 'destructive',
})
if (!ok) return
setDeleting(true)
setError(null)
try {
@@ -557,6 +568,8 @@ export function SalaryCalendar({
}}
/>
)}
<DestructiveConfirmDialog {...dialogProps} />
</div>
)
}