@engagebay/engagebay-form-module 1.0.0-beta.0
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.
- package/README.md +126 -0
- package/link.sh +2 -0
- package/package.json +30 -0
- package/src/api/index.ts +25 -0
- package/src/form/Form.tsx +157 -0
- package/src/form/FormField.tsx +80 -0
- package/src/form/FormFieldUtils.ts +241 -0
- package/src/form/FormFields.tsx +41 -0
- package/src/form/context/FormContext.tsx +66 -0
- package/src/form/formfields/ArrayField.tsx +169 -0
- package/src/form/formfields/BusinessHoursField.tsx +204 -0
- package/src/form/formfields/CheckboxButtonsField.tsx +97 -0
- package/src/form/formfields/CheckboxField.tsx +118 -0
- package/src/form/formfields/ColorPickerField.tsx +59 -0
- package/src/form/formfields/ComboMultiSelect.tsx +290 -0
- package/src/form/formfields/ComboSelect.tsx +278 -0
- package/src/form/formfields/DatePickerField.tsx +89 -0
- package/src/form/formfields/DateRangePickerField.tsx +104 -0
- package/src/form/formfields/DynamicMultiSelect.tsx +189 -0
- package/src/form/formfields/DynamicSelect.tsx +187 -0
- package/src/form/formfields/Error.tsx +15 -0
- package/src/form/formfields/ErrorContextHandler.tsx +77 -0
- package/src/form/formfields/FileUploadField.tsx +196 -0
- package/src/form/formfields/IframeField.tsx +65 -0
- package/src/form/formfields/InputField.tsx +67 -0
- package/src/form/formfields/InputGroupField.tsx +44 -0
- package/src/form/formfields/MultipleSelectField.tsx +98 -0
- package/src/form/formfields/NumberField.tsx +61 -0
- package/src/form/formfields/PasswordField.tsx +93 -0
- package/src/form/formfields/PhoneNumberField.tsx +163 -0
- package/src/form/formfields/RadioField.tsx +104 -0
- package/src/form/formfields/RadioGroupComponent.tsx +94 -0
- package/src/form/formfields/RangeField.tsx +53 -0
- package/src/form/formfields/SelectField.tsx +82 -0
- package/src/form/formfields/SwitchField.tsx +131 -0
- package/src/form/formfields/TextAreaField.tsx +48 -0
- package/src/form/formfields/TimeField.tsx +53 -0
- package/src/form/formfields/Typeahead.tsx +211 -0
- package/src/form/formfields/TypeaheadMultiSelect.tsx +203 -0
- package/src/form/formfields/UrlField.tsx +53 -0
- package/src/form/hooks/useDynamicReducer.tsx +42 -0
- package/src/form/schema/CustomValidators.ts +63 -0
- package/src/form/schema/FormFieldSchema.ts +342 -0
- package/src/form/util/RenderFormField.tsx +149 -0
- package/src/form/util/RenderListOptions.tsx +424 -0
- package/src/form/util/index.ts +185 -0
- package/src/util/LoaderWithText.tsx +28 -0
- package/src/util/svg/HELPER_ICONS.ts +16 -0
- package/src/util/svg/SVGIcon.tsx +23 -0
- package/tsconfig.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Form and FormField Documentation
|
|
2
|
+
|
|
3
|
+
## `Form` Component
|
|
4
|
+
|
|
5
|
+
### Description
|
|
6
|
+
|
|
7
|
+
The `Form` component is a wrapper that handles form submission, validation, and state management using the `react-hook-form` library. It provides context to child components and handles the form's lifecycle, including validation and submission.
|
|
8
|
+
|
|
9
|
+
### Props
|
|
10
|
+
|
|
11
|
+
- **`fieldSchema: FormFieldSchema[]`**
|
|
12
|
+
An array of objects that define the structure and validation rules of form fields.
|
|
13
|
+
|
|
14
|
+
- **`formData: any`**
|
|
15
|
+
Default values for the form fields.
|
|
16
|
+
|
|
17
|
+
- **`onError?: (error: any) => void`**
|
|
18
|
+
(Optional) Callback function invoked on form validation errors.
|
|
19
|
+
|
|
20
|
+
- **`onSubmit: (data: FormData) => void`**
|
|
21
|
+
Callback function that is triggered on successful form submission.
|
|
22
|
+
|
|
23
|
+
- **`children: (props: { ... }) => React.ReactNode`**
|
|
24
|
+
Function that renders child components, providing various form methods and state as props. These include `submitcb`, `watch`, `setValue`, `getValues`, `reset`, `setError`, `trigger`, and `unregister`.
|
|
25
|
+
|
|
26
|
+
- **`customClass?: string`**
|
|
27
|
+
(Optional) Custom CSS class for the form element.
|
|
28
|
+
|
|
29
|
+
### Example
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
<Form
|
|
33
|
+
fieldSchema={fieldSchema}
|
|
34
|
+
formData={defaultValues}
|
|
35
|
+
onSubmit={handleSubmit}
|
|
36
|
+
onError={handleError}
|
|
37
|
+
customClass="custom-form-class"
|
|
38
|
+
>
|
|
39
|
+
{({ submitcb, watch, setValue }) => <>{/* Your form fields go here */}</>}
|
|
40
|
+
</Form>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## `FormField` Component
|
|
44
|
+
|
|
45
|
+
### Description
|
|
46
|
+
|
|
47
|
+
The `FormField` component renders individual form fields based on the configuration provided via `fieldConfig`. It uses the form context provided by the `Form` component to handle registration and validation.
|
|
48
|
+
|
|
49
|
+
### Props
|
|
50
|
+
|
|
51
|
+
- **`fieldConfig: FormFieldSchema`**
|
|
52
|
+
Configuration object that defines the field's properties, such as type, validation, and custom handling functions.
|
|
53
|
+
|
|
54
|
+
- **`onChange?: (data: any) => void`**
|
|
55
|
+
(Optional) Callback function triggered when the field value changes.
|
|
56
|
+
|
|
57
|
+
### Example
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
<FormField fieldConfig={yourFieldConfig} onChange={handleFieldChange} />
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## `FormFieldSchema`
|
|
64
|
+
|
|
65
|
+
### Description
|
|
66
|
+
|
|
67
|
+
Defines the structure, behavior, and validation rules for individual form fields.
|
|
68
|
+
|
|
69
|
+
### Properties
|
|
70
|
+
|
|
71
|
+
- **`name: string`**
|
|
72
|
+
The name of the field, used as a key for form data.
|
|
73
|
+
|
|
74
|
+
- **`required: boolean`**
|
|
75
|
+
Whether the field is required.
|
|
76
|
+
|
|
77
|
+
- **`formFieldType: FormFieldType`**
|
|
78
|
+
The type of form field, e.g., `INPUT`, `SELECT`, `CHECKBOX`, etc.
|
|
79
|
+
|
|
80
|
+
- **`label?: string`**
|
|
81
|
+
(Optional) Label for the form field.
|
|
82
|
+
|
|
83
|
+
- **`placeholder?: string`**
|
|
84
|
+
(Optional) Placeholder text for the field.
|
|
85
|
+
|
|
86
|
+
- **`helpText?: string`**
|
|
87
|
+
(Optional) Help text displayed alongside the field.
|
|
88
|
+
|
|
89
|
+
- **`disabled?: boolean`**
|
|
90
|
+
(Optional) Disables the field if set to `true`.
|
|
91
|
+
|
|
92
|
+
- **`options?: FieldOptionsSchema[]`**
|
|
93
|
+
(Optional) Array of options for fields like `SELECT` or `RADIO`.
|
|
94
|
+
|
|
95
|
+
- **`onChange?: (data: any) => void`**
|
|
96
|
+
(Optional) Custom handler for the field's `onChange` event.
|
|
97
|
+
|
|
98
|
+
- **`customClassNames?: { ... }`**
|
|
99
|
+
(Optional) Custom CSS classes for different parts of the field.
|
|
100
|
+
|
|
101
|
+
### Example
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
const fieldSchema: FormFieldSchema = {
|
|
105
|
+
name: "email",
|
|
106
|
+
required: true,
|
|
107
|
+
formFieldType: FormFieldType.INPUT,
|
|
108
|
+
label: "Email",
|
|
109
|
+
placeholder: "Enter your email",
|
|
110
|
+
formFieldPattern: [FormFieldPatternsImpl.EMAIL],
|
|
111
|
+
};
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Additional Types and Enums
|
|
115
|
+
|
|
116
|
+
- **`FormFieldType`**
|
|
117
|
+
Enum defining various types of form fields (e.g., `INPUT`, `PASSWORD`, `SELECT`, etc.).
|
|
118
|
+
|
|
119
|
+
- **`FormFieldSubType`**
|
|
120
|
+
Enum defining subtypes of fields, like `TEXT` and `EMAIL`.
|
|
121
|
+
|
|
122
|
+
- **`FieldOptionsSchema`**
|
|
123
|
+
Structure defining options for fields like `SELECT` or `RADIO`. Includes `value`, `label`, `isDisabled`, etc.
|
|
124
|
+
|
|
125
|
+
- **`FormFieldPatternsImpl`**
|
|
126
|
+
Class providing validation patterns and messages for fields (e.g., `REQUIRED`, `EMAIL`, `URL`).
|
package/link.sh
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@engagebay/engagebay-form-module",
|
|
3
|
+
"version": "1.0.0-beta.0",
|
|
4
|
+
"description": "Provide base form components to reacho",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
|
+
},
|
|
8
|
+
"author": "Reacho Dev",
|
|
9
|
+
"license": "ISC",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"react-phone-input-2": "^2.15.1",
|
|
12
|
+
"react-phone-number-input": "^3.4.9"
|
|
13
|
+
},
|
|
14
|
+
"peerDependencies": {
|
|
15
|
+
"@headlessui/react": ">=2.1.2",
|
|
16
|
+
"@heroicons/react": ">=2.1.5",
|
|
17
|
+
"@reduxjs/toolkit": ">=2.2.7",
|
|
18
|
+
"@tippyjs/react": ">=4.2.6",
|
|
19
|
+
"@types/lodash": ">=4.17.7",
|
|
20
|
+
"@types/react-redux": ">=7.1.33",
|
|
21
|
+
"axios": ">=1.7.2",
|
|
22
|
+
"clsx": ">=2.1.1",
|
|
23
|
+
"moment": ">=2.30.1",
|
|
24
|
+
"react-hook-form": ">=7.52.1",
|
|
25
|
+
"react-popper": ">=2.3.0",
|
|
26
|
+
"react-redux": ">=8.0.4",
|
|
27
|
+
"react-tailwindcss-datepicker": ">=1.6.6",
|
|
28
|
+
"redux-saga": ">=1.3.0"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/api/index.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import axios, { AxiosRequestConfig } from "axios";
|
|
2
|
+
|
|
3
|
+
const BASE_API: AxiosRequestConfig = {
|
|
4
|
+
baseURL:
|
|
5
|
+
(window as any).REACHO_BASE_URL ||
|
|
6
|
+
(window as any).parent.REACHO_BASE_URL,
|
|
7
|
+
timeout: 30000,
|
|
8
|
+
headers: {
|
|
9
|
+
"Content-Type": "application/json",
|
|
10
|
+
Authorization: "Bearer " + localStorage.getItem("__session_token"),
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const baseReqService = axios;
|
|
15
|
+
|
|
16
|
+
export const reachoAPI = baseReqService.create(BASE_API);
|
|
17
|
+
|
|
18
|
+
reachoAPI.interceptors.request.use(
|
|
19
|
+
(config) => {
|
|
20
|
+
return config;
|
|
21
|
+
},
|
|
22
|
+
(error) => {
|
|
23
|
+
return Promise.reject(error);
|
|
24
|
+
}
|
|
25
|
+
);
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
UseFormWatch,
|
|
4
|
+
UseFormSetValue,
|
|
5
|
+
UseFormGetValues,
|
|
6
|
+
UseFormReset,
|
|
7
|
+
useForm,
|
|
8
|
+
UseFormSetError,
|
|
9
|
+
UseFormTrigger,
|
|
10
|
+
UseFormUnregister,
|
|
11
|
+
UseFormResetField,
|
|
12
|
+
} from "react-hook-form";
|
|
13
|
+
import { FormFieldSchema } from "./schema/FormFieldSchema";
|
|
14
|
+
import { FormContext } from "./context/FormContext";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Props for the Form component
|
|
18
|
+
*
|
|
19
|
+
* @typedef {Object} FormPropsSchema
|
|
20
|
+
* @property {FormFieldSchema[]} fieldSchema - An array of form field schema objects defining the structure and validation of the form fields.
|
|
21
|
+
* @property {any} formData - Default values for the form fields.
|
|
22
|
+
* @property {(error: any) => void} [onError] - Optional callback function to handle form validation errors.
|
|
23
|
+
* @property {(data: FormData) => void} onSubmit - Callback function to handle form submission with valid data.
|
|
24
|
+
* @property {(props: FormChildrenProps) => React.ReactNode} children - Function that renders child components, providing form methods and state as props.
|
|
25
|
+
* @property {string} [customClass] - Optional custom CSS class for the form element.
|
|
26
|
+
*/
|
|
27
|
+
type FormPropsSchema = {
|
|
28
|
+
fieldSchema: FormFieldSchema[];
|
|
29
|
+
formData: any;
|
|
30
|
+
onError?: (error: any) => void;
|
|
31
|
+
onSubmit?: (data: FormData) => void;
|
|
32
|
+
setFormRef?: (ref: HTMLFormElement | null) => void; // Must be called in Modal's and Offcanvas's
|
|
33
|
+
children: (props: {
|
|
34
|
+
submitcb: () => void;
|
|
35
|
+
watch: UseFormWatch<any>;
|
|
36
|
+
setValue: UseFormSetValue<any>;
|
|
37
|
+
getValues: UseFormGetValues<any>;
|
|
38
|
+
reset: UseFormReset<any>;
|
|
39
|
+
setError: UseFormSetError<any>;
|
|
40
|
+
trigger: UseFormTrigger<any>;
|
|
41
|
+
unregister: UseFormUnregister<any>;
|
|
42
|
+
resetField: UseFormResetField<any>;
|
|
43
|
+
}) => React.ReactNode;
|
|
44
|
+
customClass?: string;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Form component to handle form submission, validation, and state management.
|
|
49
|
+
*
|
|
50
|
+
* @param {FormPropsSchema} props - The properties for the Form component.
|
|
51
|
+
* @returns {JSX.Element} The rendered Form component.
|
|
52
|
+
*/
|
|
53
|
+
export default function Form(props: FormPropsSchema): JSX.Element {
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
const formRef = useRef<HTMLFormElement>(null);
|
|
57
|
+
|
|
58
|
+
// Initialize the form using useForm hook from react-hook-form
|
|
59
|
+
const {
|
|
60
|
+
register,
|
|
61
|
+
control,
|
|
62
|
+
setFocus,
|
|
63
|
+
watch,
|
|
64
|
+
setValue,
|
|
65
|
+
handleSubmit,
|
|
66
|
+
formState: { errors },
|
|
67
|
+
getFieldState,
|
|
68
|
+
getValues,
|
|
69
|
+
reset,
|
|
70
|
+
resetField,
|
|
71
|
+
trigger,
|
|
72
|
+
setError,
|
|
73
|
+
unregister,
|
|
74
|
+
} = useForm({
|
|
75
|
+
defaultValues: props.formData, // Set default values from props
|
|
76
|
+
mode: "onChange", // Set validation mode to "onChange"
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
console.log("formRef.current: new", formRef.current);
|
|
81
|
+
if (formRef.current && props.setFormRef) {
|
|
82
|
+
props.setFormRef(formRef.current);
|
|
83
|
+
}
|
|
84
|
+
}, []);
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Function to handle valid form submission
|
|
88
|
+
*
|
|
89
|
+
* @param {any} data - The form data.
|
|
90
|
+
*/
|
|
91
|
+
const onFormvalid = (data: any) => {
|
|
92
|
+
console.log("Valid Form Data :: ", data);
|
|
93
|
+
props.onSubmit && props.onSubmit(data);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Function to handle invalid form submission
|
|
98
|
+
*
|
|
99
|
+
* @param {any} data - The form data.
|
|
100
|
+
*/
|
|
101
|
+
const onFormInvalid = (data: any) => {
|
|
102
|
+
console.log("Invalid Form Data :: ", data);
|
|
103
|
+
props.onError && props.onError(errors);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Handler for form submission
|
|
107
|
+
const onSubmit = (e?: React.BaseSyntheticEvent) => {
|
|
108
|
+
console.log("Submitting form...");
|
|
109
|
+
e?.preventDefault();
|
|
110
|
+
e?.stopPropagation();
|
|
111
|
+
handleSubmit(onFormvalid, onFormInvalid)(e); // Properly invoke handleSubmit
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<>
|
|
116
|
+
{/* Provide form context to child components */}
|
|
117
|
+
<FormContext.Provider
|
|
118
|
+
value={{
|
|
119
|
+
formFields: props.fieldSchema,
|
|
120
|
+
onSubmit,
|
|
121
|
+
register,
|
|
122
|
+
control,
|
|
123
|
+
setValue,
|
|
124
|
+
errors,
|
|
125
|
+
getFieldState,
|
|
126
|
+
getValues,
|
|
127
|
+
handleSubmit,
|
|
128
|
+
watch,
|
|
129
|
+
reset,
|
|
130
|
+
trigger,
|
|
131
|
+
resetField,
|
|
132
|
+
setError,
|
|
133
|
+
setFocus,
|
|
134
|
+
unregister,
|
|
135
|
+
}}>
|
|
136
|
+
{/* Form element */}
|
|
137
|
+
<form
|
|
138
|
+
ref={formRef}
|
|
139
|
+
className={props.customClass ? props.customClass : ""}
|
|
140
|
+
onSubmit={onSubmit}>
|
|
141
|
+
{/* Render children with form methods and state */}
|
|
142
|
+
{props.children({
|
|
143
|
+
submitcb: onSubmit,
|
|
144
|
+
watch,
|
|
145
|
+
setValue,
|
|
146
|
+
getValues,
|
|
147
|
+
reset,
|
|
148
|
+
setError,
|
|
149
|
+
trigger,
|
|
150
|
+
unregister,
|
|
151
|
+
resetField,
|
|
152
|
+
})}
|
|
153
|
+
</form>
|
|
154
|
+
</FormContext.Provider>
|
|
155
|
+
</>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import {
|
|
4
|
+
FormFieldComponentPropSchema,
|
|
5
|
+
FormFieldType,
|
|
6
|
+
} from "./schema/FormFieldSchema";
|
|
7
|
+
import { FormContext } from "./context/FormContext";
|
|
8
|
+
import FormFieldComponents from "./FormFieldUtils";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `FormField` Component
|
|
12
|
+
*
|
|
13
|
+
* The `FormField` component is responsible for rendering individual form fields
|
|
14
|
+
* based on the provided `fieldConfig`. It utilizes the form context to manage
|
|
15
|
+
* the form's state, validation, and other functionalities.
|
|
16
|
+
*
|
|
17
|
+
* @param {FormFieldComponentPropSchema} props - The props for the `FormField` component.
|
|
18
|
+
* @param {FormFieldSchema} props.fieldConfig - Configuration object defining the field's properties, such as type, validation, and custom handling functions.
|
|
19
|
+
* @param {(data: any) => void} [props.onChange] - Optional callback function triggered when the field value changes.
|
|
20
|
+
*
|
|
21
|
+
* @returns {JSX.Element} The rendered `FormField` component.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* const fieldConfig: FormFieldSchema = {
|
|
26
|
+
* name: "email",
|
|
27
|
+
* required: true,
|
|
28
|
+
* formFieldType: FormFieldType.INPUT,
|
|
29
|
+
* label: "Email",
|
|
30
|
+
* placeholder: "Enter your email",
|
|
31
|
+
* formFieldPattern: [FormFieldPatternsImpl.EMAIL],
|
|
32
|
+
* };
|
|
33
|
+
*
|
|
34
|
+
* <FormField fieldConfig={fieldConfig} onChange={handleFieldChange} />
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
const FormField: React.FC<FormFieldComponentPropSchema> = ({
|
|
38
|
+
fieldConfig,
|
|
39
|
+
onChange,
|
|
40
|
+
}: FormFieldComponentPropSchema) => {
|
|
41
|
+
let formContext = useContext(FormContext);
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
if (!fieldConfig.formFieldType) {
|
|
45
|
+
return <>Please provide formFieldType</>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Retrieve the component based on the formFieldType
|
|
49
|
+
const Component =
|
|
50
|
+
FormFieldComponents[FormFieldType[fieldConfig.formFieldType]].component;
|
|
51
|
+
|
|
52
|
+
return fieldConfig.wrapper ? (
|
|
53
|
+
<fieldConfig.wrapper>
|
|
54
|
+
<Component
|
|
55
|
+
{...{
|
|
56
|
+
fieldConfig: fieldConfig,
|
|
57
|
+
control: formContext.control,
|
|
58
|
+
register: formContext.register,
|
|
59
|
+
errors: formContext.errors,
|
|
60
|
+
}}
|
|
61
|
+
onChange={onChange}
|
|
62
|
+
/>
|
|
63
|
+
</fieldConfig.wrapper>
|
|
64
|
+
) : (
|
|
65
|
+
<Component
|
|
66
|
+
{...{
|
|
67
|
+
fieldConfig: fieldConfig,
|
|
68
|
+
control: formContext.control,
|
|
69
|
+
register: formContext.register,
|
|
70
|
+
errors: formContext.errors,
|
|
71
|
+
}}
|
|
72
|
+
onChange={onChange}
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return <div>Could not find input component</div>;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export default FormField;
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import ArrayField from "./formfields/ArrayField";
|
|
3
|
+
import { BusinessHoursField } from "./formfields/BusinessHoursField";
|
|
4
|
+
import CheckboxButtonField from "./formfields/CheckboxButtonsField";
|
|
5
|
+
import CheckboxField from "./formfields/CheckboxField";
|
|
6
|
+
import { ColorPickerField } from "./formfields/ColorPickerField";
|
|
7
|
+
import ComboMultiSelect from "./formfields/ComboMultiSelect";
|
|
8
|
+
import ComboSelect from "./formfields/ComboSelect";
|
|
9
|
+
import DatePicker from "./formfields/DatePickerField";
|
|
10
|
+
import DateRangePicker from "./formfields/DateRangePickerField";
|
|
11
|
+
import DynamicMultiSelect from "./formfields/DynamicMultiSelect";
|
|
12
|
+
import DynamicSelect from "./formfields/DynamicSelect";
|
|
13
|
+
import FileUploadField from "./formfields/FileUploadField";
|
|
14
|
+
import IframeField from "./formfields/IframeField";
|
|
15
|
+
import InputField from "./formfields/InputField";
|
|
16
|
+
import InputGroupField from "./formfields/InputGroupField";
|
|
17
|
+
import MultipleSelectField from "./formfields/MultipleSelectField";
|
|
18
|
+
import NumberField from "./formfields/NumberField";
|
|
19
|
+
import PasswordField from "./formfields/PasswordField";
|
|
20
|
+
import PhoneNumberField from "./formfields/PhoneNumberField";
|
|
21
|
+
import RadioField from "./formfields/RadioField";
|
|
22
|
+
import RadioGroupComponent from "./formfields/RadioGroupComponent";
|
|
23
|
+
import { RangeField } from "./formfields/RangeField";
|
|
24
|
+
import SelectField from "./formfields/SelectField";
|
|
25
|
+
import SwitchField from "./formfields/SwitchField";
|
|
26
|
+
import TextAreaField from "./formfields/TextAreaField";
|
|
27
|
+
import TimeField from "./formfields/TimeField";
|
|
28
|
+
import Typeahead from "./formfields/Typeahead";
|
|
29
|
+
import TypeaheadMultiSelect from "./formfields/TypeaheadMultiSelect";
|
|
30
|
+
import UrlField from "./formfields/UrlField";
|
|
31
|
+
import {
|
|
32
|
+
FieldOptionsSchema,
|
|
33
|
+
FormFieldComponentPropSchema,
|
|
34
|
+
FormFieldType,
|
|
35
|
+
OptionMappingConfig,
|
|
36
|
+
} from "./schema/FormFieldSchema";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @property {React.FC<FormFieldComponentPropSchema>} component - React component for a form field.
|
|
40
|
+
*/
|
|
41
|
+
interface FormComponentSchema {
|
|
42
|
+
[key: string]: {
|
|
43
|
+
component: React.FC<FormFieldComponentPropSchema>;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* An object mapping form field types to their respective components.
|
|
49
|
+
* @type {FormComponentSchema}
|
|
50
|
+
*/
|
|
51
|
+
const formFieldComponents: FormComponentSchema = {
|
|
52
|
+
[FormFieldType[FormFieldType.INPUT]]: {
|
|
53
|
+
component: InputField,
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
[FormFieldType[FormFieldType.URL]]: {
|
|
57
|
+
component: UrlField,
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
[FormFieldType[FormFieldType.NUMBER]]: {
|
|
61
|
+
component: NumberField,
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
[FormFieldType[FormFieldType.PASSWORD]]: {
|
|
65
|
+
component: PasswordField,
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
[FormFieldType[FormFieldType.TIME]]: {
|
|
69
|
+
component: TimeField,
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
[FormFieldType[FormFieldType.TEXTAREA]]: {
|
|
73
|
+
component: TextAreaField,
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
[FormFieldType[FormFieldType.RADIO]]: {
|
|
77
|
+
component: RadioField,
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
[FormFieldType[FormFieldType.RADIO_GROUP]]: {
|
|
81
|
+
component: RadioGroupComponent,
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
[FormFieldType[FormFieldType.CHECKBOX]]: {
|
|
85
|
+
component: CheckboxField,
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
[FormFieldType[FormFieldType.CHECKBOXBUTTONS]]: {
|
|
89
|
+
component: CheckboxButtonField,
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
[FormFieldType[FormFieldType.ARRAY]]: {
|
|
93
|
+
component: ArrayField,
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
[FormFieldType[FormFieldType.INPUT_GROUP]]: {
|
|
97
|
+
component: InputGroupField,
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
[FormFieldType[FormFieldType.RANGE]]: {
|
|
101
|
+
component: RangeField,
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
[FormFieldType[FormFieldType.COLOR_PICKER]]: {
|
|
105
|
+
component: ColorPickerField,
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
[FormFieldType[FormFieldType.FILE_UPLOAD]]: {
|
|
109
|
+
component: FileUploadField,
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
[FormFieldType[FormFieldType.DATE_PICKER]]: {
|
|
113
|
+
component: DatePicker,
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
[FormFieldType[FormFieldType.DATE_RANGE_PICKER]]: {
|
|
117
|
+
component: DateRangePicker,
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
[FormFieldType[FormFieldType.SWITCH]]: {
|
|
121
|
+
component: SwitchField,
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
[FormFieldType[FormFieldType.SELECT]]: {
|
|
125
|
+
component: SelectField,
|
|
126
|
+
},
|
|
127
|
+
[FormFieldType[FormFieldType.MULTI_SELECT]]: {
|
|
128
|
+
component: MultipleSelectField,
|
|
129
|
+
},
|
|
130
|
+
[FormFieldType[FormFieldType.DYNAMIC_SELECT]]: {
|
|
131
|
+
component: DynamicSelect,
|
|
132
|
+
},
|
|
133
|
+
[FormFieldType[FormFieldType.DYNAMIC_MULTI_SELECT]]: {
|
|
134
|
+
component: DynamicMultiSelect,
|
|
135
|
+
},
|
|
136
|
+
[FormFieldType[FormFieldType.TYPEAHEAD]]: {
|
|
137
|
+
component: Typeahead,
|
|
138
|
+
},
|
|
139
|
+
[FormFieldType[FormFieldType.TYPEAHEAD_MULTI_SELECT]]: {
|
|
140
|
+
component: TypeaheadMultiSelect,
|
|
141
|
+
},
|
|
142
|
+
[FormFieldType[FormFieldType.COMBO_SELECT]]: {
|
|
143
|
+
component: ComboSelect,
|
|
144
|
+
},
|
|
145
|
+
[FormFieldType[FormFieldType.COMBO_MULTI_SELECT]]: {
|
|
146
|
+
component: ComboMultiSelect,
|
|
147
|
+
},
|
|
148
|
+
[FormFieldType[FormFieldType.BUSINESS_HOURS]]: {
|
|
149
|
+
component: BusinessHoursField,
|
|
150
|
+
},
|
|
151
|
+
[FormFieldType[FormFieldType.PHONE_NUMBER_INPUT]]: {
|
|
152
|
+
component: PhoneNumberField,
|
|
153
|
+
},
|
|
154
|
+
[FormFieldType[FormFieldType.IFRAME]]: {
|
|
155
|
+
component: IframeField,
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export default { ...formFieldComponents };
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Retrieves a nested value from an object based on a dot-separated path.
|
|
163
|
+
* @param {Object} obj - The object to retrieve the value from.
|
|
164
|
+
* @param {string} [path] - Dot-separated path of the property.
|
|
165
|
+
* @returns {*} - The value at the specified path, or undefined if not found.
|
|
166
|
+
*/
|
|
167
|
+
const getNestedValue = (obj: any, path: string | undefined): any => {
|
|
168
|
+
if (!path) return undefined;
|
|
169
|
+
return path.split(".").reduce((acc, part) => acc && acc[part], obj);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Maps data to a list of options based on the fieldOptionConfig.
|
|
174
|
+
* @param {Object} data - The data to be mapped to options.
|
|
175
|
+
* @param {OptionMappingConfig} [fieldOptionConfig] - Configuration for mapping options.
|
|
176
|
+
* @returns {FieldOptionsSchema[]} - A list of field options.
|
|
177
|
+
*/
|
|
178
|
+
export const getListOptions = (
|
|
179
|
+
data: any,
|
|
180
|
+
fieldOptionConfig?: OptionMappingConfig
|
|
181
|
+
): FieldOptionsSchema[] => {
|
|
182
|
+
let keys: any = fieldOptionConfig && fieldOptionConfig.listItemKey;
|
|
183
|
+
if (keys && keys.indexOf(".") > -1) {
|
|
184
|
+
keys = keys.split(".");
|
|
185
|
+
}
|
|
186
|
+
if (keys) {
|
|
187
|
+
if (Array.isArray(keys)) {
|
|
188
|
+
for (const key of keys) {
|
|
189
|
+
data = data[key];
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
data = data[keys];
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
let output;
|
|
196
|
+
if (fieldOptionConfig) {
|
|
197
|
+
output = data.map((item: { [x: string]: any }) => {
|
|
198
|
+
return {
|
|
199
|
+
label: getNestedValue(item, fieldOptionConfig.labelKey),
|
|
200
|
+
value: getNestedValue(item, fieldOptionConfig.valueKey),
|
|
201
|
+
groupName:
|
|
202
|
+
fieldOptionConfig?.groupKey &&
|
|
203
|
+
item[fieldOptionConfig?.groupKey],
|
|
204
|
+
isDisabled:
|
|
205
|
+
fieldOptionConfig?.disabledKey &&
|
|
206
|
+
item[fieldOptionConfig?.disabledKey],
|
|
207
|
+
};
|
|
208
|
+
});
|
|
209
|
+
} else {
|
|
210
|
+
output = data.map((item: any) => {
|
|
211
|
+
return {
|
|
212
|
+
label: item,
|
|
213
|
+
value: item,
|
|
214
|
+
};
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
return output;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
export const getListOption = (
|
|
221
|
+
data: any,
|
|
222
|
+
fieldOptionConfig?: OptionMappingConfig
|
|
223
|
+
): FieldOptionsSchema => {
|
|
224
|
+
if (fieldOptionConfig) {
|
|
225
|
+
return {
|
|
226
|
+
label: getNestedValue(data, fieldOptionConfig.labelKey),
|
|
227
|
+
value: getNestedValue(data, fieldOptionConfig.valueKey),
|
|
228
|
+
groupName:
|
|
229
|
+
fieldOptionConfig?.groupKey &&
|
|
230
|
+
data[fieldOptionConfig?.groupKey],
|
|
231
|
+
isDisabled:
|
|
232
|
+
fieldOptionConfig?.disabledKey &&
|
|
233
|
+
data[fieldOptionConfig?.disabledKey],
|
|
234
|
+
};
|
|
235
|
+
} else {
|
|
236
|
+
return {
|
|
237
|
+
label: data,
|
|
238
|
+
value: data,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
};
|