Captures the full output of autodev existing-code Phase A through Step 4 (Code Testability Revision) for the Azaion UI workspace: - Step 1 Document: _docs/02_document/ (FINAL_report, architecture, glossary, components/, modules/, diagrams/, system-flows, module-layout) plus _docs/00_problem/ + _docs/01_solution/ + _docs/legacy/ + _docs/how_to_test + README. - Step 2 Architecture Baseline: architecture_compliance_baseline.md. - Step 3 Test Spec: _docs/02_document/tests/ (environment, test-data, blackbox/performance/resilience/security/ resource-limit tests, traceability-matrix), enum_spec_snapshot, expected_results/results_report.md (98 rows), plus the run-tests.sh + run-performance-tests.sh runners. - Step 4 Code Testability Revision: 01-testability-refactoring/ run dir (list-of-changes C01-C07, deferred_to_refactor, analysis/research_findings + refactoring_roadmap) and the 7 child task specs AZ-448..AZ-454 under _docs/02_tasks/todo/ plus _dependencies_table.md. - _docs/_autodev_state.md pins the cursor at Step 4 / refactor Phase 4 entry so /autodev resumes cleanly. Epic AZ-447 (UI testability gates) tracks the 7 child tasks that will land in subsequent commits. Co-authored-by: Cursor <cursoragent@cursor.com>
3.9 KiB
Module: src/components/ConfirmDialog.tsx
Source:
src/components/ConfirmDialog.tsx(47 lines) Topo batch: B3 (usesreact-i18nextonly; no intra-repo deps)
Purpose
A controlled, single-message confirm dialog used wherever the SPA needs an "Are you sure?" gate. Replaces the legacy WPF MessageBox.Show(..., MessageBoxButton.YesNo, ...) pattern (_docs/legacy/wpf-era.md §4 / §"What survived").
Public interface
interface Props {
open: boolean
title: string
message?: string
onConfirm: () => void
onCancel: () => void
}
export default function ConfirmDialog(props: Props): JSX.Element | null
When open === false, returns null. When open === true, renders a centered modal over a dimmed backdrop. The component is fully controlled — it owns no open state itself.
Internal logic
- Auto-focus: when
openflips totrue, the Cancel button is focused viacancelRef.current?.focus()(seeuseEffectkeyed onopen). This makes Cancel the default keyboard target — a common pattern for destructive confirmations. - Escape-to-cancel: a
keydownhandler is attached towindowwhileopen === true; pressingEscapecallsonCancel(). The listener is removed on unmount or whenopenflips tofalse. This is the only dismiss path other than the explicit Cancel/Confirm buttons (no backdrop click handler). - Translation: button labels use
t('common.cancel')andt('common.confirm'). Title and message are passed in by the caller — the caller is responsible for translation.
Dependencies
- Internal: none.
- External:
react(useEffect,useRef),react-i18next(useTranslation).
Consumers (intra-repo)
From the §7a dependency graph in _docs/02_document/00_discovery.md:
src/features/admin/AdminPage.tsx— confirm before deleting users.src/features/annotations/MediaList.tsx— confirm before deleting media.src/features/flights/FlightsPage.tsx— confirm before deleting a flight.src/features/dataset/DatasetPage.tsx— confirm before deleting dataset items.
(HelpModal.tsx is the non-confirm sibling; it does NOT use ConfirmDialog and notably does not have Escape-to-close — see src__components__HelpModal.md §Notes.)
Data models
None.
Configuration
Tailwind tokens used: bg-az-panel, border-az-border, text-az-text, bg-az-red, bg-az-bg, text-white. All defined in src/index.css (per _docs/02_document/00_discovery.md §2a).
z-[100] is the chosen stacking layer. No other modal currently competes with it; if a third-party library introduces a portal at z-[200]+, layering will need a docs entry.
External integrations
None.
Security
- No backdrop dismissal: clicking outside the dialog does NOT cancel. Combined with Escape-to-cancel and a default-focused Cancel button, this gives a deliberate, keyboard-safe destructive-action flow.
- No
aria-modal/ role="dialog": not annotated for screen readers; flag for Step 4 verification against the_docs/ui_design/README.md§"Confirmation dialogs" spec (which specifies modal semantics).
Tests
None.
Notes / open questions
- The "destructive" colour (
bg-az-red) is hardcoded into the Confirm button. Some callers useConfirmDialogfor non-destructive confirms (e.g. flight selection in some flows — verify in B7); a future variant prop (destructive: boolean) would be cleaner. Defer to Step 8. - No
widthprop — the dialog is fixed atw-80(320px). On the mobile breakpoint defined in_docs/ui_design/README.md§"Responsive Breakpoints" (640px), this fits, but very long titles or multi-line messages will overflow. Flag for Step 4 cosmetic verification. - Escape handler attaches to
window, not the dialog DOM. If twoConfirmDialogs are mounted simultaneously (the SPA never does this today, but it's not enforced), both would call theironCancel()on a single Escape press. Acceptable under current usage.