wallet-core/packages/aml-backoffice-ui/src/handlers/forms.ts

136 lines
4.2 KiB
TypeScript
Raw Normal View History

2023-05-10 05:53:37 +02:00
import { TranslatedString } from "@gnu-taler/taler-util";
import { InputText } from "./InputText.js";
import { InputDate } from "./InputDate.js";
import { InputInteger } from "./InputInteger.js";
import { h as create, Fragment, VNode } from "preact";
2023-05-16 06:23:44 +02:00
import { InputChoiceStacked } from "./InputChoiceStacked.js";
2023-05-10 05:53:37 +02:00
import { InputArray } from "./InputArray.js";
import { InputSelectMultiple } from "./InputSelectMultiple.js";
import { InputTextArea } from "./InputTextArea.js";
import { InputFile } from "./InputFile.js";
2023-05-16 16:33:29 +02:00
import { Caption } from "./Caption.js";
2023-05-16 06:23:44 +02:00
import { Group } from "./Group.js";
import { InputSelectOne } from "./InputSelectOne.js";
2023-05-19 18:26:47 +02:00
import { FormProvider } from "./FormProvider.js";
import { InputLine } from "./InputLine.js";
import { InputAmount } from "./InputAmount.js";
import { InputChoiceHorizontal } from "./InputChoiceHorizontal.js";
2023-05-10 05:53:37 +02:00
export type DoubleColumnForm = Array<DoubleColumnFormSection | undefined>;
2023-05-10 05:53:37 +02:00
2023-05-25 23:23:38 +02:00
export type DoubleColumnFormSection = {
2023-05-10 05:53:37 +02:00
title: TranslatedString;
description?: TranslatedString;
fields: UIFormField[];
};
/**
* Constrain the type with the ui props
*/
2023-05-22 15:40:13 +02:00
type FieldType<T extends object = any, K extends keyof T = any> = {
2023-05-16 06:23:44 +02:00
group: Parameters<typeof Group>[0];
2023-05-16 16:33:29 +02:00
caption: Parameters<typeof Caption>[0];
2023-05-22 15:40:13 +02:00
array: Parameters<typeof InputArray<T, K>>[0];
file: Parameters<typeof InputFile<T, K>>[0];
selectOne: Parameters<typeof InputSelectOne<T, K>>[0];
selectMultiple: Parameters<typeof InputSelectMultiple<T, K>>[0];
text: Parameters<typeof InputText<T, K>>[0];
textArea: Parameters<typeof InputTextArea<T, K>>[0];
choiceStacked: Parameters<typeof InputChoiceStacked<T, K>>[0];
choiceHorizontal: Parameters<typeof InputChoiceHorizontal<T, K>>[0];
2023-05-22 15:40:13 +02:00
date: Parameters<typeof InputDate<T, K>>[0];
integer: Parameters<typeof InputInteger<T, K>>[0];
amount: Parameters<typeof InputAmount<T, K>>[0];
2023-05-10 05:53:37 +02:00
};
/**
* List all the form fields so typescript can type-check the form instance
*/
export type UIFormField =
2023-05-16 06:23:44 +02:00
| { type: "group"; props: FieldType["group"] }
2023-05-16 16:33:29 +02:00
| { type: "caption"; props: FieldType["caption"] }
2023-05-10 05:53:37 +02:00
| { type: "array"; props: FieldType["array"] }
| { type: "file"; props: FieldType["file"] }
| { type: "amount"; props: FieldType["amount"] }
2023-05-16 06:23:44 +02:00
| { type: "selectOne"; props: FieldType["selectOne"] }
2023-05-10 05:53:37 +02:00
| { type: "selectMultiple"; props: FieldType["selectMultiple"] }
| { type: "text"; props: FieldType["text"] }
| { type: "textArea"; props: FieldType["textArea"] }
| { type: "choiceStacked"; props: FieldType["choiceStacked"] }
| { type: "choiceHorizontal"; props: FieldType["choiceHorizontal"] }
2023-05-10 05:53:37 +02:00
| { type: "integer"; props: FieldType["integer"] }
| { type: "date"; props: FieldType["date"] };
type FieldComponentFunction<key extends keyof FieldType> = (
props: FieldType[key],
) => VNode;
type UIFormFieldMap = {
[key in keyof FieldType]: FieldComponentFunction<key>;
};
/**
* Maps input type with component implementation
*/
const UIFormConfiguration: UIFormFieldMap = {
2023-05-16 06:23:44 +02:00
group: Group,
2023-05-16 16:33:29 +02:00
caption: Caption,
2023-05-22 15:40:13 +02:00
//@ts-ignore
2023-05-10 05:53:37 +02:00
array: InputArray,
text: InputText,
2023-05-22 15:40:13 +02:00
//@ts-ignore
file: InputFile,
2023-05-10 05:53:37 +02:00
textArea: InputTextArea,
2023-05-22 15:40:13 +02:00
//@ts-ignore
2023-05-10 05:53:37 +02:00
date: InputDate,
2023-05-22 15:40:13 +02:00
//@ts-ignore
2023-05-10 05:53:37 +02:00
choiceStacked: InputChoiceStacked,
//@ts-ignore
choiceHorizontal: InputChoiceHorizontal,
2023-05-10 05:53:37 +02:00
integer: InputInteger,
2023-05-22 15:40:13 +02:00
//@ts-ignore
2023-05-16 06:23:44 +02:00
selectOne: InputSelectOne,
2023-05-22 15:40:13 +02:00
//@ts-ignore
2023-05-10 05:53:37 +02:00
selectMultiple: InputSelectMultiple,
//@ts-ignore
amount: InputAmount,
2023-05-10 05:53:37 +02:00
};
export function RenderAllFieldsByUiConfig({
fields,
}: {
fields: UIFormField[];
}): VNode {
return create(
Fragment,
{},
2023-05-15 16:45:23 +02:00
fields.map((field, i) => {
2023-05-10 05:53:37 +02:00
const Component = UIFormConfiguration[
field.type
] as FieldComponentFunction<any>;
2023-05-16 16:33:29 +02:00
return Component(field.props);
2023-05-10 05:53:37 +02:00
}),
);
}
2023-05-19 18:26:47 +02:00
type FormSet<T extends object> = {
2023-05-19 18:26:47 +02:00
Provider: typeof FormProvider<T>;
InputLine: <K extends keyof T>() => typeof InputLine<T, K>;
InputChoiceHorizontal: <K extends keyof T>() => typeof InputChoiceHorizontal<
T,
K
>;
2023-05-19 18:26:47 +02:00
};
export function createNewForm<T extends object>() {
const res: FormSet<T> = {
2023-05-19 18:26:47 +02:00
Provider: FormProvider,
InputLine: () => InputLine,
InputChoiceHorizontal: () => InputChoiceHorizontal,
};
return {
Provider: res.Provider,
InputLine: res.InputLine(),
InputChoiceHorizontal: res.InputChoiceHorizontal(),
2023-05-19 18:26:47 +02:00
};
}