commit 9d6d313afb68bb4e22926a34867148f01001d923
parent 6d9b0817a407b11a9dc1997f3aae1e37848cfa32
Author: Sebastian <sebasjm@taler-systems.com>
Date: Thu, 4 Dec 2025 17:26:22 -0300
fix #9996
Diffstat:
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",