taler-typescript-core

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

commit f5be09f5b4ab66581281aa6327264e67a7b73106
parent 7a04a81ed53cbfa32d46cc6545c45b63cd1346db
Author: Sebastian <sebasjm@gmail.com>
Date:   Fri, 13 Dec 2024 14:08:13 -0300

required when is undefined, undefined toggle

Diffstat:
Mpackages/kyc-ui/src/forms/accept-tos.ts | 13++-----------
Mpackages/kyc-ui/src/hooks/form.ts | 2+-
Mpackages/kyc-ui/src/pages/FillForm.tsx | 18+++++++++++++-----
Mpackages/web-util/src/forms/InputToggle.stories.tsx | 1+
Mpackages/web-util/src/forms/InputToggle.tsx | 21++++++++++++---------
Mpackages/web-util/src/forms/forms.ts | 1+
Mpackages/web-util/src/forms/ui-form.ts | 7++++++-
Mpackages/web-util/src/hooks/useForm.ts | 2+-
8 files changed, 37 insertions(+), 28 deletions(-)

diff --git a/packages/kyc-ui/src/forms/accept-tos.ts b/packages/kyc-ui/src/forms/accept-tos.ts @@ -36,20 +36,11 @@ export const acceptTos = (i18n: InternationalizationAPI, context?: any): DoubleC url: context.tos_url } : undefined, { - type: "choiceHorizontal", + type: "toggle", id: "ACCEPTED_TERMS_OF_SERVICE" as UIHandlerId, required: true, + threeState: true, label: i18n.str`Do you accept terms of service`, - choices: [ - { - label: i18n.str`Yes`, - value: "yes", - }, - { - label: i18n.str`No`, - value: "no", - }, - ], }, ]), }, diff --git a/packages/kyc-ui/src/hooks/form.ts b/packages/kyc-ui/src/hooks/form.ts @@ -221,7 +221,7 @@ export function validateRequiredFields<FormType>( fields.forEach((f) => { const path = f.split("."); const v = getValueDeeper(form as any, path); - result = setValueDeeper(result, path, !v ? "required" : undefined); + result = setValueDeeper(result, path, v === undefined ? "required" : undefined); }); return result; } diff --git a/packages/kyc-ui/src/pages/FillForm.tsx b/packages/kyc-ui/src/pages/FillForm.tsx @@ -16,6 +16,7 @@ import { AbsoluteTime, AccessToken, + AmountJson, Amounts, HttpStatusCode, KycRequirementInformation, @@ -153,12 +154,12 @@ export function FillForm({ // data.set("header", JSON.stringify(information.header)) // data.set("payload", JSON.stringify(information.payload)) const data = new URLSearchParams(); - Object.entries(validatedForm as Record<string, string>).forEach( + Object.entries(validatedForm as Record<string, unknown>).forEach( ([key, value]) => { if (key === "money") { - data.set(key, Amounts.stringify(value)); + data.set(key, Amounts.stringify(value as AmountJson)); } else { - data.set(key, value); + data.set(key, String(value)); } }, ); @@ -223,7 +224,14 @@ export function FillForm({ </div> {preferences.showDebugInfo ? ( - <pre>{JSON.stringify(state.result, undefined, 2)}</pre> + <div class="m-4"> + <p class="text-sm font-semibold leading-6 text-gray-900"> + <i18n.Translate> + Debug information about the values in the form + </i18n.Translate> + </p> + <pre>{JSON.stringify(state.result, undefined, 2)}</pre> + </div> ) : ( <Fragment /> )} @@ -237,7 +245,7 @@ export function FillForm({ <Button type="submit" handler={submitHandler} - // disabled={!submitHandler} + disabled={!submitHandler} class="disabled:opacity-50 disabled:cursor-default rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" > <i18n.Translate>Confirm</i18n.Translate> diff --git a/packages/web-util/src/forms/InputToggle.stories.tsx b/packages/web-util/src/forms/InputToggle.stories.tsx @@ -52,6 +52,7 @@ const form: FlexibleForm_Deprecated<TargetObject> = { { type: "toggle", label: "label of the field" as TranslatedString, + threeState: false, id: "comment" as UIHandlerId, }, ], diff --git a/packages/web-util/src/forms/InputToggle.tsx b/packages/web-util/src/forms/InputToggle.tsx @@ -5,7 +5,7 @@ import { LabelWithTooltipMaybeRequired } from "./InputLine.js"; import { useField } from "./useField.js"; export function InputToggle<T extends object, K extends keyof T>( - props: UIFormProps<T, K>, + props: { threeState: boolean } & UIFormProps<T, K>, ): VNode { const { name, @@ -17,6 +17,7 @@ export function InputToggle<T extends object, K extends keyof T>( before, after, converter, + threeState, } = props; //FIXME: remove deprecated const fieldCtx = useField<T, K>(props.name); @@ -34,21 +35,23 @@ export function InputToggle<T extends object, K extends keyof T>( /> <button type="button" - data-enabled={isOn} - class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" + data-state={isOn ? "on" : value === undefined ? "undefined" : "off"} + class="bg-indigo-600 data-[state=off]:bg-gray-200 data-[state=undefined]:bg-gray-200 relative inline-flex h-6 w-12 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" - aria-checked="false" aria-labelledby="availability-label" aria-describedby="availability-description" onClick={() => { - onChange(!isOn as any); + if (value === false && threeState) { + return onChange(undefined as any); + } else { + return onChange(!isOn as any); + } }} > <span - aria-hidden="true" - data-enabled={isOn} - class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out" - ></span> + data-state={isOn ? "on" : value === undefined ? "undefined" : "off"} + class="translate-x-6 data-[state=off]:translate-x-0 data-[state=undefined]:translate-x-3 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out" + ></span> </button> </div> </div> diff --git a/packages/web-util/src/forms/forms.ts b/packages/web-util/src/forms/forms.ts @@ -325,6 +325,7 @@ export function convertUiField( properties: { ...converBaseFieldsProps(i18n_, config), ...converInputFieldsProps(form, config, getConverterById), + threeState: config.threeState, }, } as UIFormField; } diff --git a/packages/web-util/src/forms/ui-form.ts b/packages/web-util/src/forms/ui-form.ts @@ -12,6 +12,7 @@ import { codecForStringURL, codecForTimestamp, codecOptional, + codecOptionalDefault, Integer, TalerProtocolTimestamp, TranslatedString, @@ -131,7 +132,10 @@ type UIFormFieldSelectOne = { } & UIFormFieldBaseConfig; type UIFormFieldText = { type: "text" } & UIFormFieldBaseConfig; type UIFormFieldTextArea = { type: "textArea" } & UIFormFieldBaseConfig; -type UIFormFieldToggle = { type: "toggle" } & UIFormFieldBaseConfig; +type UIFormFieldToggle = { + type: "toggle"; + threeState: boolean; +} & UIFormFieldBaseConfig; export type UIFieldElementDescription = { /* label if the field, visible for the user */ @@ -311,6 +315,7 @@ const codecForUiFormFieldTextArea = (): Codec<UIFormFieldTextArea> => const codecForUiFormFieldToggle = (): Codec<UIFormFieldToggle> => codecForUIFormFieldBaseConfigTemplate<UIFormFieldToggle>() + .property("threeState", codecOptionalDefault(codecForBoolean(), false)) .property("type", codecForConstString("toggle")) .build("UIFormFieldToggle"); diff --git a/packages/web-util/src/hooks/useForm.ts b/packages/web-util/src/hooks/useForm.ts @@ -261,7 +261,7 @@ export function validateRequiredFields<FormType>( fields.forEach((f) => { const path = f.split("."); const v = getValueDeeper(form as any, path); - result = setValueDeeper(result, path, !v ? "required" : undefined); + result = setValueDeeper(result, path, v === undefined ? "required" : undefined); }); return result; }