commit 26c58e4212d92f8bb6948b612d62d90c82f2f41f
parent 6ea3ea72762e367ab8b86f13c013f31ad104b1f0
Author: Sebastian <sebasjm@gmail.com>
Date: Mon, 14 Apr 2025 10:16:10 -0300
fix lass addr
Diffstat:
3 files changed, 153 insertions(+), 65 deletions(-)
diff --git a/packages/challenger-ui/src/Routing.tsx b/packages/challenger-ui/src/Routing.tsx
@@ -17,7 +17,8 @@
import {
urlPattern,
useCurrentLocation,
- useNavigationContext
+ useNavigationContext,
+ useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
@@ -72,6 +73,7 @@ export function safeToURL(s: string | undefined): URL | undefined {
function PublicRounting(): VNode {
const loc = useCurrentLocation(publicPages);
+ const { i18n } = useTranslationContext();
const { navigateTo } = useNavigationContext();
useErrorBoundary((e) => {
console.log("error", e);
@@ -127,9 +129,9 @@ function PublicRounting(): VNode {
if (!sessionId) {
return (
<div>
- one of the params is missing{" "}
+ <i18n.Translate>The application needs to be loaded with 4 request parameters. One or more are missing:</i18n.Translate>
{JSON.stringify(
- { clientId, redirectURL, state, nonce },
+ { client_id: clientId, redirect_url: redirectURL?.href, state, nonce },
undefined,
2,
)}
@@ -161,7 +163,7 @@ function PublicRounting(): VNode {
);
}}
>
- No nonce has been found
+ <i18n.Translate>No nonce has been found</i18n.Translate>
</CheckChallengeIsUpToDate>
);
}
@@ -186,8 +188,12 @@ function PublicRounting(): VNode {
if (!sessionId) {
return (
<div>
- one of the params is missing{" "}
- {JSON.stringify(sessionId, undefined, 2)}
+ <i18n.Translate>The application needs to be loaded with 4 request parameters. One or more are missing:</i18n.Translate>
+ {JSON.stringify(
+ { client_id: clientId, redirect_url: redirectURL?.href, state, nonce },
+ undefined,
+ 2,
+ )}
</div>
);
}
@@ -234,15 +240,16 @@ function PublicRounting(): VNode {
if (!sessionId) {
return (
<div>
- one of the params is missing{" "}
+ <i18n.Translate>The application needs to be loaded with 4 request parameters. One or more are missing:</i18n.Translate>
{JSON.stringify(
- { clientId, redirectURL, state, nonce },
+ { client_id: clientId, redirect_url: redirectURL?.href, state, nonce },
undefined,
2,
)}
</div>
);
}
+
return (
<AnswerChallenge
focus
diff --git a/packages/challenger-ui/src/pages/AnswerChallenge.tsx b/packages/challenger-ui/src/pages/AnswerChallenge.tsx
@@ -18,7 +18,8 @@ import {
EmptyObject,
HttpStatusCode,
TalerError,
- assertUnreachable,
+ ChallengerApi,
+ assertUnreachable
} from "@gnu-taler/taler-util";
import {
Attention,
@@ -38,6 +39,7 @@ import {
useChallengeSession,
} from "../hooks/challenge.js";
import { SessionId, useSessionState } from "../hooks/session.js";
+import { TalerFormAttributes } from "@gnu-taler/taler-util";
type Props = {
focus?: boolean;
@@ -64,6 +66,24 @@ function useReloadOnDeadline(deadline: AbsoluteTime): void {
}, [deadline]);
}
+export function getAddressDescriptionFromAddrType(type: ChallengerApi.ChallengerTermsOfServiceResponse["address_type"], addr: Record<string,string>): string {
+ switch (type) {
+ case "email":{
+ return addr[TalerFormAttributes.CONTACT_EMAIL];
+ }
+ case "phone": {
+ return addr[TalerFormAttributes.CONTACT_PHONE];
+ }
+ case "postal": {
+ return addr[TalerFormAttributes.ADDRESS_ZIPCODE];
+ }
+ case "postal-ch": {
+ return addr[TalerFormAttributes.ADDRESS_ZIPCODE];
+
+ }
+ }
+}
+
export function AnswerChallenge({
session,
focus,
@@ -79,8 +99,6 @@ export function AnswerChallenge({
pin: !pin ? i18n.str`Can't be empty` : undefined,
});
- const restrictionKey = config.address_type;
-
const result = useChallengeSession(session);
const lastStatus =
@@ -96,12 +114,12 @@ export function AnswerChallenge({
useReloadOnDeadline(deadline ?? AbsoluteTime.never());
const lastAddr =
- !restrictionKey || !lastStatus?.last_address
+ !lastStatus?.last_address
? undefined
- : lastStatus.last_address[restrictionKey];
+ : getAddressDescriptionFromAddrType(config.address_type, lastStatus.last_address);
const unableToChangeAddr = !lastStatus || lastStatus.changes_left < 1;
- const contact = lastAddr ? { [restrictionKey]: lastAddr } : undefined;
+ const contact = lastStatus?.last_address;
const onSendAgain =
contact === undefined ||
diff --git a/packages/challenger-ui/src/pages/AskChallenge.tsx b/packages/challenger-ui/src/pages/AskChallenge.tsx
@@ -38,15 +38,16 @@ import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { useChallengeSession } from "../hooks/challenge.js";
import { SessionId, useSessionState } from "../hooks/session.js";
-import { doAutoFocus } from "./AnswerChallenge.js";
+import {
+ doAutoFocus,
+ getAddressDescriptionFromAddrType,
+} from "./AnswerChallenge.js";
import { ErrorLoadingWithDebug } from "./ErrorLoadingWithDebug.js";
import { ChallengerApi } from "@gnu-taler/taler-util";
import { TalerFormAttributes } from "@gnu-taler/taler-util";
import { InternationalizationAPI } from "@gnu-taler/taler-util";
import { assertUnreachable } from "@gnu-taler/taler-util";
-export const EMAIL_REGEX = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/;
-
type Props = {
onSendSuccesful: () => void;
session: SessionId;
@@ -137,58 +138,20 @@ export function AskChallenge({
const lastStatus = result.body;
- const restrictionKey = config.address_type;
- const restriction = !config.restrictions
- ? undefined
- : config.restrictions[restrictionKey];
- const regexText =
- restriction && restriction.regex ? restriction.regex : undefined;
- const restrictionHint =
- restriction && restriction.hint
- ? restriction.hint
- : i18n.str`invalid field`;
-
- let restrictionRG;
- if (regexText) {
- try {
- restrictionRG = new RegExp(regexText);
- } catch (e) {
- return (
- <Attention title={i18n.str`Server configuration error`} type="danger">
- <i18n.Translate>
- Invalid server regular expression configuration. Server restriction
- is "{regexText}" but it didn't compile: {String(e)}
- </i18n.Translate>
- </Attention>
- );
- }
- } else {
- restrictionRG = EMAIL_REGEX;
- }
-
- const design = getFormDesignBasedOnAddressType(i18n, config.address_type);
+ const design = getFormDesignBasedOnAddressType(
+ i18n,
+ config.address_type,
+ config.restrictions ?? {},
+ lastStatus.last_address ?? {}
+ );
const form = useForm(design, lastStatus.last_address ?? {});
const prevAddr = !lastStatus?.last_address
? undefined
- : lastStatus.last_address[restrictionKey];
-
- // const errors = undefinedIfEmpty({
- // address: !address
- // ? i18n.str`required`
- // : !restrictionRG.test(address)
- // ? restrictionHint
- // : prevAddr !== undefined && address === prevAddr
- // ? i18n.str`can't use the same address`
- // : undefined,
- // });
-
- // const contact = address ? { [restrictionKey]: address } : undefined;
-
- // const usableAddrs =
- // !state?.lastAddress || !state.lastAddress.length
- // ? []
- // : state.lastAddress.filter((d) => !!d.address[restrictionKey]);
+ : getAddressDescriptionFromAddrType(
+ config.address_type,
+ lastStatus.last_address,
+ );
const contact =
form.status.status === "fail"
@@ -532,10 +495,53 @@ Grunerstraße 1
12345 City_name
country_name `;
+export const EMAIL_REGEX = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/;
+export const PHONE_REGEX = /^(\+\d{1,2}\s?)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/;
+export const CONTACT_REGEX = /.*/
+export const ZIPCODE_REGEX = /.*/
+export const ADDR_LINES_REGEX = /.*/
+
+
function getFormDesignBasedOnAddressType(
i18n: InternationalizationAPI,
type: ChallengerApi.ChallengerTermsOfServiceResponse["address_type"],
+ restrictions: Record<string, ChallengerApi.Restriction | undefined>,
+ prevValue: Record<string, string>,
): FormDesign {
+
+ function getRestriction(
+ serverConfig: ChallengerApi.Restriction | undefined,
+ fallback?: RegExp,
+ ): { regex: undefined | RegExp; hint: TranslatedString } {
+ const regexText =
+ serverConfig && serverConfig.regex ? serverConfig.regex : undefined;
+ const hint =
+ serverConfig && serverConfig.hint
+ ? serverConfig.hint as TranslatedString
+ : i18n.str`Invalid field`;
+
+ let regex;
+ if (regexText) {
+ try {
+ regex = new RegExp(regexText);
+ } catch (e) {
+ console.error(`Invalid server regular expression configuration. Server restriction
+ is "${regexText}" but it didn't compile: ${String(e)}`);
+ // return (
+ // <Attention title={i18n.str`Server configuration error`} type="danger">
+ // <i18n.Translate>
+ // Invalid server regular expression configuration. Server
+ // restriction is "{regexText}" but it didn't compile: {String(e)}
+ // </i18n.Translate>
+ // </Attention>
+ // );
+ }
+ regex = fallback;
+ } else {
+ regex = fallback;
+ }
+ return { regex, hint };
+ }
switch (type) {
case "email":
return {
@@ -546,6 +552,17 @@ function getFormDesignBasedOnAddressType(
id: TalerFormAttributes.CONTACT_EMAIL,
required: true,
label: i18n.str`Email`,
+ validator(text) {
+ const restriction = getRestriction(restrictions[TalerFormAttributes.CONTACT_EMAIL], EMAIL_REGEX)
+ if (!restriction.regex?.test(text)) {
+ return restriction.hint
+ }
+ const prev = prevValue[TalerFormAttributes.CONTACT_EMAIL]
+ if (prev === text) {
+ return i18n.str`Can't use the same address`
+ }
+ return undefined
+ },
},
],
};
@@ -558,6 +575,17 @@ function getFormDesignBasedOnAddressType(
id: TalerFormAttributes.CONTACT_PHONE,
required: true,
label: i18n.str`Phone`,
+ validator(text) {
+ const restriction = getRestriction(restrictions[TalerFormAttributes.CONTACT_PHONE], PHONE_REGEX)
+ if (!restriction.regex?.test(text)) {
+ return restriction.hint
+ }
+ const prev = prevValue[TalerFormAttributes.CONTACT_PHONE]
+ if (prev === text) {
+ return i18n.str`Can't use the same number`
+ }
+ return undefined
+ },
},
],
};
@@ -571,6 +599,13 @@ function getFormDesignBasedOnAddressType(
required: true,
label: i18n.str`Contact name`,
placeholder: i18n.str`Person full name or name of the business`,
+ validator(text) {
+ const restriction = getRestriction(restrictions[TalerFormAttributes.CONTACT_NAME], CONTACT_REGEX)
+ if (!restriction.regex?.test(text)) {
+ return restriction.hint
+ }
+ return undefined
+ },
},
{
type: "textArea",
@@ -578,6 +613,13 @@ function getFormDesignBasedOnAddressType(
required: true,
label: i18n.str`Address`,
placeholder: ADDRESS_EXAMPLE_INTERNATIONAL,
+ validator(text) {
+ const restriction = getRestriction(restrictions[TalerFormAttributes.ADDRESS_LINES], ADDR_LINES_REGEX)
+ if (!restriction.regex?.test(text)) {
+ return restriction.hint
+ }
+ return undefined
+ },
},
{
id: TalerFormAttributes.ADDRESS_COUNTRY,
@@ -586,6 +628,13 @@ function getFormDesignBasedOnAddressType(
choices: countryNameList(i18n),
required: true,
preferredChoiceVals: ["CH", "DE"],
+ validator(text) {
+ const restriction = getRestriction(restrictions[TalerFormAttributes.ADDRESS_COUNTRY])
+ if (!restriction.regex?.test(text)) {
+ return restriction.hint
+ }
+ return undefined
+ },
},
],
};
@@ -600,6 +649,13 @@ function getFormDesignBasedOnAddressType(
required: true,
label: i18n.str`Contact name`,
placeholder: i18n.str`Your full name`,
+ validator(text) {
+ const restriction = getRestriction(restrictions[TalerFormAttributes.CONTACT_PERSON_NAME])
+ if (!restriction.regex?.test(text)) {
+ return restriction.hint
+ }
+ return undefined
+ },
},
{
type: "textArea",
@@ -607,6 +663,13 @@ function getFormDesignBasedOnAddressType(
required: true,
label: i18n.str`Address`,
placeholder: ADDRESS_EXAMPLE_CH,
+ validator(text) {
+ const restriction = getRestriction(restrictions[TalerFormAttributes.ADDRESS_LINES])
+ if (!restriction.regex?.test(text)) {
+ return restriction.hint
+ }
+ return undefined
+ },
},
],
};