taler-typescript-core

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

commit 40d4492e1b52bc77b1d06e27cfe2083d03e4f743
parent f86b75617b8e41cd45d4a20976e19bceda09a3ed
Author: Florian Dold <dold@taler.net>
Date:   Sun,  9 Aug 2026 14:15:52 +0200

Fix button error notification dismissal

Diffstat:
Mpackages/web-util/src/components/Button.tsx | 2--
Mpackages/web-util/src/hooks/useNotifications.stories.tsx | 49+++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/packages/web-util/src/components/Button.tsx b/packages/web-util/src/components/Button.tsx @@ -62,14 +62,12 @@ export function Button({ const [running, setRunning] = useState(false); const [failed, setFailed] = useState(false); const { notification: ns } = useNotificationContext(); - const notification = ns.length > 0 ? ns[0] : undefined; // if the button is in failed state and the user // change the state of the form that affect this action handler // the remove the failed state for faster submit useEffect(() => { if (failed) { - notification?.acknowledge(); setFailed(false); } }, onClick?.args ?? []); diff --git a/packages/web-util/src/hooks/useNotifications.stories.tsx b/packages/web-util/src/hooks/useNotifications.stories.tsx @@ -30,6 +30,10 @@ import { Fragment, h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { Attention } from "../components/Attention.js"; import { Button } from "../components/Button.js"; +import { + NotificationProvider, + useNotificationContext, +} from "../context/notification.js"; import { delayMs } from "./useAsync.js"; import * as tests from "../tests/hook.js"; import { @@ -279,6 +283,51 @@ export const messages = tests.createExample(() => { ); }, {}); +export const recreatedArgumentsKeepErrorVisible = tests.createExample(() => { + return ( + <NotificationProvider> + <RecreatedArgumentsKeepErrorVisible /> + </NotificationProvider> + ); +}, {}); + +function RecreatedArgumentsKeepErrorVisible(): VNode { + const { actionHandler, notification, showError } = useNotificationContext(); + const action = actionHandler( + async function (_ct, _input: { value: string }) { + return opKnownFailure({} as any, "failure"); + }, + // Deliberately recreate the argument object on every render. This mirrors + // the password wrapper used by the AML session unlock form. + [{ value: "same value" }], + ); + action.onFail = showError( + "the operation failed" as TranslatedString, + () => "the error should remain visible" as TranslatedString, + ); + + return ( + <div> + <p> + Click the button. The error must remain visible after the failed action + rerenders the component. + </p> + <Button onClick={action}>fail</Button> + {notification.length ? ( + <Attention + type="danger" + title={notification[0].message.title} + onClose={notification[0].acknowledge} + > + {notification[0].message.type === "error" + ? notification[0].message.description + : undefined} + </Attention> + ) : undefined} + </div> + ); +} + export const confirm = tests.createExample(() => { const safe = newSafeHandlerBuilder({}); const [name, setName] = useState("");