taler-typescript-core

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

commit 9d6d313afb68bb4e22926a34867148f01001d923
parent 6d9b0817a407b11a9dc1997f3aae1e37848cfa32
Author: Sebastian <sebasjm@taler-systems.com>
Date:   Thu,  4 Dec 2025 17:26:22 -0300

fix #9996

Diffstat:
Mpackages/challenger-ui/src/pages/AskChallenge.tsx | 2+-
Mpackages/web-util/src/forms/field-types.ts | 4++++
Mpackages/web-util/src/forms/fields/InputLine.tsx | 2+-
Apackages/web-util/src/forms/fields/InputPhone.tsx | 24++++++++++++++++++++++++
Mpackages/web-util/src/forms/forms-types.ts | 12++++++++++++
Mpackages/web-util/src/forms/forms-utils.ts | 15+++++++++++++++
6 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/packages/challenger-ui/src/pages/AskChallenge.tsx b/packages/challenger-ui/src/pages/AskChallenge.tsx @@ -579,7 +579,7 @@ function getFormDesignBasedOnAddressType( type: "single-column", fields: [ { - type: "text", + type: "phone", id: TalerFormAttributes.CONTACT_PHONE, required: true, label: i18n.str`Phone`, diff --git a/packages/web-util/src/forms/field-types.ts b/packages/web-util/src/forms/field-types.ts @@ -21,6 +21,7 @@ import { InputTextArea } from "./fields/InputTextArea.js"; import { InputToggle } from "./fields/InputToggle.js"; import { Group } from "./Group.js"; import { HtmlIframe } from "./HtmlIframe.js"; +import { InputPhone } from "./fields/InputPhone.js"; /** * Constrain the type with the ui props @@ -43,6 +44,7 @@ type FieldType<T extends object = any, K extends keyof T = any> = { absoluteTimeText: Parameters<typeof InputAbsoluteTime>[0]; isoDateText: Parameters<typeof InputIsoDate>[0]; integer: Parameters<typeof InputInteger>[0]; + phone: Parameters<typeof InputPhone>[0]; secret: Parameters<typeof InputSecret>[0]; toggle: Parameters<typeof InputToggle>[0]; amount: Parameters<typeof InputAmount>[0]; @@ -82,6 +84,7 @@ export type UIFormField = properties: FieldType["drilldown"]; } | { type: "integer"; properties: FieldType["integer"] } + | { type: "phone"; properties: FieldType["phone"] } | { type: "secret"; properties: FieldType["secret"] } | { type: "toggle"; properties: FieldType["toggle"] } | { @@ -133,6 +136,7 @@ export const UIFormConfiguration: UIFormFieldMap = { //@ts-ignore choiceHorizontal: InputChoiceHorizontal, integer: InputInteger, + phone: InputPhone, secret: InputSecret, //@ts-ignore selectOne: InputSelectOne, diff --git a/packages/web-util/src/forms/fields/InputLine.tsx b/packages/web-util/src/forms/fields/InputLine.tsx @@ -165,7 +165,7 @@ function defaultFromString(v: string) { return v; } -type InputType = "text" | "text-area" | "password" | "email" | "number"; +type InputType = "text" | "text-area" | "password" | "email" | "number" | "tel"; export function InputLine( props: { type: InputType; defaultValue?: string } & UIFormProps<string>, diff --git a/packages/web-util/src/forms/fields/InputPhone.tsx b/packages/web-util/src/forms/fields/InputPhone.tsx @@ -0,0 +1,24 @@ +import { VNode, h } from "preact"; +import { InputLine } from "./InputLine.js"; +import { UIFormProps } from "../FormProvider.js"; + +export function InputPhone( + props: UIFormProps<number>, +): VNode { + return ( + <InputLine + type="tel" + converter={{ + //@ts-ignore + fromStringUI: (v): number => { + return !v ? 0 : Number.parseInt(v, 10); + }, + //@ts-ignore + toStringUI: (v?: number): string => { + return v === undefined ? "" : String(v); + }, + }} + {...props} + /> + ); +} diff --git a/packages/web-util/src/forms/forms-types.ts b/packages/web-util/src/forms/forms-types.ts @@ -85,6 +85,7 @@ export type UIFormElementConfig = | UIFormFieldChoiceStacked | UIFormFieldFile | UIFormFieldInteger + | UIFormFieldPhone | UIFormFieldSecret | UIFormFieldSelectMultiple | UIFormFieldDuration @@ -200,6 +201,10 @@ type UIFormFieldInteger = { min?: Integer; } & UIFormFieldBaseConfig; +type UIFormFieldPhone = { + type: "phone"; +} & UIFormFieldBaseConfig; + type UIFormFieldSecret = { type: "secret"; } & UIFormFieldBaseConfig; @@ -472,6 +477,12 @@ const codecForUiFormVoid = (): Codec<UIFormVoid> => .property("type", codecForConstString("void")) .build("UIFormVoid"); + +const codecForUIFormFieldPhone = (): Codec<UIFormFieldPhone> => + codecForUIFormFieldBaseConfigTemplate<UIFormFieldPhone>() + .property("type", codecForConstString("phone")) + .build("UIFormFieldPhone"); + const codecForUiFormFieldInteger = (): Codec<UIFormFieldInteger> => codecForUIFormFieldBaseConfigTemplate<UIFormFieldInteger>() .property("type", codecForConstString("integer")) @@ -547,6 +558,7 @@ const codecForUiFormField = (): Codec<UIFormElementConfig> => .alternative("choiceStacked", codecForUiFormFieldChoiceStacked()) .alternative("file", codecForUiFormFieldFile()) .alternative("integer", codecForUiFormFieldInteger()) + .alternative("phone", codecForUIFormFieldPhone()) .alternative("secret", codecForUiFormFieldSecret()) .alternative("selectMultiple", codecForUiFormFieldSelectMultiple()) .alternative("duration", codecForUiFormFieldDuration()) diff --git a/packages/web-util/src/forms/forms-utils.ts b/packages/web-util/src/forms/forms-utils.ts @@ -257,6 +257,21 @@ export function convertFormConfigToUiField( }, } as UIFormField; } + case "phone": { + return { + type: "phone", + properties: { + ...convertBaseFieldsProps(i18n_, config), + ...convertInputFieldsProps( + name, + handler, + config, + getConverterByFieldType(config.type, config), + ), + hidden, + }, + } as UIFormField; + } case "secret": { return { type: "secret",