taler-typescript-core

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

commit 09369587931379bfb982defa93551ff022b83cc9
parent 65d955e954fd3eccc7a05f1bbc9c48e5d9212932
Author: Florian Dold <florian@dold.me>
Date:   Mon, 21 Jul 2025 13:32:08 +0200

forms: tweaks for GLS forms

Diffstat:
Mpackages/web-util/src/forms/forms-types.ts | 16++++++++--------
Mpackages/web-util/src/forms/gana/gls_merchant_onboarding.ts | 189++++++++++++++++++++++++++++++++++++++++++-------------------------------------
2 files changed, 108 insertions(+), 97 deletions(-)

diff --git a/packages/web-util/src/forms/forms-types.ts b/packages/web-util/src/forms/forms-types.ts @@ -300,22 +300,22 @@ export type UIFieldElementDescription = ComputableFieldConfig & { }; export type UIFormFieldBaseConfig = UIFieldElementDescription & { - /* example to be shown inside the field */ + /** Example to be shown inside the field */ placeholder?: string; - /* conversion id to convert the string into the value type - the id should be known to the ui impl + /** + * Conversion id to convert the string into the value type. + * The id should be known to the ui implementation. */ converterId?: string; - /* - return an error message if the value is not valid. - should returns un undefined if there is no error. - this function is called before conversion + /** + * Return an error message if the value is not valid, + * undefined otherwise. */ validator?: (text: string, form: any) => TranslatedString | undefined; - /* property id of the form */ + /** Property id of the form */ id: UIHandlerId; }; diff --git a/packages/web-util/src/forms/gana/gls_merchant_onboarding.ts b/packages/web-util/src/forms/gana/gls_merchant_onboarding.ts @@ -1,4 +1,4 @@ -import { TalerFormAttributes } from "@gnu-taler/taler-util"; +import { TalerFormAttributes, TranslatedString } from "@gnu-taler/taler-util"; import { intervalToDuration, isFuture, isValid, parse } from "date-fns"; import { DoubleColumnFormDesign, @@ -21,6 +21,76 @@ export const form_gls_merchant_onboarding = ( version: 1, }); +function validateDateOfBirth( + i18n: InternationalizationAPI, + text: string, + _form: any, +): TranslatedString | undefined { + // Date is stored as ISO timestamp + const time = parse(text, "yyyy-MM-dd", new Date()); + if (!isValid(time)) { + return i18n.str`invalid format`; + } + if (isFuture(time)) { + return i18n.str`it can't be in the future`; + } + const { years } = intervalToDuration({ + start: time, + end: new Date(), + }); + if (years && years > 120) { + return i18n.str`it can't be greater than 120 years`; + } + return undefined; +} + +function validateFoundingDate( + i18n: InternationalizationAPI, + text: string, + _form: any, +): TranslatedString | undefined { + // Date is stored as ISO timestamp + const time = parse(text, "yyyy-MM-dd", new Date()); + if (!isValid(time)) { + return i18n.str`invalid format`; + } + if (isFuture(time)) { + return i18n.str`it can't be in the future`; + } + const { years } = intervalToDuration({ + start: time, + end: new Date(), + }); + if (years && years > 120) { + return i18n.str`it can't be greater than 120 years`; + } + return undefined; +} + +function validateEmail( + i18n: InternationalizationAPI, + text: string, + _form: any, +): TranslatedString | undefined { + const re = /^\S+@\S+\.\S+$/; + if (re.test(text)) { + return undefined; + } + return i18n.str`Invalid e-mail address`; +} + +function validatePhone( + i18n: InternationalizationAPI, + text: string, + _form: any, +): TranslatedString | undefined { + const re = /^[+]?([0-9]+[. ]*)+$/; + if (re.test(text)) { + return undefined; + } + return i18n.str`Invalid phone number`; +} + export function gls_merchant_onboarding( i18n: InternationalizationAPI, context?: any, @@ -30,8 +100,8 @@ export function gls_merchant_onboarding( title: "Merchant Onboarding Information", sections: [ { - title: i18n.str`Personal Information`, - description: i18n.str`Personal information of the acting person`, + title: i18n.str`Personal Details`, + description: i18n.str`Personal details of the authorised representative.`, fields: [ { id: TalerFormAttributes.PERSON_FIRST_NAMES, @@ -50,27 +120,10 @@ export function gls_merchant_onboarding( id: TalerFormAttributes.DATE_OF_BIRTH, label: i18n.str`Date of birth`, type: "isoDateText", - placeholder: "dd/MM/yyyy", - pattern: "dd/MM/yyyy", + placeholder: "dd.MM.yyyy", + pattern: "dd.MM.yyyy", required: true, - validator(text, form) { - //FIXME: why returning in this format even if pattern is in another? - const time = parse(text, "yyyy-MM-dd", new Date()); - if (!isValid(time)) { - return i18n.str`invalid format`; - } - if (isFuture(time)) { - return i18n.str`it can't be in the future`; - } - const { years } = intervalToDuration({ - start: time, - end: new Date(), - }); - if (years && years > 120) { - return i18n.str`it can't be greater than 120 years`; - } - return undefined; - }, + validator: (text, form) => validateDateOfBirth(i18n, text, form), }, { id: TalerFormAttributes.NATIONALITY, @@ -84,50 +137,14 @@ export function gls_merchant_onboarding( label: i18n.str`Phone number`, type: "text", required: true, + validator: (text, form) => validatePhone(i18n, text, form), }, { id: TalerFormAttributes.CONTACT_EMAIL, label: i18n.str`E-Mail`, type: "text", required: true, - }, - ], - }, - { - title: i18n.str`Terms of Service`, - fields: [ - { - type: "external-link", - id: TalerFormAttributes.DOWNLOADED_TERMS_OF_SERVICE, - required: true, - url: "https://google.com", - label: i18n.str`Download the term of service`, - media: "text/plain", - }, - { - type: "caption", - label: - "You need to download the terms of service before you can accept them.", - hide(value, root) { - console.log( - `hide caption: ${root["DOWNLOADED_TERMS_OF_SERVICE"] === true}`, - ); - return root["DOWNLOADED_TERMS_OF_SERVICE"] === true; - }, - }, - { - type: "toggle", - id: TalerFormAttributes.ACCEPTED_TERMS_OF_SERVICE, - required: true, - label: i18n.str`Do you accept the terms of service?`, - validator(v) { - return !v - ? i18n.str`Can't continue without accepting term of service.` - : undefined; - }, - hide(value, root) { - return !root["DOWNLOADED_TERMS_OF_SERVICE"]; - }, + validator: (text, form) => validateEmail(i18n, text, form), }, ], }, @@ -172,27 +189,10 @@ export function gls_merchant_onboarding( id: TalerFormAttributes.FOUNDING_DATE, label: i18n.str`Founding date`, type: "isoDateText", - placeholder: "dd/MM/yyyy", - pattern: "dd/MM/yyyy", + placeholder: "dd.MM.yyyy", + pattern: "dd.MM.yyyy", required: true, - validator(text, form) { - //FIXME: why returning in this format even if pattern is in another? - const time = parse(text, "yyyy-MM-dd", new Date()); - if (!isValid(time)) { - return i18n.str`invalid format`; - } - if (isFuture(time)) { - return i18n.str`it can't be in the future`; - } - const { years } = intervalToDuration({ - start: time, - end: new Date(), - }); - if (years && years > 120) { - return i18n.str`it can't be greater than 120 years`; - } - return undefined; - }, + validator: (text, form) => validateFoundingDate(i18n, text, form), }, { id: TalerFormAttributes.BUSINESS_IS_NON_PROFIT, @@ -217,12 +217,6 @@ export function gls_merchant_onboarding( type: "drilldown", choices: drilldownGlsIndustries, }, - // { - // id: TalerFormAttributes.BUSINESS_INDUSTRY_OTHER, - // label: i18n.str`Industry (free-form entry for other)`, - // type: "text", - // required: true, - // }, ], }, { @@ -328,9 +322,11 @@ export function gls_merchant_onboarding( id: TalerFormAttributes.DATE_OF_BIRTH, label: i18n.str`Date of birth`, type: "isoDateText", - placeholder: "dd/MM/yyyy", - pattern: "dd/MM/yyyy", + placeholder: "dd.MM.yyyy", + pattern: "dd.MM.yyyy", required: true, + validator: (text, form) => + validateDateOfBirth(i18n, text, form), }, { id: TalerFormAttributes.NATIONALITY, @@ -363,6 +359,21 @@ export function gls_merchant_onboarding( }, ], }, + { + title: i18n.str`New Customer Identification`, + fields: [ + { + type: "caption", + label: "Please complete the customer registration and identification for the authorized representative and other persons listed in this form.", + }, + { + type: "external-link", + url: "https://kontoeroeffnung.gls.de/kundenanlage/gks-v", + id: "none", + label: "GLS Customer Registration", + } + ], + }, ], }; }