admin_lsac 1.2.8 → 1.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,304 +1,308 @@
1
- import {
2
- Box,
3
- Button,
4
- FormControl,
5
- FormErrorMessage,
6
- FormLabel,
7
- Input,
8
- Select,
9
- } from "@chakra-ui/react";
10
- import { Field, Form, Formik, FieldArray, getIn } from "formik";
11
- import {
12
- Action,
13
- FormField,
14
- SimpleField,
15
- DropdownField,
16
- RowAction,
17
- } from "../schema/schema";
18
- import * as Yup from "yup";
19
- import Swal from "sweetalert2";
20
- import { useEffect, useState } from "react";
21
-
22
- interface GenericFormProps {
23
- action: Action | RowAction;
24
- onClose?: () => void;
25
- rowId?: number;
26
- }
27
-
28
- function parseValidation(fields: FormField[] | undefined) {
29
- if (!fields) {
30
- return {};
31
- }
32
-
33
- return fields.reduce((acc: any, field) => {
34
- if (
35
- field.type !== "dropdown" &&
36
- field.type !== "object" &&
37
- field.type !== "array"
38
- ) {
39
- acc[field.name] = field.validationSchema;
40
- } else if (field.type === "array") {
41
- if (field.element.type === "dropdown") {
42
- acc[field.name] = Yup.array().of(Yup.string().required());
43
- } else if (field.element.type === "object") {
44
- acc[field.name] = Yup.array().of(
45
- Yup.object(parseValidation(field.element.fields))
46
- );
47
- } else {
48
- acc[field.name] = Yup.array().of(field.element.validationSchema);
49
- }
50
- } else if (field.type === "object") {
51
- acc[field.name] = Yup.object(parseValidation(field.fields));
52
- }
53
- if (field.type === "dropdown") {
54
- acc[field.name] = Yup.string().required();
55
- }
56
- return acc;
57
- }, {});
58
- }
59
-
60
- function generateSingleField(
61
- formfield: SimpleField | DropdownField,
62
- fieldName: string,
63
- key: any
64
- ) {
65
- return (
66
- <Field name={fieldName} key={key}>
67
- {({ field, form }: any) => (
68
- <FormControl
69
- isInvalid={
70
- getIn(form.touched, fieldName) && getIn(form.errors, fieldName)
71
- }
72
- >
73
- <FormLabel marginTop={2}>{formfield.label}</FormLabel>
74
-
75
- {formfield.type === "string" || formfield.type === "number" ? (
76
- <Input
77
- {...field}
78
- type={formfield.type === "number" ? "number" : "text"}
79
- placeholder=""
80
- />
81
- ) : formfield.type === "file" ? (
82
- <Input
83
- type="file"
84
- name={fieldName}
85
- onChange={(event) => {
86
- if (event.currentTarget.files != null) {
87
- form.setFieldValue(fieldName, event.currentTarget.files[0]);
88
- }
89
- }}
90
- />
91
- ) : (
92
- <Select {...field} defaultValue="">
93
- <option disabled={true} value="">
94
- Select an option!
95
- </option>
96
- {(formfield as DropdownField).options?.map((option, key) => (
97
- <option key={key} value={`${option.value}`}>
98
- {option.display}
99
- </option>
100
- ))}
101
- </Select>
102
- )}
103
-
104
- <FormErrorMessage>{getIn(form.errors, fieldName)}</FormErrorMessage>
105
- </FormControl>
106
- )}
107
- </Field>
108
- );
109
- }
110
-
111
- function parseFields(
112
- fields: FormField[] | undefined,
113
- previous?: string | undefined
114
- ) {
115
- if (!fields) {
116
- return [];
117
- }
118
-
119
- const computedFields = fields.map((formfield, key) => {
120
- let fieldName: string =
121
- previous !== undefined ? previous + "." + formfield.name : formfield.name;
122
-
123
- if (formfield.type === "object") {
124
- const objectFields = parseFields(formfield.fields, fieldName);
125
- return <FormControl key={fieldName}>{objectFields}</FormControl>;
126
- } else if (formfield.type === "array") {
127
- return (
128
- <FieldArray name={fieldName}>
129
- {({ remove, push, form }) => (
130
- <div>
131
- <FormLabel marginTop={2}>{formfield.label}</FormLabel>
132
- {getIn(form.values, fieldName).length > 0 &&
133
- getIn(form.values, fieldName).map(
134
- (element: any, index: number) => (
135
- <Box paddingLeft={10}>
136
- <h4>
137
- <b>{`${fieldName}.${index}`}</b>
138
- </h4>
139
- <Box paddingLeft={10}>
140
- {formfield.element.type === "object"
141
- ? parseFields(
142
- formfield.element.fields,
143
- `${fieldName}.${index}`
144
- )
145
- : generateSingleField(
146
- formfield.element,
147
- `${fieldName}.${index}`,
148
- key
149
- )}
150
- </Box>
151
- <Button
152
- type="button"
153
- colorScheme="red"
154
- marginY={2}
155
- onClick={() => remove(index)}
156
- >
157
- Remove {`${fieldName}.${index}`}
158
- </Button>
159
- </Box>
160
- )
161
- )}
162
-
163
- <Button
164
- type="button"
165
- marginY={2}
166
- colorScheme="blue"
167
- onClick={() => {
168
- let value = undefined;
169
-
170
- if (formfield.element.type === "object") {
171
- value = getCustomInitialValues(formfield.element.fields);
172
- } else {
173
- value = getCustomInitialValues([formfield.element])[0];
174
- }
175
-
176
- push(value);
177
- }}
178
- >
179
- Add {fieldName}
180
- </Button>
181
- </div>
182
- )}
183
- </FieldArray>
184
- );
185
- } else {
186
- return generateSingleField(formfield, fieldName, key);
187
- }
188
- });
189
-
190
- return computedFields;
191
- }
192
-
193
- function getCustomInitialValues(fields: FormField[] | undefined) {
194
- let obj: any = {};
195
-
196
- if (!fields) {
197
- return obj;
198
- }
199
-
200
- fields.forEach((field) => {
201
- if (field.type === "array") obj[field.name] = [];
202
- else if (field.type === "object")
203
- obj[field.name] = getCustomInitialValues(field.fields);
204
- else if (field.type === "string") obj[field.name] = "";
205
- else if (field.type === "number") obj[field.name] = 0;
206
- else obj[field.name] = null;
207
- });
208
-
209
- return obj;
210
- }
211
-
212
- async function getInitialValues(action: Action | RowAction, rowId: number | undefined) {
213
- let obj: any = {};
214
- if ((action as RowAction).initialise) {
215
- obj = await (action as RowAction).initialise(rowId);
216
- }
217
- const customInitialValues = getCustomInitialValues(action.fields);
218
- return Object.assign({}, customInitialValues, obj);
219
- }
220
-
221
- async function setOptions(fields: FormField[] | undefined) {
222
- if (!fields) {
223
- return;
224
- }
225
-
226
- const promises = fields.map(async (field) => {
227
- if (field.type === "dropdown") field.options = await field.getOptions();
228
- else if (field.type === "array") await setOptions([field.element]);
229
- else if (field.type === "object") await setOptions(field.fields);
230
- });
231
-
232
- await Promise.all(promises);
233
- }
234
-
235
- export function GenericForm({ action, onClose, rowId }: GenericFormProps) {
236
- const [formFields, setFormFields] = useState<any[]>(
237
- parseFields(action.fields)
238
- );
239
- const [initialValues, setInitialValues] = useState<any>(getCustomInitialValues(action.fields));
240
- const [validationSchema, setValidationSchema] = useState<any>(parseValidation(action.fields));
241
-
242
- useEffect(() => {
243
- setOptions(action.fields).then(() => {
244
- setFormFields(parseFields(action.fields));
245
- });
246
- }, []);
247
-
248
- const handleFormReset = async () => {
249
- const newInitialValues = await getInitialValues(action, rowId);
250
- console.log(newInitialValues)
251
- setInitialValues(newInitialValues);
252
- };
253
-
254
- if (!action.fields) return <></>;
255
- return (
256
- <>
257
- <Formik
258
- enableReinitialize={true}
259
- initialValues={initialValues}
260
- validationSchema={Yup.object(validationSchema)}
261
- onReset={handleFormReset}
262
- onSubmit={async (values) => {
263
- try {
264
- let res;
265
- if (rowId) res = await action.onSubmit(values, rowId);
266
- else res = await action.onSubmit(values);
267
-
268
- if (onClose) onClose();
269
-
270
- Swal.fire("Ok");
271
- } catch (e: any) {
272
- if (onClose) onClose();
273
- const err = e.request.response;
274
-
275
- Swal.fire({
276
- text: "Error: " + err,
277
- });
278
- }
279
- }}
280
- >
281
- {({ isSubmitting }) => (
282
- <Form>
283
- {formFields}
284
- <Button
285
- mt={4}
286
- colorScheme="teal"
287
- isLoading={isSubmitting}
288
- type="submit"
289
- >
290
- Submit
291
- </Button>
292
- <Button
293
- mt={4}
294
- colorScheme="teal"
295
- type="reset"
296
- >
297
- Initialise Form
298
- </Button>
299
- </Form>
300
- )}
301
- </Formik>
302
- </>
303
- );
304
- }
1
+ import {
2
+ Box,
3
+ Button,
4
+ FormControl,
5
+ FormErrorMessage,
6
+ FormLabel,
7
+ Input,
8
+ Select,
9
+ } from "@chakra-ui/react";
10
+ import { Field, Form, Formik, FieldArray, getIn } from "formik";
11
+ import {
12
+ Action,
13
+ FormField,
14
+ SimpleField,
15
+ DropdownField,
16
+ RowAction,
17
+ } from "../schema/schema";
18
+ import * as Yup from "yup";
19
+ import Swal from "sweetalert2";
20
+ import { useEffect, useState } from "react";
21
+
22
+ interface RowActionWithInitialise extends RowAction {
23
+ initialise: (obj: any) => any;
24
+ }
25
+
26
+ interface GenericFormProps {
27
+ action: Action | RowAction;
28
+ onClose?: () => void;
29
+ rowId?: number;
30
+ }
31
+
32
+ function parseValidation(fields: FormField[] | undefined) {
33
+ if (!fields) {
34
+ return {};
35
+ }
36
+
37
+ return fields.reduce((acc: any, field) => {
38
+ if (
39
+ field.type !== "dropdown" &&
40
+ field.type !== "object" &&
41
+ field.type !== "array"
42
+ ) {
43
+ acc[field.name] = field.validationSchema;
44
+ } else if (field.type === "array") {
45
+ if (field.element.type === "dropdown") {
46
+ acc[field.name] = Yup.array().of(Yup.string().required());
47
+ } else if (field.element.type === "object") {
48
+ acc[field.name] = Yup.array().of(
49
+ Yup.object(parseValidation(field.element.fields))
50
+ );
51
+ } else {
52
+ acc[field.name] = Yup.array().of(field.element.validationSchema);
53
+ }
54
+ } else if (field.type === "object") {
55
+ acc[field.name] = Yup.object(parseValidation(field.fields));
56
+ }
57
+ if (field.type === "dropdown") {
58
+ acc[field.name] = Yup.string().required();
59
+ }
60
+ return acc;
61
+ }, {});
62
+ }
63
+
64
+ function generateSingleField(
65
+ formfield: SimpleField | DropdownField,
66
+ fieldName: string,
67
+ key: any
68
+ ) {
69
+ return (
70
+ <Field name={fieldName} key={key}>
71
+ {({ field, form }: any) => (
72
+ <FormControl
73
+ isInvalid={
74
+ getIn(form.touched, fieldName) && getIn(form.errors, fieldName)
75
+ }
76
+ >
77
+ <FormLabel marginTop={2}>{formfield.label}</FormLabel>
78
+
79
+ {formfield.type === "string" || formfield.type === "number" ? (
80
+ <Input
81
+ {...field}
82
+ type={formfield.type === "number" ? "number" : "text"}
83
+ placeholder=""
84
+ />
85
+ ) : formfield.type === "file" ? (
86
+ <Input
87
+ type="file"
88
+ name={fieldName}
89
+ onChange={(event) => {
90
+ if (event.currentTarget.files != null) {
91
+ form.setFieldValue(fieldName, event.currentTarget.files[0]);
92
+ }
93
+ }}
94
+ />
95
+ ) : (
96
+ <Select {...field} defaultValue="">
97
+ <option disabled={true} value="">
98
+ Select an option!
99
+ </option>
100
+ {(formfield as DropdownField).options?.map((option, key) => (
101
+ <option key={key} value={`${option.value}`}>
102
+ {option.display}
103
+ </option>
104
+ ))}
105
+ </Select>
106
+ )}
107
+
108
+ <FormErrorMessage>{getIn(form.errors, fieldName)}</FormErrorMessage>
109
+ </FormControl>
110
+ )}
111
+ </Field>
112
+ );
113
+ }
114
+
115
+ function parseFields(
116
+ fields: FormField[] | undefined,
117
+ previous?: string | undefined
118
+ ) {
119
+ if (!fields) {
120
+ return [];
121
+ }
122
+
123
+ const computedFields = fields.map((formfield, key) => {
124
+ let fieldName: string =
125
+ previous !== undefined ? previous + "." + formfield.name : formfield.name;
126
+
127
+ if (formfield.type === "object") {
128
+ const objectFields = parseFields(formfield.fields, fieldName);
129
+ return <FormControl key={fieldName}>{objectFields}</FormControl>;
130
+ } else if (formfield.type === "array") {
131
+ return (
132
+ <FieldArray name={fieldName}>
133
+ {({ remove, push, form }) => (
134
+ <div>
135
+ <FormLabel marginTop={2}>{formfield.label}</FormLabel>
136
+ {getIn(form.values, fieldName).length > 0 &&
137
+ getIn(form.values, fieldName).map(
138
+ (element: any, index: number) => (
139
+ <Box paddingLeft={10}>
140
+ <h4>
141
+ <b>{`${fieldName}.${index}`}</b>
142
+ </h4>
143
+ <Box paddingLeft={10}>
144
+ {formfield.element.type === "object"
145
+ ? parseFields(
146
+ formfield.element.fields,
147
+ `${fieldName}.${index}`
148
+ )
149
+ : generateSingleField(
150
+ formfield.element,
151
+ `${fieldName}.${index}`,
152
+ key
153
+ )}
154
+ </Box>
155
+ <Button
156
+ type="button"
157
+ colorScheme="red"
158
+ marginY={2}
159
+ onClick={() => remove(index)}
160
+ >
161
+ Remove {`${fieldName}.${index}`}
162
+ </Button>
163
+ </Box>
164
+ )
165
+ )}
166
+
167
+ <Button
168
+ type="button"
169
+ marginY={2}
170
+ colorScheme="blue"
171
+ onClick={() => {
172
+ let value = undefined;
173
+
174
+ if (formfield.element.type === "object") {
175
+ value = getCustomInitialValues(formfield.element.fields);
176
+ } else {
177
+ value = getCustomInitialValues([formfield.element])[0];
178
+ }
179
+
180
+ push(value);
181
+ }}
182
+ >
183
+ Add {fieldName}
184
+ </Button>
185
+ </div>
186
+ )}
187
+ </FieldArray>
188
+ );
189
+ } else {
190
+ return generateSingleField(formfield, fieldName, key);
191
+ }
192
+ });
193
+
194
+ return computedFields;
195
+ }
196
+
197
+ function getCustomInitialValues(fields: FormField[] | undefined) {
198
+ let obj: any = {};
199
+
200
+ if (!fields) {
201
+ return obj;
202
+ }
203
+
204
+ fields.forEach((field) => {
205
+ if (field.type === "array") obj[field.name] = [];
206
+ else if (field.type === "object")
207
+ obj[field.name] = getCustomInitialValues(field.fields);
208
+ else if (field.type === "string") obj[field.name] = "";
209
+ else if (field.type === "number") obj[field.name] = 0;
210
+ else obj[field.name] = null;
211
+ });
212
+
213
+ return obj;
214
+ }
215
+
216
+ async function getInitialValues(action: Action | RowAction, rowId: number | undefined) {
217
+ let obj: any = {};
218
+ if ((action as RowAction).initialise) {
219
+ obj = await (action as RowActionWithInitialise).initialise(rowId);
220
+ }
221
+ const customInitialValues = getCustomInitialValues(action.fields);
222
+ return Object.assign({}, customInitialValues, obj);
223
+ }
224
+
225
+ async function setOptions(fields: FormField[] | undefined) {
226
+ if (!fields) {
227
+ return;
228
+ }
229
+
230
+ const promises = fields.map(async (field) => {
231
+ if (field.type === "dropdown") field.options = await field.getOptions();
232
+ else if (field.type === "array") await setOptions([field.element]);
233
+ else if (field.type === "object") await setOptions(field.fields);
234
+ });
235
+
236
+ await Promise.all(promises);
237
+ }
238
+
239
+ export function GenericForm({ action, onClose, rowId }: GenericFormProps) {
240
+ const [formFields, setFormFields] = useState<any[]>(
241
+ parseFields(action.fields)
242
+ );
243
+ const [initialValues, setInitialValues] = useState<any>(getCustomInitialValues(action.fields));
244
+ const [validationSchema, setValidationSchema] = useState<any>(parseValidation(action.fields));
245
+
246
+ useEffect(() => {
247
+ setOptions(action.fields).then(() => {
248
+ setFormFields(parseFields(action.fields));
249
+ });
250
+ }, []);
251
+
252
+ const handleFormReset = async () => {
253
+ const newInitialValues = await getInitialValues(action, rowId);
254
+ console.log(newInitialValues)
255
+ setInitialValues(newInitialValues);
256
+ };
257
+
258
+ if (!action.fields) return <></>;
259
+ return (
260
+ <>
261
+ <Formik
262
+ enableReinitialize={true}
263
+ initialValues={initialValues}
264
+ validationSchema={Yup.object(validationSchema)}
265
+ onReset={handleFormReset}
266
+ onSubmit={async (values) => {
267
+ try {
268
+ let res;
269
+ if (rowId) res = await action.onSubmit(values, rowId);
270
+ else res = await action.onSubmit(values);
271
+
272
+ if (onClose) onClose();
273
+
274
+ Swal.fire("Ok");
275
+ } catch (e: any) {
276
+ if (onClose) onClose();
277
+ const err = e.request.response;
278
+
279
+ Swal.fire({
280
+ text: "Error: " + err,
281
+ });
282
+ }
283
+ }}
284
+ >
285
+ {({ isSubmitting }) => (
286
+ <Form>
287
+ {formFields}
288
+ <Button
289
+ mt={4}
290
+ colorScheme="teal"
291
+ isLoading={isSubmitting}
292
+ type="submit"
293
+ >
294
+ Submit
295
+ </Button>
296
+ <Button
297
+ mt={4}
298
+ colorScheme="teal"
299
+ type="reset"
300
+ >
301
+ Initialise Form
302
+ </Button>
303
+ </Form>
304
+ )}
305
+ </Formik>
306
+ </>
307
+ );
308
+ }