View Issue Details

IDProjectCategoryView StatusLast Update
0012020Talermerchant portal webuipublic2026-11-10 23:43
Reporterbot-cg [agent] Assigned ToResolution deadline
ImplementerReviewer 
Release signed byDeployed by 
VerifierCommunicatorCM_7  
Data protection authority notification requiredNo  
CSIRT notification requiredNo  
Estimated effort (hours)Actual effort (hours)0 
Fast-trackNo
Work packagenone
PrioritynormalSeverityminorReproducibilityhave not tried
Status newResolutionopen 
Summary0012020: Merchant: Remove bank account confirmation does not take focus (and Escape does nothing)
DescriptionWhat happens:
Bank accounts & payouts -> account '⋯' menu -> 'Delete' shows a hand-made role=dialog overlay. The menu (and the item that had focus) unmounts, so focus falls to BODY; the dialog's onKeyDown Escape handler therefore never fires (measured: still open after Escape).

Expected:
Focus starts inside the confirmation on Cancel, not on 'Yes, remove it'.

Where:
  - packages/taler-merchant-webui/src/screens/MoneyInScreen.tsx:197
  - packages/taler-merchant-webui/src/screens/MoneyInScreen.tsx:1339

Measured in headless Chromium (document.activeElement):
  before: BODY; Escape: dialog stays open
  after: BUTTON 'Cancel' inside the dialog; Escape closes it

Proposed fix:
Ref on the Cancel button and an effect on deletingAccount that focuses it when the dialog opens; Escape now works through the existing handler.

Patch against taler-typescript-core master attached; the same change is committed on branch dev/bots/autofocus (durian). Screenshots attached (focused element outlined in red): 'before' is master, 'after' is with the patch.

Verified: tsc ok for file; screens.test.js passes; screenshot confirms
TagsNo tags attached.
Attached Files
merchant-b--money-in-remove-account-dialog.diff (1,637 bytes)   
diff --git a/packages/taler-merchant-webui/src/screens/MoneyInScreen.tsx b/packages/taler-merchant-webui/src/screens/MoneyInScreen.tsx
index 727eb01a9..7bc2439a9 100644
--- a/packages/taler-merchant-webui/src/screens/MoneyInScreen.tsx
+++ b/packages/taler-merchant-webui/src/screens/MoneyInScreen.tsx
@@ -15,7 +15,7 @@
  */
 
 import type { VNode } from "preact";
-import { useState } from "preact/hooks";
+import { useEffect, useRef, useState } from "preact/hooks";
 import { TalerMerchantApi } from "@gnu-taler/taler-util";
 import { BankMonitoringDialog } from "./BankMonitoringDialog.js";
 import { Header } from "../ui/Header.js";
@@ -191,6 +191,13 @@ export function MoneyInScreen({
   >(undefined);
   const [isDeletingAccount, setIsDeletingAccount] = useState<boolean>(false);
   const [deleteAccountError, setDeleteAccountError] = useState<unknown>();
+  // Open the confirmation on its safe choice. The dialog only hears Escape
+  // while focus is inside it, and the account menu that opens it unmounts the
+  // control that had focus.
+  const deleteAccountCancel = useRef<HTMLButtonElement>(null);
+  useEffect(() => {
+    if (deletingAccount) deleteAccountCancel.current?.focus();
+  }, [deletingAccount]);
   const [openAccountMenuId, setOpenAccountMenuId] = useState<
     string | undefined
   >(undefined);
@@ -1329,6 +1336,7 @@ export function MoneyInScreen({
             />
             <div class="flex justify-end space-x-2 pt-2">
               <button
+                ref={deleteAccountCancel}
                 type="button"
                 onClick={() => {
                   setDeletingAccount(undefined);

Required notifications

Address or linkRemarkAdded byNotifiedActions

Relationships

child of 0012002 new Merchant portal: dialogs, PIN/code prompts and single-purpose forms open without keyboard focus on the obvious field 

Activities

Issue History

Date ModifiedUsernameFieldChange
2026-11-10 23:41bot-cgNew Issue
2026-11-10 23:41bot-cgRelationship addedchild of 0012002
2026-11-10 23:43bot-cgFile Added: merchant-b--money-in-remove-account-dialog.diff
2026-11-10 23:43bot-cgFile Added: merchant-b--money-in-remove-account-dialog--before.png
2026-11-10 23:43bot-cgFile Added: merchant-b--money-in-remove-account-dialog--after.png