Files
ui/_docs/02_document/modules/src__components__ConfirmDialog.md
T
Oleksandr Bezdieniezhnykh 510df68bcf [AZ-447] autodev Steps 1-4 baseline: docs, tests, refactor specs
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>
2026-05-11 00:38:49 +03:00

3.9 KiB

Module: src/components/ConfirmDialog.tsx

Source: src/components/ConfirmDialog.tsx (47 lines) Topo batch: B3 (uses react-i18next only; 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 open flips to true, the Cancel button is focused via cancelRef.current?.focus() (see useEffect keyed on open). This makes Cancel the default keyboard target — a common pattern for destructive confirmations.
  • Escape-to-cancel: a keydown handler is attached to window while open === true; pressing Escape calls onCancel(). The listener is removed on unmount or when open flips to false. This is the only dismiss path other than the explicit Cancel/Confirm buttons (no backdrop click handler).
  • Translation: button labels use t('common.cancel') and t('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 use ConfirmDialog for 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 width prop — the dialog is fixed at w-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 two ConfirmDialogs are mounted simultaneously (the SPA never does this today, but it's not enforced), both would call their onCancel() on a single Escape press. Acceptable under current usage.