taler-typescript-core

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

commit 063ee8244e4304de4f14697008848dea934c98dc
parent c8f3e929d2f5551460122c9288ea77e05f42c37f
Author: Sebastian <sebasjm@gmail.com>
Date:   Tue,  4 Nov 2025 14:52:55 -0300

error reporting fix in merchant backoffice

Diffstat:
Mpackages/merchant-backoffice-ui/src/Routing.tsx | 4++--
Mpackages/merchant-backoffice-ui/src/hooks/preference.ts | 3---
Mpackages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx | 8++++----
Mpackages/merchant-backoffice-ui/src/paths/admin/create/index.tsx | 15+--------------
Mpackages/merchant-backoffice-ui/src/paths/login/index.tsx | 79++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mpackages/merchant-backoffice-ui/src/paths/settings/index.tsx | 22+++++++++++++++-------
Mpackages/web-util/src/hooks/useNotifications.ts | 1-
7 files changed, 98 insertions(+), 34 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/Routing.tsx b/packages/merchant-backoffice-ui/src/Routing.tsx @@ -25,7 +25,7 @@ import { TalerError, TranslatedString, } from "@gnu-taler/taler-util"; -import { LocalNotificationBannerBulma, urlPattern, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { urlPattern, useTranslationContext } from "@gnu-taler/web-util/browser"; import { createHashHistory } from "history"; import { Fragment, VNode, h } from "preact"; import { Route, Router, route } from "preact-router"; @@ -83,9 +83,9 @@ import WebhookListPage from "./paths/instance/webhooks/list/index.js"; import WebhookUpdatePage from "./paths/instance/webhooks/update/index.js"; import { LoginPage } from "./paths/login/index.js"; import { NewAccount } from "./paths/newAccount/index.js"; +import { ResetAccount } from "./paths/resetAccount/index.js"; import { Settings } from "./paths/settings/index.js"; import { Notification } from "./utils/types.js"; -import { ResetAccount } from "./paths/resetAccount/index.js"; export enum InstancePaths { error = "/error", diff --git a/packages/merchant-backoffice-ui/src/hooks/preference.ts b/packages/merchant-backoffice-ui/src/hooks/preference.ts @@ -28,7 +28,6 @@ import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser"; export interface Preferences { advanceOrderMode: boolean; advanceInstanceMode: boolean; - developerMode: boolean; hideKycUntil: AbsoluteTime; hideMissingAccountUntil: AbsoluteTime; dateFormat: "ymd" | "dmy" | "mdy"; @@ -37,7 +36,6 @@ export interface Preferences { const defaultSettings: Preferences = { advanceOrderMode: false, advanceInstanceMode: false, - developerMode: false, hideKycUntil: AbsoluteTime.never(), hideMissingAccountUntil: AbsoluteTime.never(), dateFormat: "ymd", @@ -47,7 +45,6 @@ export const codecForPreferences = (): Codec<Preferences> => buildCodecForObject<Preferences>() .property("advanceOrderMode", codecForBoolean()) .property("advanceInstanceMode", codecForBoolean()) - .property("developerMode", codecForBoolean()) .property("hideKycUntil", codecForAbsoluteTime) .property("hideMissingAccountUntil", codecForAbsoluteTime) .property( diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx @@ -141,7 +141,7 @@ export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { : undefined, }); - const hasTokenErrors = tokenFormErrors === undefined; + const hasTokenErrors = tokenFormErrors !== undefined; const [notification, safeFunctionHandler] = useLocalNotificationBetter(); const { state: session, lib, logIn } = useSessionContext(); const mfa = useChallengeHandler(); @@ -153,20 +153,20 @@ export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { password: tokenForm.password!, }, }; - // if (!newValue.address) newValue.address = {}; - // if (!newValue.jurisdiction) newValue.jurisdiction = {}; const create = safeFunctionHandler( async ( token: AccessToken, data: TalerMerchantApi.InstanceConfigurationMessage, challengeIds: string[], ) => { + if (!data.address) data.address = {}; + if (!data.jurisdiction) data.jurisdiction = {}; const instanceResp = await lib.instance.createInstance(token, data, { challengeIds, }); if (instanceResp.type === "fail") return instanceResp; if (data.auth.password) { - const tokenResp = await lib.instance.createAccessToken( + const tokenResp = await lib.subInstanceApi(data.id).instance.createAccessToken( data.id, data.auth.password, FOREVER_REFRESHABLE_TOKEN(i18n.str`Instance created`), diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx @@ -18,22 +18,9 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { - HttpStatusCode, - InstanceConfigurationMessage, - TalerMerchantApi, + TalerMerchantApi } from "@gnu-taler/taler-util"; -import { - LocalNotificationBannerBulma, - useChallengeHandler, - useTranslationContext, -} from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; -import { useState } from "preact/hooks"; -import { NotificationCard } from "../../../components/menu/index.js"; -import { SolveMFAChallenges } from "../../../components/SolveMFA.js"; -import { useSessionContext } from "../../../context/session.js"; -import { Notification } from "../../../utils/types.js"; -import { FOREVER_REFRESHABLE_TOKEN } from "../../login/index.js"; import { CreatePage } from "./CreatePage.js"; interface Props { diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx b/packages/merchant-backoffice-ui/src/paths/login/index.tsx @@ -24,12 +24,13 @@ import { HttpStatusCode, LoginTokenRequest, LoginTokenScope, - TranslatedString + TranslatedString, } from "@gnu-taler/taler-util"; import { ButtonBetterBulma, - LocalNotificationBannerBulma, + Notification, useChallengeHandler, + useCommonPreference, useLocalNotificationBetter, useTranslationContext, } from "@gnu-taler/web-util/browser"; @@ -114,7 +115,31 @@ export function LoginPage({ showCreateAccount }: Props): VNode { return ( <Fragment> - <LocalNotificationBannerBulma notification={notification} /> + <LocalNotificationBannerBulma + notification={{ + acknowledge() {}, + message: { + title: "The operation failed." as TranslatedString, + type: "error", + description: "Unauthorized" as TranslatedString, + debug: { + detail: { + code: 2015, + hint: "The merchant refused the request due to lack of authorization.", + detail: "Check 'Authorization' header", + }, + case: 401, + when: { + t_ms: 1762199783634, + }, + args: "admin, w, []", + }, + when: { + t_ms: 1762199783634, + } as any, + }, + }} + /> <div class="columns is-centered" style={{ margin: "auto" }}> <div class="column is-two-thirds "> <div class="modal-card" style={{ width: "100%", margin: 0 }}> @@ -241,3 +266,51 @@ export function LoginPage({ showCreateAccount }: Props): VNode { </Fragment> ); } + +function LocalNotificationBannerBulma({ + notification, +}: { + notification?: Notification; +}): VNode { + const { showDebugInfo, toggle } = useCommonPreference(); + if (!notification) return <Fragment />; + const msg = notification.message; + switch (msg.type) { + case "error": + return ( + <div class="notification"> + <div class="columns is-vcentered"> + <div class="column is-12"> + <article class="message is-danger"> + <div class="message-header"> + <p>{msg.title}</p> + </div> + {msg.description && ( + <div class="message-body"> + <div>{msg.description}</div> + {!showDebugInfo ? undefined : msg.debug && ( + <pre> {JSON.stringify(msg.debug, undefined, 2)}</pre> + )} + </div> + )} + </article> + </div> + </div> + </div> + ); + case "info": + return ( + <div class="notification"> + <div class="columns is-vcentered"> + <div class="column is-12"> + <article class="message is-info"> + <div class="message-header"> + <p>{msg.title}</p> + </div> + </article> + </div> + </div> + </div> + ); + } +} diff --git a/packages/merchant-backoffice-ui/src/paths/settings/index.tsx b/packages/merchant-backoffice-ui/src/paths/settings/index.tsx @@ -15,7 +15,7 @@ */ import { AbsoluteTime } from "@gnu-taler/taler-util"; -import { useLang, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { useCommonPreference, useLang, useTranslationContext } from "@gnu-taler/web-util/browser"; import { VNode, h } from "preact"; import { FormErrors, @@ -26,22 +26,27 @@ import { InputToggle } from "../../components/form/InputToggle.js"; import { LangSelector } from "../../components/menu/LangSelector.js"; import { Preferences, usePreference } from "../../hooks/preference.js"; +type FormType = Preferences & {developerMode: boolean} export function Settings({ onClose }: { onClose?: () => void }): VNode { const { i18n } = useTranslationContext(); const [value, , updateValue] = usePreference(); - const errors: FormErrors<Preferences> = {}; + const {showDebugInfo, toggle} = useCommonPreference(); + const errors: FormErrors<FormType> = {}; - function valueHandler(s: (d: Partial<Preferences>) => Partial<Preferences>): void { + function valueHandler(s: (d: Partial<FormType>) => Partial<FormType>): void { const next = s(value); const v: Preferences = { advanceOrderMode: next.advanceOrderMode ?? false, advanceInstanceMode: next.advanceInstanceMode ?? false, - developerMode: next.developerMode ?? false, hideMissingAccountUntil: next.hideMissingAccountUntil ?? AbsoluteTime.never(), hideKycUntil: next.hideKycUntil ?? AbsoluteTime.never(), dateFormat: next.dateFormat ?? "ymd", }; + if (next.developerMode !== undefined && next.developerMode !== showDebugInfo) { + toggle() + } + updateValue(v); } @@ -52,10 +57,13 @@ export function Settings({ onClose }: { onClose?: () => void }): VNode { <div class="column" /> <div class="column is-four-fifths"> <div> - <FormProvider<Preferences> + <FormProvider<FormType> name="settings" errors={errors} - object={value} + object={{ + ...value, + developerMode: showDebugInfo + }} valueHandler={valueHandler} > <div class="field is-horizontal"> @@ -108,7 +116,7 @@ export function Settings({ onClose }: { onClose?: () => void }): VNode { values={["ymd", "mdy", "dmy"]} tooltip={i18n.str`How the date is going to be displayed`} /> - <InputToggle<Preferences> + <InputToggle<FormType> label={i18n.str`Developer mode`} tooltip={i18n.str`Shows more options and tools that are not intended for a general audience.`} name="developerMode" diff --git a/packages/web-util/src/hooks/useNotifications.ts b/packages/web-util/src/hooks/useNotifications.ts @@ -11,7 +11,6 @@ import { TranslatedString, } from "@gnu-taler/taler-util"; import { useEffect, useState } from "preact/hooks"; -import { ButtonHandler } from "../components/Button.js"; import { InternationalizationAPI, memoryMap,