@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
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { useContext } from "react";
|
|
2
|
+
import { FormContext } from "./context/FormContext";
|
|
3
|
+
import FormField from "./FormField";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* FormFields Component
|
|
7
|
+
*
|
|
8
|
+
* The FormFields component maps over a list of field names and renders
|
|
9
|
+
* corresponding FormField components based on the provided form context.
|
|
10
|
+
*
|
|
11
|
+
* @param {Object} props - The component props.
|
|
12
|
+
* @param {string[]} props.fields - An array of field names to render.
|
|
13
|
+
* @returns {JSX.Element} The rendered FormFields component.
|
|
14
|
+
*/
|
|
15
|
+
export default function FormFields({
|
|
16
|
+
fields,
|
|
17
|
+
}: {
|
|
18
|
+
fields: string[];
|
|
19
|
+
}): JSX.Element {
|
|
20
|
+
// Get context from FormContext
|
|
21
|
+
let formContext = useContext(FormContext);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
{/* Map over the field names and render FormField components */}
|
|
26
|
+
{fields.map((fieldName, index) => {
|
|
27
|
+
// Find the field configuration from the form context
|
|
28
|
+
let fieldConfig = formContext.formFields.find((fieldInfo) => {
|
|
29
|
+
return fieldInfo.name == fieldName;
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Render the FormField component if fieldConfig is found, else render an empty fragment
|
|
33
|
+
return fieldConfig ? (
|
|
34
|
+
<FormField key={index} fieldConfig={fieldConfig} />
|
|
35
|
+
) : (
|
|
36
|
+
<></>
|
|
37
|
+
);
|
|
38
|
+
})}
|
|
39
|
+
</>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createContext } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Control,
|
|
4
|
+
FieldErrors,
|
|
5
|
+
UseFormClearErrors,
|
|
6
|
+
UseFormGetFieldState,
|
|
7
|
+
UseFormGetValues,
|
|
8
|
+
UseFormHandleSubmit,
|
|
9
|
+
UseFormRegister,
|
|
10
|
+
UseFormReset,
|
|
11
|
+
UseFormResetField,
|
|
12
|
+
UseFormSetError,
|
|
13
|
+
UseFormSetFocus,
|
|
14
|
+
UseFormSetValue,
|
|
15
|
+
UseFormTrigger,
|
|
16
|
+
UseFormUnregister,
|
|
17
|
+
UseFormWatch,
|
|
18
|
+
} from "react-hook-form";
|
|
19
|
+
import { FormFieldSchema } from "../schema/FormFieldSchema";
|
|
20
|
+
|
|
21
|
+
export interface FormContextType {
|
|
22
|
+
formFields: FormFieldSchema[];
|
|
23
|
+
onSubmit?: (e?: any) => void;
|
|
24
|
+
register: UseFormRegister<any>;
|
|
25
|
+
control?: Control<any, any>;
|
|
26
|
+
setValue: UseFormSetValue<any>;
|
|
27
|
+
errors?: FieldErrors<any>;
|
|
28
|
+
getValues: UseFormGetValues<any>;
|
|
29
|
+
reset: UseFormReset<any>;
|
|
30
|
+
watch: UseFormWatch<any>;
|
|
31
|
+
// updateField: (context: any) => void
|
|
32
|
+
// getValues?: UseFormGetValues<TFieldValues>;
|
|
33
|
+
getFieldState: UseFormGetFieldState<any>;
|
|
34
|
+
setError: UseFormSetError<any>;
|
|
35
|
+
clearErrors?: UseFormClearErrors<any>;
|
|
36
|
+
// setValue: UseFormSetValue<TFieldValues>;
|
|
37
|
+
trigger: UseFormTrigger<any>;
|
|
38
|
+
// formState: FormState<TFieldValues>;
|
|
39
|
+
resetField: UseFormResetField<any>;
|
|
40
|
+
// reset: UseFormReset<TFieldValues>;
|
|
41
|
+
handleSubmit?: UseFormHandleSubmit<any, any>;
|
|
42
|
+
unregister: UseFormUnregister<any>;
|
|
43
|
+
// control: Control<TFieldValues, TContext>;
|
|
44
|
+
// register: UseFormRegister<TFieldValues>;
|
|
45
|
+
setFocus: UseFormSetFocus<any>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const FormContext = createContext({
|
|
49
|
+
formFields: [],
|
|
50
|
+
// onSubmit: (undefined) => void,
|
|
51
|
+
register: {} as UseFormRegister<{}>,
|
|
52
|
+
getValues: {} as UseFormGetValues<{}>,
|
|
53
|
+
setValue: {} as UseFormSetValue<any>,
|
|
54
|
+
watch: {} as UseFormWatch<any>,
|
|
55
|
+
reset: {} as UseFormReset<any>,
|
|
56
|
+
resetField: {} as UseFormResetField<any>,
|
|
57
|
+
getFieldState: {} as UseFormGetFieldState<any>,
|
|
58
|
+
setError: {} as UseFormSetError<any>,
|
|
59
|
+
unregister: {} as UseFormUnregister<any>,
|
|
60
|
+
// updateField: (context: any) => { },
|
|
61
|
+
// control: undefined,
|
|
62
|
+
// setValue: [],
|
|
63
|
+
setFocus: {} as UseFormSetFocus<any>,
|
|
64
|
+
trigger: {} as UseFormTrigger<any>,
|
|
65
|
+
// errors: []
|
|
66
|
+
} as FormContextType);
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { useContext, useEffect } from "react";
|
|
2
|
+
import { FieldArrayMethodProps, FieldValues, useFieldArray, UseFieldArrayAppend, UseFieldArrayPrepend, UseFieldArrayRemove } from "react-hook-form";
|
|
3
|
+
import FormField from "../FormField";
|
|
4
|
+
import { FormContext } from "../context/FormContext";
|
|
5
|
+
import { FormFieldComponentPropSchema } from "../schema/FormFieldSchema";
|
|
6
|
+
import React from "react";
|
|
7
|
+
|
|
8
|
+
const ArrayField: React.FC<FormFieldComponentPropSchema> = ({
|
|
9
|
+
fieldConfig,
|
|
10
|
+
}: FormFieldComponentPropSchema) => {
|
|
11
|
+
let {
|
|
12
|
+
formFields,
|
|
13
|
+
getFieldState,
|
|
14
|
+
getValues,
|
|
15
|
+
register,
|
|
16
|
+
reset,
|
|
17
|
+
resetField,
|
|
18
|
+
setError,
|
|
19
|
+
setFocus,
|
|
20
|
+
setValue,
|
|
21
|
+
trigger,
|
|
22
|
+
unregister,
|
|
23
|
+
watch,
|
|
24
|
+
clearErrors,
|
|
25
|
+
control,
|
|
26
|
+
errors,
|
|
27
|
+
onSubmit,
|
|
28
|
+
} = useContext(FormContext);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if(fieldConfig.defaultValue && !getValues(fieldConfig.name)){
|
|
31
|
+
append(fieldConfig.defaultValue);
|
|
32
|
+
}
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
35
|
+
const { fields, append, prepend, remove, swap, move, insert, replace } =
|
|
36
|
+
useFieldArray({
|
|
37
|
+
control: control,
|
|
38
|
+
name: fieldConfig.name,
|
|
39
|
+
rules: {
|
|
40
|
+
minLength: fieldConfig.minLength,
|
|
41
|
+
maxLength: fieldConfig.maxLength,
|
|
42
|
+
required: fieldConfig.required,
|
|
43
|
+
validate: fieldConfig.formFieldPattern
|
|
44
|
+
? fieldConfig?.formFieldPattern[0].getValidate()
|
|
45
|
+
: null,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const removeField: UseFieldArrayRemove = (
|
|
50
|
+
index: number | number[] | undefined
|
|
51
|
+
) => {
|
|
52
|
+
remove(index);
|
|
53
|
+
reset(getValues());
|
|
54
|
+
|
|
55
|
+
if (fieldConfig.submitOnChange) {
|
|
56
|
+
onSubmit && onSubmit();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const appendField: UseFieldArrayAppend<any> = (
|
|
61
|
+
value,
|
|
62
|
+
options?: FieldArrayMethodProps
|
|
63
|
+
) => {
|
|
64
|
+
append(value, options);
|
|
65
|
+
reset(getValues());
|
|
66
|
+
|
|
67
|
+
if (fieldConfig.submitOnChange) {
|
|
68
|
+
onSubmit && onSubmit();
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const prependField: UseFieldArrayPrepend<any> = (
|
|
73
|
+
value,
|
|
74
|
+
options?: FieldArrayMethodProps
|
|
75
|
+
) => {
|
|
76
|
+
prepend(value, options);
|
|
77
|
+
reset(getValues());
|
|
78
|
+
|
|
79
|
+
if (fieldConfig.submitOnChange) {
|
|
80
|
+
onSubmit && onSubmit();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const getObjectField = (objectIndex: number) => {
|
|
85
|
+
return fieldConfig.children?.map((child) => {
|
|
86
|
+
let childConfig = { ...child };
|
|
87
|
+
childConfig.name =
|
|
88
|
+
fieldConfig.name + "." + objectIndex + "." + child.name;
|
|
89
|
+
|
|
90
|
+
return <FormField fieldConfig={childConfig}></FormField>;
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const childByFieldName = (
|
|
95
|
+
objectIndex: number,
|
|
96
|
+
fieldName: string,
|
|
97
|
+
mapperType?: string
|
|
98
|
+
) => {
|
|
99
|
+
if (!fieldConfig.children || fieldConfig.children.length == 0)
|
|
100
|
+
return null;
|
|
101
|
+
|
|
102
|
+
for (const child of fieldConfig.children) {
|
|
103
|
+
if (
|
|
104
|
+
(mapperType &&
|
|
105
|
+
child.name == fieldName &&
|
|
106
|
+
child.mapperType == mapperType) ||
|
|
107
|
+
(!mapperType && child.name == fieldName)
|
|
108
|
+
) {
|
|
109
|
+
let childConfig = { ...child };
|
|
110
|
+
childConfig.name =
|
|
111
|
+
fieldConfig.name + "." + objectIndex + "." + child.name;
|
|
112
|
+
return <FormField fieldConfig={childConfig}></FormField>;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const getArrayfields = () => {
|
|
119
|
+
return (
|
|
120
|
+
fields &&
|
|
121
|
+
fields.map((field, index) => {
|
|
122
|
+
return fieldConfig.arrayIndexWrapper ? (
|
|
123
|
+
<fieldConfig.arrayIndexWrapper
|
|
124
|
+
key={field.id}
|
|
125
|
+
{...{
|
|
126
|
+
append: appendField,
|
|
127
|
+
prepend: prependField,
|
|
128
|
+
remove: removeField,
|
|
129
|
+
index,
|
|
130
|
+
getValues,
|
|
131
|
+
setValue,
|
|
132
|
+
length: fields.length,
|
|
133
|
+
mappedName: fieldConfig.name + "." + index,
|
|
134
|
+
childByFieldName: (
|
|
135
|
+
fieldName: string,
|
|
136
|
+
mapperType?: string
|
|
137
|
+
) => {
|
|
138
|
+
let field = childByFieldName(
|
|
139
|
+
index,
|
|
140
|
+
fieldName,
|
|
141
|
+
mapperType
|
|
142
|
+
);
|
|
143
|
+
return field ? field : <span></span>;
|
|
144
|
+
},
|
|
145
|
+
}}>
|
|
146
|
+
{getObjectField(index)}
|
|
147
|
+
</fieldConfig.arrayIndexWrapper>
|
|
148
|
+
) : (
|
|
149
|
+
<div key={field.id}>{getObjectField(index)}</div>
|
|
150
|
+
);
|
|
151
|
+
})
|
|
152
|
+
);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
return fieldConfig.arrayWrapper ? (
|
|
156
|
+
<fieldConfig.arrayWrapper
|
|
157
|
+
{...{
|
|
158
|
+
append,
|
|
159
|
+
prepend,
|
|
160
|
+
remove,
|
|
161
|
+
getValues: getValues,
|
|
162
|
+
}}>
|
|
163
|
+
{getArrayfields()}
|
|
164
|
+
</fieldConfig.arrayWrapper>
|
|
165
|
+
) : (
|
|
166
|
+
<>{getArrayfields()}</>
|
|
167
|
+
);
|
|
168
|
+
};
|
|
169
|
+
export default ArrayField;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FieldAlignType,
|
|
3
|
+
FieldOptionsSchema,
|
|
4
|
+
FormFieldComponentPropSchema,
|
|
5
|
+
FormFieldSchema,
|
|
6
|
+
FormFieldType
|
|
7
|
+
} from "../schema/FormFieldSchema";
|
|
8
|
+
import React, {useCallback, useContext, useEffect, useMemo, useState} from "react";
|
|
9
|
+
import {FormContext} from "../context/FormContext";
|
|
10
|
+
import {RegisterOptions} from "react-hook-form";
|
|
11
|
+
import {convertToTitleCase, registerFormField} from "../util";
|
|
12
|
+
import axios from "axios";
|
|
13
|
+
import {reachoAPI} from "../../api";
|
|
14
|
+
import SwitchField from "./SwitchField";
|
|
15
|
+
import FormField from "../FormField";
|
|
16
|
+
import RenderFormField from "../util/RenderFormField";
|
|
17
|
+
import {TrashIcon, XMarkIcon} from "@heroicons/react/24/outline";
|
|
18
|
+
import Tippy from "@tippyjs/react";
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
export const BusinessHoursField: React.FC<FormFieldComponentPropSchema> = (props: FormFieldComponentPropSchema) => {
|
|
22
|
+
const formContext = useContext(FormContext);
|
|
23
|
+
const [listOptions, setListOptions] = useState<any[]>([]);
|
|
24
|
+
const [loading, setLoading] = useState<boolean>(false);
|
|
25
|
+
|
|
26
|
+
let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
|
|
27
|
+
const hookProps = useMemo(() => formContext.register(props.fieldConfig.name, registerOptions), [formContext, props.fieldConfig.name, registerOptions]);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
fetchData();
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
const getTimeConfig = (mappedName: string): FormFieldSchema => {
|
|
34
|
+
return {
|
|
35
|
+
required: true,
|
|
36
|
+
name: mappedName + ".sessions",
|
|
37
|
+
wrapper: ({children}) => {
|
|
38
|
+
return <div style={{border: '1px sold #ddd', padding: '0px'}}>{children}</div>;
|
|
39
|
+
},
|
|
40
|
+
arrayWrapper: ({children, append,getValues}) => {
|
|
41
|
+
return (
|
|
42
|
+
<>
|
|
43
|
+
<div style={{border: '1px sold #ddd',}}>
|
|
44
|
+
{children}
|
|
45
|
+
</div>
|
|
46
|
+
<div className='w-full sm:w-full text-end mr-[2.3em]'>
|
|
47
|
+
<button type='button' className={`text-end text-primary cursor-pointer font-[13px] font-medium ${getValues(`${mappedName}.sessions`)?.length > 1 ? "mr-9" : ''}`}
|
|
48
|
+
onClick={() => {
|
|
49
|
+
const lastEndTime = getValues(`${mappedName}.sessions`)?.[getValues(`${mappedName}.sessions`).length - 1]?.endTime || '08:30';
|
|
50
|
+
|
|
51
|
+
const newStartTime = lastEndTime; // Start new session at last session's end time
|
|
52
|
+
const newEndTime = "23:00"; // Calculate end time, but cap at 23:00
|
|
53
|
+
|
|
54
|
+
append({
|
|
55
|
+
startTime: newStartTime,
|
|
56
|
+
endTime: newEndTime,
|
|
57
|
+
});
|
|
58
|
+
}}
|
|
59
|
+
>
|
|
60
|
+
+ Add
|
|
61
|
+
</button>
|
|
62
|
+
</div>
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
},
|
|
66
|
+
arrayIndexWrapper: ({
|
|
67
|
+
mappedName,
|
|
68
|
+
getValues,
|
|
69
|
+
children,
|
|
70
|
+
childByFieldName,
|
|
71
|
+
append,
|
|
72
|
+
prepend,
|
|
73
|
+
remove,
|
|
74
|
+
index
|
|
75
|
+
}) => {
|
|
76
|
+
return (
|
|
77
|
+
<div className="flex items-center gap-4 form-group !mb-2">
|
|
78
|
+
<div>{childByFieldName('startTime')}</div>
|
|
79
|
+
<p>To</p>
|
|
80
|
+
<div>{childByFieldName('endTime')}</div>
|
|
81
|
+
{index > 0 ?
|
|
82
|
+
<button
|
|
83
|
+
className="Button__StyledButton-sc-1l1v2a6-0 gVdTUT"
|
|
84
|
+
type="button"
|
|
85
|
+
onClick={() => {
|
|
86
|
+
remove(index);
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
{/* <TrashIcon height={18} width={18} className=""/> */}
|
|
90
|
+
<Tippy content="Delete">
|
|
91
|
+
<XMarkIcon aria-hidden="true" height={18} width={18} className="" />
|
|
92
|
+
</Tippy>
|
|
93
|
+
|
|
94
|
+
</button> : <></>}
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
);
|
|
98
|
+
},
|
|
99
|
+
formFieldType: FormFieldType.ARRAY,
|
|
100
|
+
align: FieldAlignType.HORIZONTAL,
|
|
101
|
+
disableDefaultWrapper: true,
|
|
102
|
+
defaultValue: {
|
|
103
|
+
startTime: "08:30",
|
|
104
|
+
endTime: "18:00"
|
|
105
|
+
},
|
|
106
|
+
children: [
|
|
107
|
+
{
|
|
108
|
+
required: false,
|
|
109
|
+
formFieldType: FormFieldType.TIME,
|
|
110
|
+
name: "startTime",
|
|
111
|
+
disableDefaultWrapper:true,
|
|
112
|
+
defaultValue: "08:30",
|
|
113
|
+
customClassNames: {
|
|
114
|
+
fieldClassName: "border-none bg-blue-100",
|
|
115
|
+
},
|
|
116
|
+
}, {
|
|
117
|
+
required: false,
|
|
118
|
+
formFieldType: FormFieldType.TIME,
|
|
119
|
+
name: "endTime",
|
|
120
|
+
disableDefaultWrapper: true,
|
|
121
|
+
defaultValue: "18:00",
|
|
122
|
+
customClassNames: {
|
|
123
|
+
fieldClassName: "border-none bg-blue-100",
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
;
|
|
130
|
+
|
|
131
|
+
const fetchData = useCallback(async () => {
|
|
132
|
+
setLoading(true);
|
|
133
|
+
// if (!props.fieldConfig.fetchUrl) return;
|
|
134
|
+
let url = "/api/core/user-prefs/get-default-business-days";
|
|
135
|
+
if (props.fieldConfig.fetchUrl) {
|
|
136
|
+
url = props.fieldConfig.fetchUrl;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
let response = await (props.fieldConfig.disableHeaderInFetch
|
|
140
|
+
? axios.get(url)
|
|
141
|
+
: reachoAPI.get(url));
|
|
142
|
+
|
|
143
|
+
if (response.data) {
|
|
144
|
+
const data: FieldOptionsSchema[] = response.data;
|
|
145
|
+
setListOptions(data);
|
|
146
|
+
setLoading(false);
|
|
147
|
+
|
|
148
|
+
if (props.fieldConfig.fetchCallback) {
|
|
149
|
+
props.fieldConfig.fetchCallback(response);
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
console.error(response.statusText);
|
|
153
|
+
setLoading(false);
|
|
154
|
+
}
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error('Fetch error:', error);
|
|
157
|
+
setLoading(false);
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
[props.fieldConfig.fetchUrl, props.fieldConfig.optionsConfig, props.fieldConfig.fetchCallback, props.fieldConfig.disableHeaderInFetch]
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
function getInput() {
|
|
164
|
+
return <>
|
|
165
|
+
{loading?<></>:
|
|
166
|
+
listOptions && Object.keys(listOptions).map((day) => {
|
|
167
|
+
const dayInfo = listOptions[day as any];
|
|
168
|
+
return (
|
|
169
|
+
<>
|
|
170
|
+
<div className="flex baseline mb-6" data-testid="" key={day}>
|
|
171
|
+
<div className="max-w-sm space-y-2">
|
|
172
|
+
<div
|
|
173
|
+
className="group flex items-center w-full gap-x-2 text-sm font-normal leading-none text-gray-700 mt-3">
|
|
174
|
+
<SwitchField fieldConfig={{
|
|
175
|
+
name: props.fieldConfig.name + "." + day + ".enabledDay",
|
|
176
|
+
defaultValue: dayInfo.enabledDay,
|
|
177
|
+
required: false,
|
|
178
|
+
formFieldType: FormFieldType.SWITCH,
|
|
179
|
+
disableDefaultWrapper: true,
|
|
180
|
+
customClassNames: {
|
|
181
|
+
fieldClassName: "!mb-0",
|
|
182
|
+
},
|
|
183
|
+
}}/>
|
|
184
|
+
<p className="flex justify-between border-gray-900 text-sm text-gray-900 font-medium ml-2 w-24 leading-none">
|
|
185
|
+
<span className="w-full">{convertToTitleCase(day)}</span>
|
|
186
|
+
</p>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
|
|
190
|
+
<div className=" flex items-center text-gray-500 focus-within:text-blue-500">
|
|
191
|
+
<FormField fieldConfig={getTimeConfig(props.fieldConfig.name + "." + day)}/>
|
|
192
|
+
</div>
|
|
193
|
+
</div>
|
|
194
|
+
</>
|
|
195
|
+
);
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
</>
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<RenderFormField fieldConfig={props.fieldConfig} getInput={getInput}/>
|
|
203
|
+
);
|
|
204
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { RegisterOptions } from "react-hook-form";
|
|
2
|
+
import { useContext } from "react";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { FormContext } from "../context/FormContext";
|
|
5
|
+
import {
|
|
6
|
+
FormFieldComponentPropSchema,
|
|
7
|
+
FormFieldPatternsImpl,
|
|
8
|
+
} from "../schema/FormFieldSchema";
|
|
9
|
+
import { Field, Label } from "@headlessui/react";
|
|
10
|
+
import RenderFormField from "../util/RenderFormField";
|
|
11
|
+
|
|
12
|
+
const CheckboxButtonField: React.FC<FormFieldComponentPropSchema> = (
|
|
13
|
+
props: FormFieldComponentPropSchema
|
|
14
|
+
) => {
|
|
15
|
+
const formContext = useContext(FormContext);
|
|
16
|
+
|
|
17
|
+
let registerOptions: RegisterOptions = {
|
|
18
|
+
required: props.fieldConfig.required
|
|
19
|
+
? FormFieldPatternsImpl.REQUIRED.getMessage()
|
|
20
|
+
: false,
|
|
21
|
+
};
|
|
22
|
+
if (props.fieldConfig?.formFieldPattern) {
|
|
23
|
+
registerOptions.pattern =
|
|
24
|
+
props.fieldConfig?.formFieldPattern[0].getPattern();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let hookProps = formContext.register(
|
|
28
|
+
props.fieldConfig.name,
|
|
29
|
+
registerOptions
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const handleChange = (value: boolean) => {
|
|
33
|
+
formContext.setValue(props.fieldConfig?.name, value, {
|
|
34
|
+
shouldValidate: true,
|
|
35
|
+
shouldDirty: formContext.getFieldState(props.fieldConfig.name)
|
|
36
|
+
.isDirty,
|
|
37
|
+
shouldTouch: formContext.getFieldState(props.fieldConfig.name)
|
|
38
|
+
.isTouched,
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function getInput() {
|
|
43
|
+
return props.fieldConfig.options ? (
|
|
44
|
+
props.fieldConfig.options.map((option) => {
|
|
45
|
+
return (
|
|
46
|
+
<Field
|
|
47
|
+
className={
|
|
48
|
+
props.fieldConfig.customClassNames?.fieldClassName
|
|
49
|
+
? "checkbox-inline" +
|
|
50
|
+
props.fieldConfig.customClassNames
|
|
51
|
+
?.fieldClassName
|
|
52
|
+
: "checkbox-inline"
|
|
53
|
+
}>
|
|
54
|
+
<Label className="text-capitalize checkbox checkbox-primary">
|
|
55
|
+
<input
|
|
56
|
+
{...hookProps}
|
|
57
|
+
name={props.fieldConfig.name}
|
|
58
|
+
type="checkbox"
|
|
59
|
+
value={option.value}
|
|
60
|
+
data-do-not-deserialize="true"
|
|
61
|
+
/>
|
|
62
|
+
{/* <span className="text-capitalize"> </span>{" "} */}
|
|
63
|
+
{option.label}
|
|
64
|
+
</Label>
|
|
65
|
+
</Field>
|
|
66
|
+
);
|
|
67
|
+
})
|
|
68
|
+
) : (
|
|
69
|
+
<>
|
|
70
|
+
<Field className="be-checkbox">
|
|
71
|
+
<Label
|
|
72
|
+
className="checkbox checkbox-primary flex"
|
|
73
|
+
style={{ width: "fit-content" }}>
|
|
74
|
+
<input
|
|
75
|
+
{...hookProps}
|
|
76
|
+
className="form-checkbox"
|
|
77
|
+
type="checkbox"
|
|
78
|
+
// defaultValue={props.fieldConfig.defaultValue}
|
|
79
|
+
value={formContext.getValues(
|
|
80
|
+
props.fieldConfig.name
|
|
81
|
+
)}
|
|
82
|
+
onChange={(e) => handleChange(e.target.checked)}
|
|
83
|
+
/>
|
|
84
|
+
<Label className="form-check-label ms-1">
|
|
85
|
+
{props.fieldConfig.label}
|
|
86
|
+
</Label>
|
|
87
|
+
</Label>
|
|
88
|
+
</Field>
|
|
89
|
+
</>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return (
|
|
93
|
+
<RenderFormField fieldConfig={props.fieldConfig} getInput={getInput} />
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export default CheckboxButtonField;
|