taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 8194dbff4a8d6d0b4fe061ea3a9ff1033be7bb7f
parent 07c83c95c103e013db1c202fd193d4636ad2c5a4
Author: Sebastian <sebasjm@taler-systems.com>
Date:   Wed, 10 Jun 2026 13:42:40 -0300

fix #11508

Diffstat:
Mpackages/taler-merchant-webui/src/components/SolveMFA.tsx | 2++
Mpackages/taler-merchant-webui/src/components/modal/index.tsx | 4+++-
Mpackages/taler-merchant-webui/src/paths/instance/accounts/list/Table.tsx | 16++++++++++++++--
Mpackages/taler-util/src/http-client/merchant.ts | 17++++++++++++++++-
4 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/packages/taler-merchant-webui/src/components/SolveMFA.tsx b/packages/taler-merchant-webui/src/components/SolveMFA.tsx @@ -291,6 +291,7 @@ function SolveChallenge({ label: i18n.str`Verify`, } } // first try is going to be automatically + zIndex={50} // above any current dialog > <FormProvider<Form> name="settings" @@ -545,6 +546,7 @@ function SolveMFAChallenges({ <ConfirmModal title={i18n.str`Multi-factor authentication required.`} focus + zIndex={50} // above any current dialog preventBackgroundClose onCancel={onCancel} confirm={ diff --git a/packages/taler-merchant-webui/src/components/modal/index.tsx b/packages/taler-merchant-webui/src/components/modal/index.tsx @@ -53,6 +53,7 @@ interface ConfirmProps { children?: ComponentChildren; danger?: boolean; focus?: boolean; + zIndex?: number; preventBackgroundClose?: boolean; } interface BlockingProps { @@ -79,11 +80,12 @@ export function ConfirmModal({ children, danger, focus, + zIndex, preventBackgroundClose, }: ConfirmProps): VNode { const { i18n } = useTranslationContext(); return ( - <div class="modal is-active"> + <div class="modal is-active" style={zIndex ? {zIndex } : undefined}> <div class="modal-background " onClick={preventBackgroundClose ? undefined : onCancel} diff --git a/packages/taler-merchant-webui/src/paths/instance/accounts/list/Table.tsx b/packages/taler-merchant-webui/src/paths/instance/accounts/list/Table.tsx @@ -38,6 +38,7 @@ import { StateUpdater, useState } from "preact/hooks"; import { ConfirmModal } from "../../../../components/modal/index.js"; import { useSessionContext } from "../../../../context/session.js"; import { Tooltip } from "../../../../components/Tooltip.js"; +import { useMerchantChallengeHandlerContext } from "../../../../context/challenge.js"; const TALER_SCREEN_ID = 35; @@ -57,16 +58,27 @@ export function CardTable({ accounts, onCreate, onSelect }: Props): VNode { const { actionHandler, showError } = useNotificationContext(); const [deleting, setDeleting] = useState<TalerMerchantApi.BankAccountEntry | null>(null); + const mfa = useMerchantChallengeHandlerContext(); const remove = actionHandler( /*delete bank account*/ - (ct, t, w) => lib.instance.deleteBankAccount(t, w), + (ct, t, w, challengeIds: string[]) => + lib.instance.deleteBankAccount(t, w, { challengeIds }), !session.token || !deleting ? undefined - : ([session.token, deleting.h_wire] as const), + : ([session.token, deleting.h_wire, []] as const), ); remove.onFail = showError(i18n.str`Delete failed`, (fail) => { switch (fail.case) { + case HttpStatusCode.Accepted: + mfa.onNewChallenge( + i18n.str`New account`, + fail.body, + remove.lambda((prev, [ids]) => + !prev ? undefined : [prev[0], prev[1], ids], + ), + ); + return undefined; case HttpStatusCode.Unauthorized: return i18n.str`Unauthorized`; case HttpStatusCode.NotFound: diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts @@ -1119,10 +1119,19 @@ export class TalerMerchantInstanceHttpClient { /** * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-accounts-$H_WIRE */ - async deleteBankAccount(token: AccessToken, wireAccount: string) { + async deleteBankAccount( + token: AccessToken, + wireAccount: string, + params: { + challengeIds?: string[]; + } = {}, + ) { const url = new URL(`private/accounts/${wireAccount}`, this.baseUrl); const headers: Record<string, string> = {}; + if (params.challengeIds && params.challengeIds.length > 0) { + headers["Taler-Challenge-Ids"] = params.challengeIds.join(", "); + } if (token) { headers.Authorization = makeBearerTokenAuthHeader(token); } @@ -1138,6 +1147,12 @@ export class TalerMerchantInstanceHttpClient { ); return opEmptySuccess(resp); } + case HttpStatusCode.Accepted: + return opKnownAlternativeHttpFailure( + resp, + resp.status, + codecForChallengeResponse(), + ); case HttpStatusCode.Unauthorized: // FIXME: missing in docs return opKnownHttpFailure(resp.status, resp); case HttpStatusCode.NotFound: