commit 23af03a12d51cf9169ee4f16985b258276147ced
parent 069453562e87b82e3f92118abd0e343415c4516a
Author: Sebastian <sebasjm@gmail.com>
Date: Tue, 4 Feb 2025 13:34:26 -0300
external link, void input
Diffstat:
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";