taler-typescript-core

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

commit 8a0eb7fefc4ee30df6ab15d3609058e4ee524979
parent b69c478e8e7b5d209a563629cb53cc3ccb23fd97
Author: Sebastian <sebasjm@gmail.com>
Date:   Mon,  3 Nov 2025 10:27:47 -0300

fix calling on chain

Diffstat:
Mpackages/bank-ui/src/hooks/preferences.ts | 5-----
Mpackages/bank-ui/src/pages/LoginForm.tsx | 15+++++----------
Mpackages/bank-ui/src/pages/RegistrationPage.tsx | 39++++++++++++++++-----------------------
Mpackages/bank-ui/src/settings.json | 1-
Mpackages/bank-ui/src/settings.ts | 9---------
Mpackages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/update/UpdatePage.tsx | 2+-
Mpackages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/update/index.tsx | 29-----------------------------
Mpackages/web-util/src/hooks/useNotifications.ts | 114++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
8 files changed, 85 insertions(+), 129 deletions(-)

diff --git a/packages/bank-ui/src/hooks/preferences.ts b/packages/bank-ui/src/hooks/preferences.ts @@ -35,7 +35,6 @@ interface Preferences { showWithdrawalSuccess: boolean; hideDemo: boolean; showInstallWallet: boolean; - allowsSimplePassword: boolean; fastWithdrawalForm: boolean; } @@ -44,14 +43,12 @@ export const codecForPreferences = (): Codec<Preferences> => .property("showWithdrawalSuccess", codecForBoolean()) .property("hideDemo", codecOptionalDefault(codecForBoolean(), false)) .property("showInstallWallet", codecForBoolean()) - .property("allowsSimplePassword", codecForBoolean()) .property("fastWithdrawalForm", codecForBoolean()) .build("Preferences"); const defaultPreferences: Preferences = { showWithdrawalSuccess: true, hideDemo: true, - allowsSimplePassword: false, showInstallWallet: true, fastWithdrawalForm: false, }; @@ -112,8 +109,6 @@ export function getLabelForPreferences( return i18n.str`Hide demo hint.`; case "showInstallWallet": return i18n.str`Show install wallet first`; - case "allowsSimplePassword": - return i18n.str`Remove password length validation on registration`; // case "showDebugInfo": // return i18n.str`Show debug info`; } diff --git a/packages/bank-ui/src/pages/LoginForm.tsx b/packages/bank-ui/src/pages/LoginForm.tsx @@ -39,6 +39,7 @@ import { undefinedIfEmpty } from "../utils.js"; import { doAutoFocus } from "./PaytoWireTransferForm.js"; import { USERNAME_REGEX } from "./RegistrationPage.js"; import { SolveMFAChallenges } from "./SolveMFA.js"; +import { opEmptySuccess } from "@gnu-taler/taler-util"; const TALER_SCREEN_ID = 104; @@ -92,17 +93,11 @@ export function LoginForm({ password: !password ? i18n.str`Missing password` : undefined, }); - const logout = safeFunctionHandler( - api.deleteAccessToken, - !sessionState ? undefined : [sessionState.username, sessionState.token], - ); + const logout = safeFunctionHandler(async () => { + session.logOut(); + return opEmptySuccess(); + }, []); logout.onSuccess = session.logOut; - logout.onFail = (fail) => { - switch (fail.case) { - case HttpStatusCode.NotFound: - return i18n.str`User doesn't exist anymore.`; - } - }; const tokenRequest = { scope: "readwrite", diff --git a/packages/bank-ui/src/pages/RegistrationPage.tsx b/packages/bank-ui/src/pages/RegistrationPage.tsx @@ -97,7 +97,7 @@ function RegistrationForm({ : undefined, password: !password ? i18n.str`Missing password` - : pref.allowsSimplePassword && password.length < 8 + : password.length < 8 ? i18n.str`The password should be longer than 8 letters` : undefined, repeatPassword: !repeatPassword @@ -108,7 +108,7 @@ function RegistrationForm({ }); const reg: TalerCorebankApi.RegisterAccountRequest | undefined = - !name || !username || !password + !name || !username || !password || !!errors ? undefined : { name, @@ -126,6 +126,7 @@ function RegistrationForm({ setUsername(undefined); setPassword(undefined); setRepeatPassword(undefined); + setName(undefined) onRegistrationSuccesful(acc.username, acc.password); }; @@ -160,24 +161,18 @@ function RegistrationForm({ case TalerErrorCode.BANK_PASSWORD_TOO_LONG: return i18n.str`The password is too long. Can't have more than 64 characters.`; } - }; const registerRandom = register.lambda(() => { const user = getRandomUsername(); - const password = settings.simplePasswordForRandomAccounts - ? pref.allowsSimplePassword - ? "123" - : "12345678" - : getRandomPassword(); + const password = "12345678"; const username = `_${user.first}-${user.second}_`; const name = `${capitalizeFirstLetter(user.first)} ${capitalizeFirstLetter( user.second, )}`; - return [{name, username, password}] - },[]) - + return [{ name, username, password }]; + }, []); return ( <Fragment> @@ -259,16 +254,14 @@ function RegistrationForm({ isDirty={password !== undefined} /> </div> - {pref.allowsSimplePassword ? undefined : ( - <p class="mt-2 text-sm text-gray-500"> - <i18n.Translate> - Use a strong password: 8 characters minimum, don't use any - public information related to you (names, birthday, phone - number, etc...) and mix lowercase, uppercase, symbols and - numbers - </i18n.Translate> - </p> - )} + <p class="mt-2 text-sm text-gray-500"> + <i18n.Translate> + Use a strong password: 8 characters minimum, don't use any + public information related to you (names, birthday, phone + number, etc...) and mix lowercase, uppercase, symbols and + numbers + </i18n.Translate> + </p> </div> <div> @@ -343,7 +336,7 @@ function RegistrationForm({ <ButtonBetter type="submit" name="register" - class=" rounded-md bg-indigo-600 disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" + class="rounded-md bg-indigo-600 disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" onClick={register} > <i18n.Translate>Register</i18n.Translate> @@ -356,7 +349,7 @@ function RegistrationForm({ <ButtonBetter type="submit" name="create random" - class="flex mt-4 w-full justify-center rounded-md bg-green-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600" + class="flex mt-4 w-full disabled:bg-gray-300 justify-center rounded-md bg-green-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600" onClick={registerRandom} > <i18n.Translate>Create a random temporary user</i18n.Translate> diff --git a/packages/bank-ui/src/settings.json b/packages/bank-ui/src/settings.json @@ -1,6 +1,5 @@ { "backendBaseURL": "http://bank.taler.test/", - "simplePasswordForRandomAccounts": true, "allowRandomAccountCreation": true, "fastWithdrawalForm": true, "defaultSuggestedAmount": 11, diff --git a/packages/bank-ui/src/settings.ts b/packages/bank-ui/src/settings.ts @@ -33,10 +33,6 @@ export interface UiSettings { // Useful for testing // default: false allowRandomAccountCreation?: boolean; - // Create all random accounts with password "12345678" or "123" - // Useful for testing - // default: false - simplePasswordForRandomAccounts?: boolean; // URL where the user is going to be redirected after // clicking in Taler Logo // default: home page @@ -61,7 +57,6 @@ export interface UiSettings { const defaultSettings: UiSettings = { backendBaseURL: buildDefaultBackendBaseURL(), iconLinkURL: undefined, - simplePasswordForRandomAccounts: false, allowRandomAccountCreation: false, showDemoDescription: false, topNavSites: {}, @@ -74,10 +69,6 @@ const codecForUISettings = (): Codec<UiSettings> => .property("allowRandomAccountCreation", codecOptional(codecForBoolean())) .property("showDemoDescription", codecOptional(codecForBoolean())) .property("defaultSuggestedAmount", codecOptional(codecForNumber())) - .property( - "simplePasswordForRandomAccounts", - codecOptional(codecForBoolean()), - ) .property("iconLinkURL", codecOptional(codecForString())) .property("topNavSites", codecOptional(codecForMap(codecForString()))) .build("UiSettings"); diff --git a/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/update/UpdatePage.tsx @@ -27,8 +27,8 @@ import { FormErrors, FormProvider } from "../../../../components/form/FormProvid import { Input } from "../../../../components/form/Input.js"; import { InputDate } from "../../../../components/form/InputDate.js"; import { InputDuration } from "../../../../components/form/InputDuration.js"; -import { undefinedIfEmpty } from "../../../../utils/table.js"; import { useSessionContext } from "../../../../context/session.js"; +import { undefinedIfEmpty } from "../../../../utils/table.js"; type Entity = TalerMerchantApi.TokenFamilyUpdateRequest; diff --git a/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/tokenfamilies/update/index.tsx @@ -25,11 +25,9 @@ import { TalerMerchantApi, assertUnreachable, } from "@gnu-taler/taler-util"; -import { LocalNotificationBannerBulma, useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { ErrorLoadingMerchant } from "../../../../components/ErrorLoadingMerchant.js"; import { Loading } from "../../../../components/exception/loading.js"; -import { useSessionContext } from "../../../../context/session.js"; import { useTokenFamilyDetails } from "../../../../hooks/tokenfamily.js"; import { LoginPage } from "../../../login/index.js"; import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; @@ -73,33 +71,6 @@ export default function UpdateTokenFamily({ tokenFamily={result.body} onBack={onBack} onUpdated={onConfirm} - // onUpdate={(data) => { - // return lib.instance - // .updateTokenFamily(state.token, slug, data) - // .then((resp) => { - // if (resp.type === "ok") { - // setNotif({ - // message: i18n.str`Token family updated successfully`, - // type: "SUCCESS", - // }); - // onConfirm(); - // } else { - // setNotif({ - // message: i18n.str`Could not update token family`, - // type: "ERROR", - // description: resp.detail?.hint, - // }); - // } - // }) - // .catch((error) => { - // setNotif({ - // message: i18n.str`Could not update token family`, - // type: "ERROR", - // description: - // error instanceof Error ? error.message : String(error), - // }); - // }); - // }} /> </Fragment> ); diff --git a/packages/web-util/src/hooks/useNotifications.ts b/packages/web-util/src/hooks/useNotifications.ts @@ -232,62 +232,74 @@ export function useLocalNotificationBetter(): [ doAction: (...args: Args) => Promise<R>, args?: Args, ): SafeHandlerTemplate<Args, R> { - const handler: SafeHandlerTemplate<Args, R> = { - args, - withArgs(...newArgs) { - return { - ...handler, - args: newArgs, - }; - }, - lambda(converter) { - type D = Parameters<typeof converter>; - type SH = SafeHandlerTemplate<D, R>; - const r = { - ...handler, - args: undefined, - withArgs(...args: D) { + function buildSafeHandler( + a: Args | undefined, + doAction: (...args: Args) => Promise<R>, + ): SafeHandlerTemplate<Args, R> { + const thiz: SafeHandlerTemplate<Args, R> = { + args: a, + withArgs: (...newArgs) => { + const r = buildSafeHandler(newArgs, doAction) + r.onSuccess = thiz.onSuccess + r.onFail = thiz.onFail + return r + }, + lambda: (converter, init) => { + type D = Parameters<typeof converter>; + type SH = SafeHandlerTemplate<D, R>; + + const r = buildSafeHandler( + // @ts-expect-error + init ? converter(init) : undefined, + doAction, + ); + // @ts-expect-error + r.withArgs = (...args: D) => { const d = converter(...args); - const e = handler.withArgs(...d); + const e = r.withArgs(...(d as any)); return e; - }, - }; - return r as any as SH; - }, - call: async (): Promise<void> => { - if (!handler.args) return; - try { - const resp = await doAction(...handler.args); - switch (resp.type) { - case "ok": { - const msg = handler.onSuccess(resp as any, ...handler.args); - if (msg) { - save(successWithTitle(msg)); + }; + r.onSuccess = thiz.onSuccess + r.onFail = thiz.onFail + return r as any as SH; + }, + call: async (): Promise<void> => { + if (!thiz.args) return; + try { + const resp = await doAction(...thiz.args); + switch (resp.type) { + case "ok": { + const msg = thiz.onSuccess(resp.body, ...thiz.args); + if (msg) { + save(successWithTitle(msg)); + } + return; } - return; - } - case "fail": { - const error = handler.onFail(resp as any, ...handler.args); - if (error) { - save(failWithTitle(resp, error)); + case "fail": { + const error = thiz.onFail(resp as any, ...thiz.args); + if (error) { + save(failWithTitle(resp, error)); + } + return; + } + default: { + assertUnreachable(resp); } - return; - } - default: { - assertUnreachable(resp); } + } catch (error: unknown) { + // This functions should not throw, this is a problem. + console.error(`Error: `, error); + onUnexpected(i18n, save)(error); + return; } - } catch (error: unknown) { - // This functions should not throw, this is a problem. - console.error(`Error: `, error); - onUnexpected(i18n, save)(error); - return; - } - }, - onFail: (fail, ...rest) => i18n.str`Unhandled failure, please report. Code ${(fail.case)}`, - onSuccess: () => undefined, - }; - return handler; + }, + onFail: (fail, ...rest) => + i18n.str`Unhandled failure, please report. Code ${fail.case}`, + onSuccess: () => undefined, + }; + return thiz; + } + return buildSafeHandler(args, doAction); } return [notif, safeFunctionHandler]; @@ -342,7 +354,7 @@ export interface SafeHandlerTemplate<Args extends any[], Errors> { */ lambda<OtherArgs extends any[]>( e: (...d: OtherArgs) => Args, - init?: OtherArgs + init?: OtherArgs, ): SafeHandlerTemplate<OtherArgs, Errors>; /** * creates another handler with new arguements