summaryrefslogtreecommitdiff
path: root/packages/exchange-backoffice-ui/src/handlers/forms.ts
blob: a97b8561d051db35942d8e6fcaf9772726393445 (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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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 "./InputChoiceStacked.js";
import { InputArray } from "./InputArray.js";
import { InputSelectMultiple } from "./InputSelectMultiple.js";
import { InputTextArea } from "./InputTextArea.js";
import { InputFile } from "./InputFile.js";
import { Caption } from "./Caption.js";
import { Group } from "./Group.js";
import { InputSelectOne } from "./InputSelectOne.js";
import { FormProvider } from "./FormProvider.js";
import { InputLine } from "./InputLine.js";

export type DoubleColumnForm = DoubleColumnFormSection[];

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

/**
 * Constrain the type with the ui props
 */
type FieldType = {
  group: Parameters<typeof Group>[0];
  caption: Parameters<typeof Caption>[0];
  array: Parameters<typeof InputArray>[0];
  file: Parameters<typeof InputFile>[0];
  selectOne: Parameters<typeof InputSelectOne>[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: "group"; props: FieldType["group"] }
  | { type: "caption"; props: FieldType["caption"] }
  | { type: "array"; props: FieldType["array"] }
  | { type: "file"; props: FieldType["file"] }
  | { type: "selectOne"; props: FieldType["selectOne"] }
  | { 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>;
};

/**
 * Maps input type with component implementation
 */
const UIFormConfiguration: UIFormFieldMap = {
  group: Group,
  caption: Caption,
  array: InputArray,
  text: InputText,
  file: InputFile,
  textArea: InputTextArea,
  date: InputDate,
  choiceStacked: InputChoiceStacked,
  integer: InputInteger,
  selectOne: InputSelectOne,
  selectMultiple: InputSelectMultiple,
};

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

type FormSet<T> = {
  Provider: typeof FormProvider<T>;
  InputLine: typeof InputLine<T>;
};
export function createNewForm<T>(): FormSet<T> {
  return {
    Provider: FormProvider,
    InputLine: InputLine,
  };
}