taler-typescript-core

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

commit ca11dd20231ad9f1c8e06b0e257061ccccc324d5
parent 4098fb972e566cd2f718056279a547136f69d10f
Author: Sebastian <sebasjm@gmail.com>
Date:   Fri, 14 Nov 2025 11:08:04 -0300

fix horrible rendering on error

Diffstat:
Mpackages/merchant-backoffice-ui/src/components/SolveMFA.tsx | 4++--
Mpackages/merchant-backoffice-ui/src/components/form/JumpToElementById.tsx | 64+++++++++++++++++++++++++++++++++++++++++++---------------------
Mpackages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx | 75++++++++++++++++++++++++++++++++++-----------------------------------------
Mpackages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx | 10++++++++--
Mpackages/merchant-backoffice-ui/src/paths/newAccount/index.tsx | 4++--
5 files changed, 89 insertions(+), 68 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/components/SolveMFA.tsx b/packages/merchant-backoffice-ui/src/components/SolveMFA.tsx @@ -175,11 +175,11 @@ function SolveChallenge({ borderTop: 0, }} > - <button class="button" onClick={onCancel}> + <button class="button" type="button" onClick={onCancel}> <i18n.Translate>Back</i18n.Translate> </button> <ButtonBetterBulma - type="is-info" + type="submit" onClick={verify} > <i18n.Translate>Verify</i18n.Translate> diff --git a/packages/merchant-backoffice-ui/src/components/form/JumpToElementById.tsx b/packages/merchant-backoffice-ui/src/components/form/JumpToElementById.tsx @@ -15,9 +15,8 @@ */ import { AccessToken, TranslatedString } from "@gnu-taler/taler-util"; import { - ButtonBetter, ButtonBetterBulma, - LocalNotificationBanner, + Notification, useLocalNotificationBetter, useTranslationContext, } from "@gnu-taler/web-util/browser"; @@ -25,6 +24,21 @@ import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { useSessionContext } from "../../context/session.js"; +function NotificationFieldFoot({ + notification, +}: { + notification?: Notification; +}): VNode | null { + if (!notification) return null; + if (notification.message.type === "error") + return ( + <p class="help is-danger" style={{ fontSize: 16 }}> + {notification.message.description} + </p> + ); + return null; +} + export function JumpToElementById({ onSelect, placeholder, @@ -51,29 +65,37 @@ export function JumpToElementById({ return ( <Fragment> - <LocalNotificationBanner notification={notification} /> - <div class="level"> <div class="level-left"> <div class="level-item"> - <div class="field has-addons"> - <div class="control"> - <input - class={"input"} - type="text" - value={id ?? ""} - onChange={(e) => setId(e.currentTarget.value)} - placeholder={placeholder} - /> + <form> + <div class="field has-addons"> + <div class="control"> + <input + class={"input"} + type="text" + value={id ?? ""} + onChange={(e) => { + setId(e.currentTarget.value) + if (notification) notification.acknowledge() + }} + placeholder={placeholder} + /> + <NotificationFieldFoot notification={notification} /> + </div> + <span class="has-tooltip-bottom" data-tooltip={description}> + <ButtonBetterBulma + class="button" + type="submit" + onClick={checkExist} + > + <span class="icon"> + <i class="mdi mdi-arrow-right" /> + </span> + </ButtonBetterBulma> + </span> </div> - <span class="has-tooltip-bottom" data-tooltip={description}> - <ButtonBetterBulma class="button" onClick={checkExist}> - <span class="icon"> - <i class="mdi mdi-arrow-right" /> - </span> - </ButtonBetterBulma> - </span> - </div> + </form> </div> </div> </div> diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx @@ -58,6 +58,8 @@ export type Entity = TalerMerchantApi.InstanceConfigurationMessage & { auth_token?: string; // default_pay_delay: Duration; // default_wire_transfer_delay: Duration; + password: string; + repeat: string; }; export interface Props { @@ -78,13 +80,12 @@ function with_defaults(id?: string): Partial<Entity> { }; } -type TokenForm = { password: string; repeat: string }; +// type TokenForm = { }; export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { const [pref, updatePref] = usePreference(); const { i18n } = useTranslationContext(); const [value, valueHandler] = useState(with_defaults(forceId)); - const [tokenForm, setTokenForm] = useState<Partial<TokenForm>>({}); const errors = undefinedIfEmpty<FormErrors<Entity>>({ id: !value.id @@ -128,20 +129,15 @@ export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { ? i18n.str`Max 7 lines` : undefined, }), - }); - - const hasErrors = errors !== undefined; - - const tokenFormErrors = undefinedIfEmpty<FormErrors<TokenForm>>({ - password: !tokenForm.password ? i18n.str`Required` : undefined, - repeat: !tokenForm.repeat + password: !value.password ? i18n.str`Required` : undefined, + repeat: !value.repeat ? i18n.str`Required` - : tokenForm.repeat !== tokenForm.password + : value.repeat !== value.password ? i18n.str`Doesn't match` : undefined, }); - const hasTokenErrors = tokenFormErrors !== undefined; + const hasErrors = errors !== undefined; const [notification, safeFunctionHandler] = useLocalNotificationBetter(); const { state: session, lib, logIn } = useSessionContext(); const mfa = useChallengeHandler(); @@ -150,7 +146,7 @@ export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { ...(value as TalerMerchantApi.InstanceConfigurationMessage), auth: { method: MerchantAuthMethod.TOKEN, - password: tokenForm.password!, + password: value.password!, }, }; const create = safeFunctionHandler( @@ -166,7 +162,11 @@ export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { }); if (instanceResp.type === "fail") return instanceResp; if (data.auth.password) { - const tokenResp = await lib.subInstanceApi(data.id).instance.createAccessToken( + const api = + data.id === "admin" + ? lib.instance + : lib.subInstanceApi(data.id).instance; + const tokenResp = await api.createAccessToken( data.id, data.auth.password, FOREVER_REFRESHABLE_TOKEN(i18n.str`Instance created`), @@ -176,9 +176,7 @@ export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { } return opEmptySuccess(); }, - !session.token || hasErrors || hasTokenErrors - ? undefined - : [session.token, data, []], + !session.token || hasErrors ? undefined : [session.token, data, []], ); create.onSuccess = (success, oldtoken, data) => { if (success) { @@ -260,42 +258,37 @@ export function CreatePage({ onConfirm, onBack, forceId }: Props): VNode { showId={!forceId} showLessFields={!pref.advanceInstanceMode} /> - </FormProvider> - <FormProvider - errors={tokenFormErrors} - object={tokenForm} - valueHandler={setTokenForm} - > - <Input<TokenForm> + <Input<Entity> name="password" label={i18n.str`New password`} tooltip={i18n.str`Next password to be used`} inputType="password" /> - <Input<TokenForm> + <Input<Entity> name="repeat" label={i18n.str`Repeat password`} tooltip={i18n.str`Confirm the same password`} inputType="password" /> + <div class="buttons is-right mt-5"> + {onBack && ( + <button class="button" type="button" onClick={onBack}> + <i18n.Translate>Cancel</i18n.Translate> + </button> + )} + <ButtonBetterBulma + onClick={create} + type="submit" + data-tooltip={ + hasErrors + ? i18n.str`Please complete the marked fields and choose authorization method` + : i18n.str`Confirm operation` + } + > + <i18n.Translate>Confirm</i18n.Translate> + </ButtonBetterBulma> + </div> </FormProvider> - <div class="buttons is-right mt-5"> - {onBack && ( - <button class="button" onClick={onBack}> - <i18n.Translate>Cancel</i18n.Translate> - </button> - )} - <ButtonBetterBulma - onClick={create} - data-tooltip={ - hasErrors - ? i18n.str`Please complete the marked fields and choose authorization method` - : i18n.str`Confirm operation` - } - > - <i18n.Translate>Confirm</i18n.Translate> - </ButtonBetterBulma> - </div> </div> <div class="column" /> </div> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx @@ -74,7 +74,12 @@ function convert(from: TalerMerchantApi.QueryInstancesResponse): Entity { return { ...defaults, ...rest } as Entity; } -export function UpdatePage({ doUpdate, onConfirm, selected, onBack }: Props): VNode { +export function UpdatePage({ + doUpdate, + onConfirm, + selected, + onBack, +}: Props): VNode { const { state } = useSessionContext(); const [value, valueHandler] = useState<Partial<Entity>>(convert(selected)); @@ -127,7 +132,7 @@ export function UpdatePage({ doUpdate, onConfirm, selected, onBack }: Props): VN d: TalerMerchantApi.InstanceReconfigurationMessage, challengeIds: string[], ) => doUpdate(token, d, { challengeIds }), - hasErrors || !state.token? undefined : [state.token, result, []] + hasErrors || !state.token ? undefined : [state.token, result, []], ); update.onSuccess = onConfirm; update.onFail = (fail) => { @@ -199,6 +204,7 @@ export function UpdatePage({ doUpdate, onConfirm, selected, onBack }: Props): VN </button> <ButtonBetterBulma + type="submit" onClick={update} data-tooltip={ hasErrors diff --git a/packages/merchant-backoffice-ui/src/paths/newAccount/index.tsx b/packages/merchant-backoffice-ui/src/paths/newAccount/index.tsx @@ -245,10 +245,10 @@ export function NewAccount({ onCancel, onCreated }: Props): VNode { borderTop: 0, }} > - <button class="button" onClick={onCancel}> + <button class="button" type="button" onClick={onCancel}> <i18n.Translate>Cancel</i18n.Translate> </button> - <ButtonBetterBulma type="is-info" onClick={create}> + <ButtonBetterBulma onClick={create} type="submit"> <i18n.Translate>Create</i18n.Translate> </ButtonBetterBulma> </footer>