taler-typescript-core

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

commit f856b4e78eb1a1c20f5e0869c2e9ddcedb15ad82
parent 2d2873b38ec9ce8e6535f0c8630ac00610013fef
Author: Sebastian <sebasjm@gmail.com>
Date:   Sun,  5 Jan 2025 18:09:21 -0300

onclick logic should be in the notification handler

Diffstat:
Mpackages/web-util/src/components/Button.tsx | 67+++++++------------------------------------------------------------
Mpackages/web-util/src/hooks/useNotifications.ts | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
2 files changed, 83 insertions(+), 79 deletions(-)

diff --git a/packages/web-util/src/components/Button.tsx b/packages/web-util/src/components/Button.tsx @@ -40,14 +40,13 @@ export type OnOperationSuccesReturnType<T> = ( result: T extends OperationOk<any> ? T : never, ) => TranslatedString | void; export type OnOperationFailReturnType<T> = ( - (d: (T extends OperationFail<any> ? T : never) | (T extends OperationAlternative<any,any> ? T : never)) => TranslatedString) + d: + | (T extends OperationFail<any> ? T : never) + | (T extends OperationAlternative<any, any> ? T : never), +) => TranslatedString; export interface ButtonHandler<T extends OperationResult<A, B>, A, B> { onClick: () => Promise<T | undefined>; - onNotification: (n: NotificationMessage) => void; - onOperationSuccess: OnOperationSuccesReturnType<T>; - onOperationFail?: OnOperationFailReturnType<T>; - onOperationComplete?: () => void; } interface Props<T extends OperationResult<A, B>, A, B> @@ -84,61 +83,9 @@ export function Button<T extends OperationResult<A, B>, A, B>({ return; } setRunning(true); - handler - .onClick() - .then((resp) => { - if (resp) { - if (resp.type === "ok") { - const result: OperationOk<any> = resp; - // @ts-expect-error this is an operationOk - const msg = handler.onOperationSuccess(result); - if (msg) { - notifyInfo(msg); - } - } - if (resp.type === "fail") { - const d = 'detail' in resp ? resp.detail : undefined - - const title = !handler.onOperationFail ? "Unexpected error." as TranslatedString : handler.onOperationFail(resp as any); - handler.onNotification({ - title, - type: "error", - description: d && d.hint ? d.hint as TranslatedString : undefined, - debug: d, - when: AbsoluteTime.now(), - }); - } - } - if (handler.onOperationComplete) { - handler.onOperationComplete(); - } - setRunning(false); - }) - .catch((error) => { - console.error(error); - - if (error instanceof TalerError) { - handler.onNotification( - buildUnifiedRequestErrorMessage(i18n, error), - ); - } else { - const description = ( - error instanceof Error ? error.message : String(error) - ) as TranslatedString; - - handler.onNotification({ - title: i18n.str`Operation failed`, - type: "error", - description, - when: AbsoluteTime.now(), - }); - } - - if (handler.onOperationComplete) { - handler.onOperationComplete(); - } - setRunning(false); - }); + handler.onClick().finally(() => { + setRunning(false); + }); }} > {running ? <Wait /> : children} diff --git a/packages/web-util/src/hooks/useNotifications.ts b/packages/web-util/src/hooks/useNotifications.ts @@ -10,7 +10,11 @@ import { TranslatedString, } from "@gnu-taler/taler-util"; import { useEffect, useState } from "preact/hooks"; -import { ButtonHandler, OnOperationFailReturnType, OnOperationSuccesReturnType } from "../components/Button.js"; +import { + ButtonHandler, + OnOperationFailReturnType, + OnOperationSuccesReturnType, +} from "../components/Button.js"; import { InternationalizationAPI, memoryMap, @@ -106,7 +110,7 @@ export function useNotifications(): Notification[] { useEffect(() => { return storage.onUpdate(NOTIFICATION_KEY, () => { - setLastUpdate(Date.now()) + setLastUpdate(Date.now()); // const mem = storage.get(NOTIFICATION_KEY) ?? new Map(); // setter(structuredClone(mem)); }); @@ -181,11 +185,11 @@ export function useLocalNotification(): [ const notif = !value ? undefined : { - message: value, - acknowledge: () => { - setter(undefined); - }, - }; + message: value, + acknowledge: () => { + setter(undefined); + }, + }; async function errorHandling(cb: (notify: typeof errorMap) => Promise<void>) { try { @@ -218,28 +222,81 @@ export function useLocalNotificationHandler(): [ HandlerMaker, (n: NotificationMessage) => void, ] { + const { i18n } = useTranslationContext(); const [value, setter] = useState<NotificationMessage>(); const notif = !value ? undefined : { - message: value, - acknowledge: () => { - setter(undefined); - }, - }; + message: value, + acknowledge: () => { + setter(undefined); + }, + }; function makeHandler<T extends OperationResult<A, B>, A, B>( - onClick: () => Promise<T | undefined>, - onOperationSuccess:OnOperationSuccesReturnType<T>, + doAction: () => Promise<T | undefined>, + onOperationSuccess: OnOperationSuccesReturnType<T>, onOperationFail?: OnOperationFailReturnType<T>, onOperationComplete?: () => void, ): ButtonHandler<T, A, B> { + const onNotification = setter; return { - onClick, - onNotification: setter, - onOperationFail, - onOperationSuccess, - onOperationComplete, + onClick: async (): Promise<T | undefined> => { + try { + const resp = await doAction(); + if (resp) { + if (resp.type === "ok") { + const result: OperationOk<any> = resp; + // @ts-expect-error this is an operationOk + const msg = onOperationSuccess(result); + if (msg) { + notifyInfo(msg); + } + } + if (resp.type === "fail") { + const d = "detail" in resp ? resp.detail : undefined; + + const title = !onOperationFail + ? i18n.str`Unexpected error` + : onOperationFail(resp as any); + onNotification({ + title, + type: "error", + description: + d && d.hint ? (d.hint as TranslatedString) : undefined, + debug: d, + when: AbsoluteTime.now(), + }); + } + } + if (onOperationComplete) { + onOperationComplete(); + } + return resp; + } catch (error: unknown) { + console.error(error); + + if (error instanceof TalerError) { + onNotification(buildUnifiedRequestErrorMessage(i18n, error)); + } else { + const description = ( + error instanceof Error ? error.message : String(error) + ) as TranslatedString; + + onNotification({ + title: i18n.str`Operation failed`, + type: "error", + description, + when: AbsoluteTime.now(), + }); + } + if (onOperationComplete) { + onOperationComplete(); + } + return undefined; + } + // setRunning(false); + }, }; }