summaryrefslogtreecommitdiff
path: root/packages/exchange-backoffice-ui/src/forms/forms.ts
blob: 1e59e0cf2a9d3c590df8df6ffcdc58914e63f290 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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";
import { InputChoiceStacked } from "./InputChoice.js";
import { InputArray } from "./InputArray.js";
import { InputSelectMultiple } from "./InputSelectMultiple.js";
import { InputTextArea } from "./InputTextArea.js";

export type DoubleColumnForm = DoubleColumnFormSection[];

type DoubleColumnFormSection = {
  title: TranslatedString;
  description?: TranslatedString;
  fields: UIFormField[];
};

/**
 * Constrain the type with the ui props
 */
type FieldType = {
  separator: {};
  array: Parameters<typeof InputArray>[0];
  selectMultiple: Parameters<typeof InputSelectMultiple>[0];
  text: Parameters<typeof InputText>[0];
  textArea: Parameters<typeof InputTextArea>[0];
  choiceStacked: Parameters<typeof InputChoiceStacked>[0];
  date: Parameters<typeof InputDate>[0];
  integer: Parameters<typeof InputInteger>[0];
};

/**
 * List all the form fields so typescript can type-check the form instance
 */
export type UIFormField =
  | { type: "separator"; props: FieldType["separator"] }
  | { type: "array"; props: FieldType["array"] }
  | { type: "selectMultiple"; props: FieldType["selectMultiple"] }
  | { type: "text"; props: FieldType["text"] }
  | { type: "textArea"; props: FieldType["textArea"] }
  | { type: "choiceStacked"; props: FieldType["choiceStacked"] }
  | { 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>;
};

function Separator(): VNode {
  return create("div", {});
}

/**
 * Maps input type with component implementation
 */
const UIFormConfiguration: UIFormFieldMap = {
  separator: Separator,
  array: InputArray,
  text: InputText,
  textArea: InputTextArea,
  date: InputDate,
  choiceStacked: InputChoiceStacked,
  integer: InputInteger,
  selectMultiple: InputSelectMultiple,
};

export function RenderAllFieldsByUiConfig({
  fields,
}: {
  fields: UIFormField[];
}): VNode {
  return create(
    Fragment,
    {},
    fields.map((field) => {
      const Component = UIFormConfiguration[
        field.type
      ] as FieldComponentFunction<any>;
      return Component(field.props);
    }),
  );
}