taler-typescript-core

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

commit 23af03a12d51cf9169ee4f16985b258276147ced
parent 069453562e87b82e3f92118abd0e343415c4516a
Author: Sebastian <sebasjm@gmail.com>
Date:   Tue,  4 Feb 2025 13:34:26 -0300

external link, void input

Diffstat:
Apackages/web-util/src/forms/ExternalLink.tsx | 39+++++++++++++++++++++++++++++++++++++++
Mpackages/web-util/src/forms/field-types.ts | 4++++
Mpackages/web-util/src/forms/forms-types.ts | 30+++++++++++++++++++++++++++++-
Mpackages/web-util/src/forms/forms-utils.ts | 16+++++++++++++++-
Apackages/web-util/src/forms/gana/GLS_Onboarding.stories.tsx | 44++++++++++++++++++++++++++++++++++++++++++++
Mpackages/web-util/src/forms/gana/GLS_Onboarding.ts | 71++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mpackages/web-util/src/forms/gana/taler_form_attributes.ts | 7++++---
Mpackages/web-util/src/forms/index.stories.ts | 1+
8 files changed, 180 insertions(+), 32 deletions(-)

diff --git a/packages/web-util/src/forms/ExternalLink.tsx b/packages/web-util/src/forms/ExternalLink.tsx @@ -0,0 +1,39 @@ +import { TranslatedString } from "@gnu-taler/taler-util"; +import { VNode, h } from "preact"; +import { RenderAddon } from "./fields/InputLine.js"; +import { Addon } from "./FormProvider.js"; + +interface Props { + label: TranslatedString; + url: string; + media?: string; + tooltip?: TranslatedString; + help?: TranslatedString; + before?: Addon; + after?: Addon; +} + +export function ExternalLink({ + before, + after, + label, + url, + media, + tooltip, + help, +}: Props): VNode { + return ( + <div class="sm:col-span-6"> + {before !== undefined && <RenderAddon addon={before} />} + <a href={url} class="underline" target="_blank" rel="noreferrer"> + {label} + </a> + {after !== undefined && <RenderAddon addon={after} />} + {help && ( + <p class="mt-2 text-sm text-gray-500" id="email-description"> + {help} + </p> + )} + </div> + ); +} diff --git a/packages/web-util/src/forms/field-types.ts b/packages/web-util/src/forms/field-types.ts @@ -18,6 +18,7 @@ import { InputToggle } from "./fields/InputToggle.js"; import { Group } from "./Group.js"; import { HtmlIframe } from "./HtmlIframe.js"; import { InputDurationText } from "./fields/InputDurationText.js"; +import { ExternalLink } from "./ExternalLink.js"; /** * Constrain the type with the ui props */ @@ -25,6 +26,7 @@ type FieldType<T extends object = any, K extends keyof T = any> = { group: Parameters<typeof Group>[0]; caption: Parameters<typeof Caption>[0]; "download-link": Parameters<typeof DownloadLink>[0]; + "external-link": Parameters<typeof ExternalLink>[0]; htmlIframe: Parameters<typeof HtmlIframe>[0]; array: Parameters<typeof InputArray<T, K>>[0]; file: Parameters<typeof InputFile<T, K>>[0]; @@ -50,6 +52,7 @@ export type UIFormField = | { type: "group"; properties: FieldType["group"] } | { type: "caption"; properties: FieldType["caption"] } | { type: "download-link"; properties: FieldType["download-link"] } + | { type: "external-link"; properties: FieldType["external-link"] } | { type: "htmlIframe"; properties: FieldType["htmlIframe"] } | { type: "array"; properties: FieldType["array"] } | { type: "file"; properties: FieldType["file"] } @@ -99,6 +102,7 @@ type UIFormFieldMap = { export const UIFormConfiguration: UIFormFieldMap = { group: Group, "download-link": DownloadLink, + "external-link": ExternalLink, caption: Caption, htmlIframe: HtmlIframe, //@ts-ignore diff --git a/packages/web-util/src/forms/forms-types.ts b/packages/web-util/src/forms/forms-types.ts @@ -48,6 +48,7 @@ export type UIFormElementConfig = | UIFormElementGroup | UIFormElementCaption | UIFormElementDownloadLink + | UIFormElementExternalLink | UIFormElementHtmlIframe | UIFormFieldAbsoluteTime | UIFormFieldAmount @@ -63,7 +64,12 @@ export type UIFormElementConfig = | UIFormFieldSelectOne | UIFormFieldText | UIFormFieldTextArea - | UIFormFieldToggle; + | UIFormFieldToggle + | UIFormVoid; + +type UIFormVoid = { + type: "void"; +}; type UIFormFieldAbsoluteTime = { type: "absoluteTimeText"; @@ -92,6 +98,11 @@ type UIFormElementDownloadLink = { url: string; media?: string; } & UIFieldElementDescription; +type UIFormElementExternalLink = { + type: "external-link"; + url: string; + media?: string; +} & UIFieldElementDescription; type UIFormElementHtmlIframe = { type: "htmlIframe"; url: string; @@ -276,6 +287,14 @@ const codecForUIFormElementLink = (): Codec<UIFormElementDownloadLink> => .property("media", codecOptional(codecForString())) .build("UIFormElementLink"); +const codecForUIFormElementExternalLink = + (): Codec<UIFormElementExternalLink> => + codecForUIFormFieldBaseDescriptionTemplate<UIFormElementExternalLink>() + .property("type", codecForConstString("external-link")) + .property("url", codecForString()) + .property("media", codecOptional(codecForString())) + .build("UIFormElementExternalLink"); + const codecForUiFormFieldHtmlIFrame = (): Codec<UIFormElementHtmlIframe> => codecForUIFormFieldBaseDescriptionTemplate<UIFormElementHtmlIframe>() .property("type", codecForConstString("htmlIframe")) @@ -319,6 +338,13 @@ const codecForUiFormFieldGroup = (): Codec<UIFormElementGroup> => .property("fields", codecForList(codecForUiFormField())) .build("UiFormFieldGroup"); +const codecForUiFormVoid = (): Codec<UIFormVoid> => + buildCodecForObject<UIFormVoid>() + .property("type", codecForConstString("void")) + // eslint-disable-next-line @typescript-eslint/no-use-before-define + // .property("fields", codecForList(codecForUiFormField())) + .build("UIFormVoid"); + const codecForUiFormFieldInteger = (): Codec<UIFormFieldInteger> => codecForUIFormFieldBaseConfigTemplate<UIFormFieldInteger>() .property("type", codecForConstString("integer")) @@ -381,7 +407,9 @@ const codecForUiFormField = (): Codec<UIFormElementConfig> => .discriminateOn("type") .alternative("array", codecForLazy(codecForUiFormFieldArray)) .alternative("group", codecForLazy(codecForUiFormFieldGroup)) + .alternative("void", codecForUiFormVoid()) .alternative("download-link", codecForUIFormElementLink()) + .alternative("external-link", codecForUIFormElementExternalLink()) .alternative("absoluteTimeText", codecForUiFormFieldAbsoluteTime()) .alternative("amount", codecForUiFormFieldAmount()) .alternative("caption", codecForUiFormFieldCaption()) diff --git a/packages/web-util/src/forms/forms-utils.ts b/packages/web-util/src/forms/forms-utils.ts @@ -28,7 +28,8 @@ export function convertFormConfigToUiField( fieldConfig: UIFormElementConfig[], form: object, ): UIFormField[] { - return fieldConfig.map((config) => { + const result = fieldConfig.map((config) => { + if (config.type === "void") return undefined; // NON input fields switch (config.type) { case "caption": { @@ -50,6 +51,18 @@ export function convertFormConfigToUiField( }; return resp; } + case "external-link": { + const resp: UIFormField = { + type: config.type, + properties: { + ...converBaseFieldsProps(i18n_, config), + label: i18n_.str`${config.label}`, + url: config.url, + media: config.media, + }, + }; + return resp; + } case "htmlIframe": { const resp: UIFormField = { type: config.type, @@ -290,6 +303,7 @@ export function convertFormConfigToUiField( } } }); + return result.filter((v): v is UIFormField => !!v); } function getAddonById(_id: string | undefined): Addon { diff --git a/packages/web-util/src/forms/gana/GLS_Onboarding.stories.tsx b/packages/web-util/src/forms/gana/GLS_Onboarding.stories.tsx @@ -0,0 +1,44 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { i18n, setupI18n } from "@gnu-taler/taler-util"; +import * as tests from "../../tests/hook.js"; +import { DefaultForm as TestedComponent } from "../forms-ui.js"; +import { GLS_Onboarding } from "./GLS_Onboarding.js"; + +export default { + title: "GLS_Onboarding", +}; + +export namespace Simplest { + export interface Form { + comment: string; + } +} + +setupI18n("es", {}); +type TargetObject = {}; +const initial: TargetObject = {}; + +export const SimpleUsage = tests.createExample(TestedComponent, { + initial, + design: GLS_Onboarding(i18n), +}); diff --git a/packages/web-util/src/forms/gana/GLS_Onboarding.ts b/packages/web-util/src/forms/gana/GLS_Onboarding.ts @@ -8,6 +8,7 @@ import { TalerFormAttributes } from "./taler_form_attributes.js"; export function GLS_Onboarding( i18n: InternationalizationAPI, + context?: any, ): DoubleColumnFormDesign { return { type: "double-column", @@ -34,7 +35,7 @@ export function GLS_Onboarding( { id: "PERSON_DATE_OF_BIRTH" satisfies keyof TalerFormAttributes.GLS_Onboarding as UIHandlerId, label: i18n.str`Date of birth`, - // gana_type: "AbsoluteDate", + // gana_type: "ISO8601Date", type: "absoluteTimeText", placeholder: "dd/MM/yyyy", pattern: "dd/MM/yyyy", @@ -48,6 +49,22 @@ export function GLS_Onboarding( choices: countryList(i18n), required: true, }, + { + type: "toggle", + id: "ACCEPTED_TERMS_OF_SERVICE" as UIHandlerId, + required: true, + threeState: true, + label: i18n.str`Do you accept the terms of service?`, + }, + // !context || !context.tos_url + // ? { type: "void" } + // : + { + type: "external-link", + url: "https://google.com", + label: i18n.str`Read the term of service here`, + media: "text/plain", + }, ], }, { @@ -84,7 +101,7 @@ export function GLS_Onboarding( { id: "BUSINESS_REGISTRATION_DATE" satisfies keyof TalerFormAttributes.GLS_Onboarding as UIHandlerId, label: i18n.str`Registration date`, - // gana_type: "AbsoluteDate", + // gana_type: "ISO8601Date", type: "absoluteTimeText", placeholder: "dd/MM/yyyy", pattern: "dd/MM/yyyy", @@ -109,7 +126,7 @@ export function GLS_Onboarding( label: i18n.str`Legal representatives`, // gana_type: "GLS_BusinessRepresentative[]", type: "array", - labelFieldId: "asd" as UIHandlerId, + labelFieldId: "GLS_REPRESENTATIVE_FULL_NAME" as UIHandlerId, fields: [ { id: "GLS_REPRESENTATIVE_FULL_NAME" satisfies keyof TalerFormAttributes.GLS_BusinessRepresentative as UIHandlerId, @@ -128,7 +145,7 @@ export function GLS_Onboarding( { id: "GLS_REPRESENTATIVE_DATE_OF_BIRTH" satisfies keyof TalerFormAttributes.GLS_BusinessRepresentative as UIHandlerId, label: i18n.str`Date of birth`, - // gana_type: "AbsoluteDate", + // gana_type: "ISO8601Date", type: "absoluteTimeText", placeholder: "dd/MM/yyyy", pattern: "dd/MM/yyyy", @@ -141,20 +158,20 @@ export function GLS_Onboarding( type: "text", required: true, }, - { - id: "GLS_REPRESENTATIVE_NATIONAL_ID" satisfies keyof TalerFormAttributes.GLS_BusinessRepresentative as UIHandlerId, - label: i18n.str`National ID number`, - // gana_type: "String", - type: "text", - required: true, - }, - { - id: "GLS_REPRESENTATIVE_NATIONAL_ID_SCAN" satisfies keyof TalerFormAttributes.GLS_BusinessRepresentative as UIHandlerId, - label: i18n.str`National ID photo`, - // gana_type: "File", - type: "file", - required: true, - }, + // { + // id: "GLS_REPRESENTATIVE_NATIONAL_ID" satisfies keyof TalerFormAttributes.GLS_BusinessRepresentative as UIHandlerId, + // label: i18n.str`National ID number`, + // // gana_type: "String", + // type: "text", + // required: true, + // }, + // { + // id: "GLS_REPRESENTATIVE_NATIONAL_ID_SCAN" satisfies keyof TalerFormAttributes.GLS_BusinessRepresentative as UIHandlerId, + // label: i18n.str`National ID photo`, + // // gana_type: "File", + // type: "file", + // required: true, + // }, ], required: true, }, @@ -202,7 +219,7 @@ export function GLS_Onboarding( label: i18n.str`Country subdivision`, // gana_type: "Hostname", type: "text", - required: true, + // required: true, }, { id: "ADDRESS_STREET_NAME" satisfies keyof TalerFormAttributes.GLS_Onboarding as UIHandlerId, @@ -223,21 +240,21 @@ export function GLS_Onboarding( label: i18n.str`Street lines`, // gana_type: "String", type: "textArea", - required: true, + // required: true, }, { id: "ADDRESS_BUILDING_NAME" satisfies keyof TalerFormAttributes.GLS_Onboarding as UIHandlerId, label: i18n.str`Building name`, // gana_type: "String", type: "text", - required: true, + // required: true, }, { id: "ADDRESS_BUILDING_NUMBER" satisfies keyof TalerFormAttributes.GLS_Onboarding as UIHandlerId, label: i18n.str`Building number`, // gana_type: "String", type: "text", - required: true, + // required: true, }, { id: "ADDRESS_ZIPCODE" satisfies keyof TalerFormAttributes.GLS_Onboarding as UIHandlerId, @@ -251,14 +268,14 @@ export function GLS_Onboarding( label: i18n.str`Town location`, // gana_type: "Hostname", type: "text", - required: true, + // required: true, }, { id: "ADDRESS_TOWN_DISTRICT" satisfies keyof TalerFormAttributes.GLS_Onboarding as UIHandlerId, label: i18n.str`Town district`, // gana_type: "Hostname", type: "text", - required: true, + // required: true, }, ], }, @@ -283,7 +300,7 @@ export function GLS_Onboarding( { id: "TAX_IS_USA_LAW" satisfies keyof TalerFormAttributes.GLS_Onboarding as UIHandlerId, label: i18n.str`under USA law?`, - help: i18n.str`wurde die gesellschaft in den USA oder nach US-Recht gergrudent`, + // help: i18n.str`wurde die gesellschaft in den USA oder nach US-Recht gergrudent`, // gana_type: "Boolean", type: "toggle", required: true, @@ -291,7 +308,7 @@ export function GLS_Onboarding( { id: "TAX_IS_ACTIVE" satisfies keyof TalerFormAttributes.GLS_Onboarding as UIHandlerId, label: i18n.str`is economically active?`, - help: i18n.str`wirtschaftlich aktiv oder passiv`, + // help: i18n.str`wirtschaftlich aktiv oder passiv`, // gana_type: "Boolean", type: "toggle", required: true, @@ -299,7 +316,7 @@ export function GLS_Onboarding( { id: "TAX_IS_DEDUCTED" satisfies keyof TalerFormAttributes.GLS_Onboarding as UIHandlerId, label: i18n.str`entitled to deduct tax?`, - help: i18n.str`sind sie vorsteuerabzugsberechtigt`, + // help: i18n.str`sind sie vorsteuerabzugsberechtigt`, // gana_type: "Boolean", type: "toggle", required: true, diff --git a/packages/web-util/src/forms/gana/taler_form_attributes.ts b/packages/web-util/src/forms/gana/taler_form_attributes.ts @@ -23,6 +23,7 @@ type AbsoluteDateTime = string; type AbsoluteDate = string; +type ISO8601Date = string; type CountryCode = string; type Amount = string; type ResidentialAddress = string; @@ -1239,7 +1240,7 @@ export namespace TalerFormAttributes { * Registration founding date of the company or business. * Required: false */ - BUSINESS_REGISTRATION_DATE?: AbsoluteDate; + BUSINESS_REGISTRATION_DATE?: ISO8601Date; /** * Registration id on legal entity of the company or business. * Required: false @@ -1274,7 +1275,7 @@ export namespace TalerFormAttributes { * Date of birth of an individual. Format is YYYY-MM-DD. * Required: false */ - PERSON_DATE_OF_BIRTH?: AbsoluteDate; + PERSON_DATE_OF_BIRTH?: ISO8601Date; /** * Full legal name of an individual as in the national identity card. * Required: false @@ -1331,7 +1332,7 @@ export namespace TalerFormAttributes { * * Required: false */ - GLS_REPRESENTATIVE_DATE_OF_BIRTH?: AbsoluteDate; + GLS_REPRESENTATIVE_DATE_OF_BIRTH?: ISO8601Date; /** * * Required: false diff --git a/packages/web-util/src/forms/index.stories.ts b/packages/web-util/src/forms/index.stories.ts @@ -13,3 +13,4 @@ export * as a13 from "./fields/InputToggle.stories.js"; export * as a14 from "./fields/InputSecret.stories.js"; export * as a15 from "./fields/InputDuration.stories.js"; export * as a16 from "./fields/InputDurationText.stories.js"; +export * as a17 from "./gana/GLS_Onboarding.stories.js";