Files
F-r-ldraledigplannerare/frontend/src/components/common/InlineConfirm.tsx
T
jacobh2 d5596afe10 Share one modal shell and inline confirm across the app
Modal owns the overlay, header, close button and footer for the balance,
planned-day and QR modals, and closes on Escape (held off while the QR
fetch runs). InlineConfirm replaces the hand-built delete and
remove-member confirmations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-22 22:14:05 +02:00

98 lines
2.7 KiB
TypeScript

import { ReactNode } from 'react'
export interface InlineConfirmProps {
prompt: ReactNode
confirmLabel: ReactNode
cancelLabel: ReactNode
onConfirm: () => void
onCancel: () => void
isBusy?: boolean
confirmTestId?: string
cancelTestId?: string
/** Class for the outer wrapper — the two callers use different elements
* for this (`.modal__delete-confirm`, `.settings-panel__remove-confirm`),
* so the wrapper's look stays theirs rather than being unified here. */
className?: string
/** Class for the span wrapping `prompt` — only `PlannedDayModal` needs
* one (`.modal__delete-confirm-text`, which pushes the buttons right via
* `margin-right: auto`); `Settings`' row has no such class. */
promptClassName?: string
/** `Settings`' remove-member row shows the danger confirm before cancel;
* `PlannedDayModal`'s delete row shows cancel first. Defaults to cancel
* first. */
confirmFirst?: boolean
/** Appends `btn--sm` to both buttons — `Settings`' compact row uses it,
* `PlannedDayModal`'s footer-sized row doesn't. */
small?: boolean
/** `data-testid` on the outer wrapper — `PlannedDayModal`'s row has one
* (`delete-confirm`); `Settings`' row doesn't. */
testId?: string
}
/**
* The shared "are you sure" row — a prompt plus a danger confirm and a
* secondary cancel, both disabled while busy. Replaces the hand-copied
* versions in `PlannedDayModal` (delete confirm) and `Settings` (remove-
* member confirm), which differ only in wrapper class, prompt wrapping,
* button order and button size — all exposed as props here so neither
* caller's DOM has to change.
*/
export function InlineConfirm({
prompt,
confirmLabel,
cancelLabel,
onConfirm,
onCancel,
isBusy = false,
confirmTestId,
cancelTestId,
className,
promptClassName,
confirmFirst = false,
small = false,
testId,
}: InlineConfirmProps): ReactNode {
const sizeClass = small ? ' btn--sm' : ''
const confirmButton = (
<button
type="button"
className={`btn btn--danger${sizeClass}`}
onClick={onConfirm}
disabled={isBusy}
data-testid={confirmTestId}
>
{confirmLabel}
</button>
)
const cancelButton = (
<button
type="button"
className={`btn btn--secondary${sizeClass}`}
onClick={onCancel}
disabled={isBusy}
data-testid={cancelTestId}
>
{cancelLabel}
</button>
)
return (
<div className={className} data-testid={testId}>
<span className={promptClassName}>{prompt}</span>
{confirmFirst ? (
<>
{confirmButton}
{cancelButton}
</>
) : (
<>
{cancelButton}
{confirmButton}
</>
)}
</div>
)
}