taler-typescript-core

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

commit f62dbfaf8593ecaa72c3911f6d55713beeee3dc8
parent 7fd25c6cb00f106e8487283dbeee59b562c382e9
Author: Sebastian <sebasjm@taler-systems.com>
Date:   Thu,  5 Mar 2026 15:33:44 -0300

fix #11189

Diffstat:
Mpackages/merchant-backoffice-ui/src/components/SolveMFA.tsx | 37+++++++++++++++++++++----------------
Mpackages/merchant-backoffice-ui/src/components/form/InputToggle.tsx | 28++++++++++++++++++++++++++--
Mpackages/merchant-backoffice-ui/src/components/form/InputWithAddon.tsx | 3+++
Mpackages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx | 30+++++++++++++++---------------
Mpackages/merchant-backoffice-ui/src/paths/newAccount/index.tsx | 68++++++++++++++++++++++++++++++++++++++------------------------------
5 files changed, 103 insertions(+), 63 deletions(-)

diff --git a/packages/merchant-backoffice-ui/src/components/SolveMFA.tsx b/packages/merchant-backoffice-ui/src/components/SolveMFA.tsx @@ -26,9 +26,7 @@ import { usePreference, } from "../hooks/preference.js"; import { FormErrors, FormProvider } from "./form/FormProvider.js"; -import { Input } from "./form/Input.js"; import { InputCode } from "./form/InputCode.js"; -import { time } from "console"; const TALER_SCREEN_ID = 5; @@ -38,6 +36,7 @@ export interface Props { currentChallenge: ChallengeResponse; focus?: boolean; initial?: { request: Challenge; response: ChallengeRequestResponse }; + showFull?: Partial<Record<TanChannel, string>>; } interface Form { @@ -54,12 +53,14 @@ function SolveChallenge({ onCancel, onSolved, focus, + showFull, }: { onCancel: () => void; challenge: Challenge; expiration: AbsoluteTime; onSolved: () => void; focus?: boolean; + showFull: Partial<Record<TanChannel, string>>; }): VNode { const { i18n } = useTranslationContext(); const { lib } = useSessionContext(); @@ -170,6 +171,14 @@ function SolveChallenge({ {(function (): VNode { switch (challenge.tan_channel) { case TanChannel.SMS: + if (showFull[TanChannel.SMS]) { + return ( + <i18n.Translate> + The verification code sent to the phone " + <b>{showFull[TanChannel.SMS]}</b>" + </i18n.Translate> + ); + } return ( <i18n.Translate> The verification code sent to the phone number ending @@ -177,6 +186,14 @@ function SolveChallenge({ </i18n.Translate> ); case TanChannel.EMAIL: + if (showFull[TanChannel.EMAIL]) { + return ( + <i18n.Translate> + The verification code sent to the email address " + <b>{showFull[TanChannel.EMAIL]}</b>" + </i18n.Translate> + ); + } return ( <i18n.Translate> The verification code sent to the email address @@ -256,6 +273,7 @@ export function SolveMFAChallenges({ onCancel, initial, focus, + showFull, }: Props): VNode { const { i18n } = useTranslationContext(); const { state: session, lib, logIn } = useSessionContext(); @@ -361,20 +379,7 @@ export function SolveMFAChallenges({ challenge={selected.ch} expiration={selected.expiration} focus={focus} - // onSolved={() => { - // setSelected(undefined); - // const newSolved = [...solved, selected.ch.challenge_id]; - - // const done = currentChallenge.combi_and - // ? newSolved.length === currentChallenge.challenges.length - // : newSolved.length > 0; - - // if (done) { - // onCompleted(newSolved); - // } else { - // setSolved(newSolved); - // } - // }} + showFull={showFull ?? {}} onSolved={async () => { setSelected(undefined); const total = [...solved, selected.ch.challenge_id]; diff --git a/packages/merchant-backoffice-ui/src/components/form/InputToggle.tsx b/packages/merchant-backoffice-ui/src/components/form/InputToggle.tsx @@ -66,13 +66,27 @@ export function InputToggle<T>({ * </span> )} - {tooltip && <Tooltip text={tooltip} ><i class="icon mdi mdi-information" /></Tooltip>} + {tooltip && ( + <Tooltip text={tooltip}> + <i class="icon mdi mdi-information" /> + </Tooltip> + )} </label> </div> <div class="field-body is-flex-grow-3"> <div class="field"> <p class={expand ? "control is-expanded" : "control"}> <label class="toggle" style={{ marginLeft: 4, marginTop: 0 }}> + {/* <div class="group relative inline-flex w-11 shrink-0 rounded-full bg-gray-200 p-0.5 inset-ring inset-ring-gray-900/5 outline-offset-2 outline-indigo-600 transition-colors duration-200 ease-in-out has-checked:bg-indigo-600 has-focus-visible:outline-2 dark:bg-white/5 dark:inset-ring-white/10 dark:outline-indigo-500 dark:has-checked:bg-indigo-500"> + <span class="size-5 rounded-full bg-white shadow-xs ring-1 ring-gray-900/5 transition-transform duration-200 ease-in-out group-has-checked:translate-x-5"></span> + <input + type="checkbox" + name="setting" + aria-label="Use setting" + class="absolute inset-0 size-full appearance-none focus:outline-hidden" + /> + </div> */} + <input type="checkbox" class={"toggle-checkbox"} @@ -86,16 +100,26 @@ export function InputToggle<T>({ }} readonly={readonly} name={String(name)} + style={{visibility:"inherit", appearance:"none"}} disabled={readonly} onChange={onCheckboxClick} /> <div + // type="button" class={`toggle-switch ${readonly ? "disabled" : ""} ${ toBoolean(value) === undefined ? "no-dot" : "" }`} + // tabIndex={0} + // role="switch" + // aria-checked={toBoolean(value)} + // onKeyPress={(e) => { + // if (e.key === "y") { + // onCheckboxClick(); + // } + // }} style={{ cursor: readonly ? "default" : undefined }} - ></div> + /> </label> <p>{help}</p> </p> diff --git a/packages/merchant-backoffice-ui/src/components/form/InputWithAddon.tsx b/packages/merchant-backoffice-ui/src/components/form/InputWithAddon.tsx @@ -39,6 +39,7 @@ export interface Props<T> extends InputProps<T> { inputExtra?: any; children?: ComponentChildren; side?: ComponentChildren; + focus?:boolean; autoComplete?: SupportedAutocomplete; } @@ -60,6 +61,7 @@ export function InputWithAddon<T>({ inputType, inputExtra, side, + focus, addonAfter, addonAfterAction, toStr = defaultToString, @@ -112,6 +114,7 @@ export function InputWithAddon<T>({ readonly={readonly} autoComplete={autoComplete} disabled={readonly} + focus={focus} name={String(name)} value={toStr(value)} onChange={(e: h.JSX.TargetedEvent<HTMLInputElement>): void => diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/CreatePage.tsx @@ -826,23 +826,23 @@ export function CreatePage({ </div> </InputGroup> </FragmentPersonaFlag> + <div class="buttons is-right mt-5"> + {onBack && ( + <button class="button" type="button" onClick={onBack}> + <i18n.Translate>Cancel</i18n.Translate> + </button> + )} + <ButtonBetterBulma + class="button is-success" + type="submit" + onClick={create} + > + <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 - class="button is-success" - type="submit" - onClick={create} - > - <i18n.Translate>Confirm</i18n.Translate> - </ButtonBetterBulma> - </div> </div> + <div class="column" /> </div> </section> diff --git a/packages/merchant-backoffice-ui/src/paths/newAccount/index.tsx b/packages/merchant-backoffice-ui/src/paths/newAccount/index.tsx @@ -236,6 +236,10 @@ export function NewAccount({ onCancel, onCreated }: Props): VNode { onCompleted={retry} initial={mfa.initial} focus + showFull={{ + [TanChannel.EMAIL]: value.email, + [TanChannel.SMS]: value.phone, + }} onCancel={mfa.doCancelChallenge} /> ); @@ -256,21 +260,22 @@ export function NewAccount({ onCancel, onCreated }: Props): VNode { <i18n.Translate>Self provision</i18n.Translate> </p> </header> - <section - class="modal-card-body" - style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }} + <FormProvider<Account> + name="settings" + errors={errors} + object={value} + valueHandler={valueHandler} > - <FormProvider<Account> - name="settings" - errors={errors} - object={value} - valueHandler={valueHandler} + <section + class="modal-card-body" + style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }} > <InputWithAddon<Account> name="id" label={i18n.str`Username`} tooltip={i18n.str`Name of the instance in URLs. The 'admin' instance is special in that it is used to administer other instances.`} autoComplete="username" + focus /> <Input<Account> @@ -298,6 +303,7 @@ export function NewAccount({ onCancel, onCreated }: Props): VNode { label={i18n.str`Email`} tooltip={i18n.str`Contact email`} name="email" + inputType="email" autoComplete="email" /> ) : undefined} @@ -306,6 +312,7 @@ export function NewAccount({ onCancel, onCreated }: Props): VNode { label={i18n.str`Phone`} tooltip={i18n.str`Contact phone number`} name="phone" + inputType="tel" autoComplete="tel" /> ) : undefined} @@ -318,6 +325,7 @@ export function NewAccount({ onCancel, onCreated }: Props): VNode { <a href="/terms" target="_blank" + tabIndex={-1} referrerpolicy="no-referrer" > <i18n.Translate>Terms of service</i18n.Translate> @@ -326,30 +334,30 @@ export function NewAccount({ onCancel, onCreated }: Props): VNode { } tooltip={i18n.str`You must accept the Terms of service to continue.`} /> - </FormProvider> - </section> - <footer - class="modal-card-foot " - style={{ - justifyContent: "space-between", - border: "1px solid", - borderTop: 0, - }} - > - <button - class="button" - type="button" - onClick={() => { - saveForm({}); - onCancel(); + </section> + <footer + class="modal-card-foot " + style={{ + justifyContent: "space-between", + border: "1px solid", + borderTop: 0, }} > - <i18n.Translate>Cancel</i18n.Translate> - </button> - <ButtonBetterBulma onClick={create} type="submit"> - <i18n.Translate>Create</i18n.Translate> - </ButtonBetterBulma> - </footer> + <button + class="button" + type="button" + onClick={() => { + saveForm({}); + onCancel(); + }} + > + <i18n.Translate>Cancel</i18n.Translate> + </button> + <ButtonBetterBulma onClick={create} type="submit"> + <i18n.Translate>Create</i18n.Translate> + </ButtonBetterBulma> + </footer> + </FormProvider> </div> </div> </div>