commit dcf109fd69add8b61acb570641fa1deeeef64fd1
parent 4611940d61d721dbd5b8cca9faed3795da113ca6
Author: Sebastian <sebasjm@gmail.com>
Date: Sat, 15 Nov 2025 18:11:23 -0300
fix #10597
Diffstat:
3 files changed, 74 insertions(+), 67 deletions(-)
diff --git a/packages/merchant-backoffice-ui/src/components/notifications/CreatedSuccessfully.tsx b/packages/merchant-backoffice-ui/src/components/notifications/CreatedSuccessfully.tsx
@@ -17,19 +17,24 @@
*
* @author Sebastian Javier Marchano (sebasjm)
*/
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { ComponentChildren, h, VNode } from "preact";
+import { doAutoFocus } from "../../../../web-util/src/components/utils.js";
interface Props {
onCreateAnother?: () => void;
onConfirm: () => void;
+ focus?: boolean;
children: ComponentChildren;
}
export function CreatedSuccessfully({
children,
+ focus,
onConfirm,
onCreateAnother,
}: Props): VNode {
+ const { i18n } = useTranslationContext()
return (
<div class="columns is-fullwidth is-vcentered mt-3">
<div class="column" />
@@ -43,11 +48,11 @@ export function CreatedSuccessfully({
<div class="buttons is-right">
{onCreateAnother && (
<button class="button is-info" onClick={onCreateAnother}>
- Create another
+ <i18n.Translate>Create another</i18n.Translate>
</button>
)}
- <button class="button is-info" onClick={onConfirm}>
- Continue
+ <button class="button is-info" ref={focus ? doAutoFocus : undefined} onClick={onConfirm}>
+ <i18n.Translate>Continue</i18n.Translate>
</button>
</div>
</div>
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatePage.tsx
@@ -50,13 +50,19 @@ interface Props {
onBack?: () => void;
}
-const algorithms = [0, 1, 2];
-const algorithmsNames = ["off", "30s 8d TOTP-SHA1", "30s 8d eTOTP-SHA1"];
+const algorithms = [0, 1];
+const algorithmsNames = ["30s 8d TOTP-SHA1", "30s 8d eTOTP-SHA1"];
export function CreatePage({ onCreated, onBack }: Props): VNode {
const { i18n } = useTranslationContext();
- const [state, setState] = useState<Partial<Entity>>({});
+ const [state, setState] = useState<Partial<Entity>>({
+ otp_key: "E5V6OSMTZRL2ARYKNDJ4SUDGYOCLQUOT",
+ otp_ctr: 1,
+ otp_device_id: "1",
+ otp_device_description: "asd",
+ otp_algorithm: 0,
+ });
const [notification, safeFunctionHandler] = useLocalNotificationBetter();
const { state: session, lib } = useSessionContext();
@@ -68,7 +74,7 @@ export function CreatePage({ onCreated, onBack }: Props): VNode {
: !/[a-zA-Z0-9]*/.test(state.otp_device_id)
? i18n.str`Invalid. Please enter letters and numbers only.`
: undefined,
- otp_algorithm: !state.otp_algorithm ? i18n.str`Required` : undefined,
+ // otp_algorithm: !state.otp_algorithm ? i18n.str`Required` : undefined,
otp_key: !state.otp_key
? i18n.str`Required`
: !isRfc3548Base32Charset(state.otp_key)
@@ -134,67 +140,63 @@ export function CreatePage({ onCreated, onBack }: Props): VNode {
toStr={(v) => algorithmsNames[v]}
fromStr={(v) => Number(v)}
/>
- {state.otp_algorithm ? (
- <Fragment>
- <InputWithAddon<Entity>
- expand
- name="otp_key"
- label={i18n.str`Device key`}
- inputType={showKey ? "text" : "password"}
- help={i18n.str`Be sure to choose a password that is hard to guess, or use the random generator.`}
- tooltip={i18n.str`Your device needs to match exactly the same value`}
- fromStr={(v) => v.toUpperCase()}
- addonAfterAction={() => {
- setShowKey(!showKey);
+ <InputWithAddon<Entity>
+ expand
+ name="otp_key"
+ label={i18n.str`Device key`}
+ inputType={showKey ? "text" : "password"}
+ help={i18n.str`Be sure to choose a password that is hard to guess, or use the random generator.`}
+ tooltip={i18n.str`Your device needs to match exactly the same value`}
+ fromStr={(v) => v.toUpperCase()}
+ addonAfterAction={() => {
+ setShowKey(!showKey);
+ }}
+ addonAfter={
+ <span class="icon">
+ {showKey ? (
+ <i class="mdi mdi-eye" />
+ ) : (
+ <i class="mdi mdi-eye-off" />
+ )}
+ </span>
+ }
+ side={
+ <button
+ type="button"
+ data-tooltip={i18n.str`Generate random secret key`}
+ class="button is-info mr-3"
+ onClick={(e) => {
+ setState((s) => ({
+ ...s,
+ otp_key: randomRfc3548Base32Key(),
+ }));
+ e.preventDefault();
}}
- addonAfter={
- <span class="icon">
- {showKey ? (
- <i class="mdi mdi-eye" />
- ) : (
- <i class="mdi mdi-eye-off" />
- )}
- </span>
- }
- side={
- <button
- type="button"
- data-tooltip={i18n.str`Generate random secret key`}
- class="button is-info mr-3"
- onClick={(e) => {
- setState((s) => ({
- ...s,
- otp_key: randomRfc3548Base32Key(),
- }));
- e.preventDefault();
- }}
- >
- <i18n.Translate>Random</i18n.Translate>
- </button>
- }
- />
- </Fragment>
- ) : undefined}
- </FormProvider>
-
- <div class="buttons is-right mt-5">
- {onBack && (
- <button class="button" type="button" onClick={onBack}>
- <i18n.Translate>Cancel</i18n.Translate>
- </button>
- )}
- <ButtonBetterBulma
- data-tooltip={
- hasErrors
- ? i18n.str`Please complete the marked fields`
- : i18n.str`Confirm operation`
+ >
+ <i18n.Translate>Random</i18n.Translate>
+ </button>
}
- onClick={create}
- type="submit"
- >
- <i18n.Translate>Confirm</i18n.Translate>
- </ButtonBetterBulma>
- </div>
+ />
+
+ <div class="buttons is-right mt-5">
+ {onBack && (
+ <button class="button" type="button" onClick={onBack}>
+ <i18n.Translate>Cancel</i18n.Translate>
+ </button>
+ )}
+ <ButtonBetterBulma
+ data-tooltip={
+ hasErrors
+ ? i18n.str`Please complete the marked fields`
+ : i18n.str`Confirm operation`
+ }
+ onClick={create}
+ type="submit"
+ >
+ <i18n.Translate>Confirm</i18n.Translate>
+ </ButtonBetterBulma>
+ </div>
+ </FormProvider>
</div>
<div class="column" />
</div>
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx
@@ -39,7 +39,7 @@ export function CreatedSuccessfully({
const qrTextSafe = `otpauth://totp/${state.instance}/${entity.otp_device_id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${entity.otp_key.substring(0, 6)}...`;
return (
- <Template onConfirm={onConfirm} >
+ <Template onConfirm={onConfirm} focus>
<p class="is-size-5">
<i18n.Translate>
You can scan the next QR code with your device or save the key before continuing.