commit 64e124ee48ccfd694d6a3ffb885be1692c9ea9a1
parent 0aee1fcbf037c2c9c202e11a05a99eba00dd0e54
Author: Sebastian <sebasjm@gmail.com>
Date: Wed, 29 Oct 2025 16:40:11 -0300
pwd and kyc
Diffstat:
3 files changed, 76 insertions(+), 56 deletions(-)
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx
@@ -21,6 +21,7 @@
import {
HttpStatusCode,
+ Paytos,
TalerError,
TalerMerchantApi,
assertUnreachable,
@@ -124,10 +125,37 @@ function ShowInstructionForKycRedirect({
const { i18n } = useTranslationContext();
switch (e.status) {
case TalerMerchantApi.MerchantAccountKycStatus.KYC_WIRE_REQUIRED:
+ const uri = Paytos.fromString(e.payto_uri);
+ if (uri.type === "fail") {
+ return (
+ <ConfirmModal
+ label={i18n.str`Ok`}
+ description={i18n.str`Wire account is invalid`}
+ active
+ onCancel={onCancel}
+ >
+ <p style={{ paddingTop: 0 }}>
+ <i18n.Translate>
+ The backend service responded with "{e.payto_uri}" which is invalid.
+ </i18n.Translate>
+ </p>
+ </ConfirmModal>
+ );
+ }
+ const tgs = (e.payto_kycauths ?? [])
+ .map((d) => Paytos.fromString(d))
+ .filter((d) => {
+ if (d.type !== "ok") {
+ // FIXME: maybe this need to be shown to the user more promptly
+ console.error("server replied with a wrong payto://", d)
+ }
+ return d.type === "ok"
+ })
+ .map((d) => d.body);
return (
<ValidBankAccount
- origin={parsePaytoUri(e.payto_uri)!}
- targets={(e.payto_kycauths ?? []).map((d) => parsePaytoUri(d)!)}
+ origin={uri.body}
+ targets={tgs}
onCancel={onCancel}
/>
);
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/password/DetailPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/password/DetailPage.tsx
@@ -19,24 +19,31 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { ButtonBetterBulma, useTranslationContext } from "@gnu-taler/web-util/browser";
+import {
+ ButtonBetterBulma,
+ LocalNotificationBannerBulma,
+ SafeHandlerTemplate,
+ useChallengeHandler,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { FormProvider } from "../../../components/form/FormProvider.js";
import { Input } from "../../../components/form/Input.js";
import { undefinedIfEmpty } from "../../../utils/table.js";
+import { SolveMFAChallenges } from "../../../components/SolveMFA.js";
+import { HttpStatusCode } from "@gnu-taler/taler-util";
interface Props {
instanceId: string;
- onNewPassword: (s: string) => void;
- // onNewPassword: (c: string | undefined, s: string) => void;
onBack?: () => void;
+ changePassword: SafeHandlerTemplate<[pass:string], any>;
}
export function DetailPage({
instanceId,
onBack,
- onNewPassword,
+ changePassword,
}: Props): VNode {
type State = {
// old_token: string;
@@ -48,6 +55,7 @@ export function DetailPage({
new_token: "",
repeat_token: "",
});
+
const { i18n } = useTranslationContext();
const errors = undefinedIfEmpty({
@@ -57,9 +65,9 @@ export function DetailPage({
// : undefined,
new_token: !form.new_token
? i18n.str`Required`
- // : form.new_token === form.old_token
- // ? i18n.str`Can't be the same as the old password`
- : undefined,
+ : // : form.new_token === form.old_token
+ // ? i18n.str`Can't be the same as the old password`
+ undefined,
repeat_token:
form.new_token !== form.repeat_token
? i18n.str`Is not the same`
@@ -123,13 +131,12 @@ export function DetailPage({
)}
<ButtonBetterBulma
type="submit"
- disabled={hasErrors}
data-tooltip={
hasErrors
? i18n.str`Please complete the marked fields`
: i18n.str`Confirm operation`
}
- onClick={submitForm}
+ onClick={changePassword}
>
<i18n.Translate>Confirm change</i18n.Translate>
</ButtonBetterBulma>
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/password/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/password/index.tsx
@@ -18,7 +18,7 @@ import {
HttpStatusCode,
MerchantAuthMethod,
TalerError,
- assertUnreachable
+ assertUnreachable,
} from "@gnu-taler/taler-util";
import {
LocalNotificationBannerBulma,
@@ -35,9 +35,7 @@ import {
useInstanceDetails,
useManagedInstanceDetails,
} from "../../../hooks/instance.js";
-import {
- LoginPage
-} from "../../login/index.js";
+import { LoginPage } from "../../login/index.js";
import { NotFoundPageOrAdminCreate } from "../../notfound/index.js";
import { DetailPage } from "./DetailPage.js";
@@ -56,11 +54,24 @@ export default function PasswordPage({ onCancel, onChange }: Props): VNode {
if (result instanceof TalerError) {
return <ErrorLoadingMerchant error={result} />;
}
+ if (result.type === "fail") {
+ switch (result.case) {
+ case HttpStatusCode.Unauthorized: {
+ return <LoginPage />;
+ }
+ case HttpStatusCode.NotFound: {
+ return <NotFoundPageOrAdminCreate />;
+ }
+ default: {
+ assertUnreachable(result);
+ }
+ }
+ }
const { i18n } = useTranslationContext();
const mfa = useChallengeHandler();
const changePassword = safeFunctionHandler(
- (token: AccessToken, id: string, pwd: string, challengeIds: string[]) =>
+ (token: AccessToken, pwd: string, challengeIds: string[]) =>
lib.instance.updateCurrentInstanceAuthentication(
token,
{
@@ -69,6 +80,7 @@ export default function PasswordPage({ onCancel, onChange }: Props): VNode {
},
{ challengeIds },
),
+ !session.token ? undefined : [session.token, "", []],
);
changePassword.onSuccess = (suc) => {
onChange();
@@ -88,8 +100,7 @@ export default function PasswordPage({ onCancel, onChange }: Props): VNode {
const retry = changePassword.lambda((ids: string[]) => [
changePassword.args![0],
- changePassword.args![2],
- changePassword.args![2],
+ changePassword.args![1],
ids,
]);
if (mfa.pendingChallenge) {
@@ -101,38 +112,18 @@ export default function PasswordPage({ onCancel, onChange }: Props): VNode {
/>
);
}
- if (result.type === "fail") {
- switch (result.case) {
- case HttpStatusCode.Unauthorized: {
- return <LoginPage />;
- }
- case HttpStatusCode.NotFound: {
- return <NotFoundPageOrAdminCreate />;
- }
- default: {
- assertUnreachable(result);
- }
- }
- }
- //
+
return (
<Fragment>
<LocalNotificationBannerBulma notification={notification} />
<DetailPage
onBack={onCancel}
instanceId={result.body.name}
- onNewPassword={async (newPassword): Promise<void> => {
- return (
- !session.token
- ? changePassword
- : changePassword.withArgs(
- session.token,
- instanceId,
- newPassword,
- [],
- )
- ).call();
- }}
+ changePassword={changePassword.lambda((pass: string) => [
+ changePassword.args![0],
+ pass,
+ changePassword.args![2],
+ ])}
/>
</Fragment>
);
@@ -218,18 +209,12 @@ export function AdminPassword({
<DetailPage
onBack={onCancel}
instanceId={result.body.name}
- onNewPassword={async (newPassword): Promise<void> => {
- return (
- !session.token
- ? changePassword
- : changePassword.withArgs(
- session.token,
- instanceId,
- newPassword,
- [],
- )
- ).call();
- }}
+ changePassword={changePassword.lambda((pass: string) => [
+ changePassword.args![0],
+ changePassword.args![1],
+ pass,
+ changePassword.args![3],
+ ])}
/>
</Fragment>
);