@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,82 @@
|
|
|
1
|
+
import React, {useContext, useEffect, useRef, useState,} from "react";
|
|
2
|
+
|
|
3
|
+
import {RegisterOptions} from "react-hook-form";
|
|
4
|
+
|
|
5
|
+
import {FieldOptionsSchema, FormFieldComponentPropSchema, FormFieldType,} from "../schema/FormFieldSchema";
|
|
6
|
+
import {FormContext} from "../context/FormContext";
|
|
7
|
+
import {Listbox, ListboxButton,} from "@headlessui/react";
|
|
8
|
+
import RenderFormField from "../util/RenderFormField";
|
|
9
|
+
import RenderListOptions, {renderListBoxValue,} from "../util/RenderListOptions";
|
|
10
|
+
import {handleChange, registerFormField} from "../util";
|
|
11
|
+
|
|
12
|
+
const SelectField: React.FC<FormFieldComponentPropSchema> = ({
|
|
13
|
+
fieldConfig,
|
|
14
|
+
onChange,
|
|
15
|
+
}: FormFieldComponentPropSchema) => {
|
|
16
|
+
const selectRef = useRef<HTMLUListElement>(null);
|
|
17
|
+
const formContext = useContext(FormContext);
|
|
18
|
+
const [listOptions, setListOptions] = useState<FieldOptionsSchema[]>(
|
|
19
|
+
fieldConfig.options ? fieldConfig.options : []
|
|
20
|
+
);
|
|
21
|
+
let registerOptions: RegisterOptions = registerFormField(fieldConfig);
|
|
22
|
+
|
|
23
|
+
let hookProps = formContext.register(fieldConfig.name, registerOptions);
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (
|
|
27
|
+
(fieldConfig.options && fieldConfig.options.length > 0) ||
|
|
28
|
+
(fieldConfig.forceUpdate && fieldConfig.options)
|
|
29
|
+
) {
|
|
30
|
+
setListOptions(fieldConfig.options);
|
|
31
|
+
}
|
|
32
|
+
if (!formContext.getValues(fieldConfig.name) && fieldConfig.defaultValue) {
|
|
33
|
+
formContext.setValue(fieldConfig.name, fieldConfig.defaultValue);
|
|
34
|
+
}
|
|
35
|
+
}, [fieldConfig.options, fieldConfig.forceUpdate]);
|
|
36
|
+
|
|
37
|
+
function getInput() {
|
|
38
|
+
return (
|
|
39
|
+
<Listbox
|
|
40
|
+
as={"div"}
|
|
41
|
+
{...hookProps}
|
|
42
|
+
value={formContext.getValues(fieldConfig.name)}
|
|
43
|
+
defaultValue={fieldConfig.defaultValue}
|
|
44
|
+
onChange={(val) => {
|
|
45
|
+
const currentValue = formContext.getValues(fieldConfig.name);
|
|
46
|
+
|
|
47
|
+
// If the value matches, set it to null, otherwise set it to val
|
|
48
|
+
const newValue = currentValue === val ? null : val;
|
|
49
|
+
|
|
50
|
+
handleChange(newValue, formContext, fieldConfig, onChange);
|
|
51
|
+
}}
|
|
52
|
+
disabled={fieldConfig.disabled}
|
|
53
|
+
className={"relative form-listbox flex-1"}>
|
|
54
|
+
<ListboxButton
|
|
55
|
+
className={
|
|
56
|
+
fieldConfig.customClassNames?.fieldClassName
|
|
57
|
+
? "form-listbox-select " +
|
|
58
|
+
fieldConfig.customClassNames?.fieldClassName
|
|
59
|
+
: "form-listbox-select"
|
|
60
|
+
}>
|
|
61
|
+
{renderListBoxValue(
|
|
62
|
+
formContext,
|
|
63
|
+
fieldConfig,
|
|
64
|
+
listOptions,
|
|
65
|
+
onChange
|
|
66
|
+
)}
|
|
67
|
+
</ListboxButton>
|
|
68
|
+
<RenderListOptions
|
|
69
|
+
ref={selectRef}
|
|
70
|
+
fieldConfig={fieldConfig}
|
|
71
|
+
formContext={formContext}
|
|
72
|
+
formField={FormFieldType.SELECT}
|
|
73
|
+
listOptions={listOptions}
|
|
74
|
+
setListOptions={setListOptions}
|
|
75
|
+
/>
|
|
76
|
+
</Listbox>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return <RenderFormField fieldConfig={fieldConfig} getInput={getInput}/>;
|
|
81
|
+
};
|
|
82
|
+
export default SelectField;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {Switch} from '@headlessui/react';
|
|
2
|
+
import React, {Fragment, useContext, useEffect, useState} from 'react';
|
|
3
|
+
import {RegisterOptions} from "react-hook-form";
|
|
4
|
+
import {FormContext} from "../context/FormContext";
|
|
5
|
+
import {FormFieldComponentPropSchema} from "../schema/FormFieldSchema";
|
|
6
|
+
import RenderFormField from "../util/RenderFormField";
|
|
7
|
+
import {handleChange, registerFormField} from "../util";
|
|
8
|
+
import XMarkIcon from "@heroicons/react/20/solid/XMarkIcon";
|
|
9
|
+
import CheckIcon from "@heroicons/react/20/solid/CheckIcon";
|
|
10
|
+
import clsx from 'clsx';
|
|
11
|
+
|
|
12
|
+
const SwitchField: React.FC<FormFieldComponentPropSchema> = (props) => {
|
|
13
|
+
const formContext = useContext(FormContext);
|
|
14
|
+
|
|
15
|
+
const [enabled, setEnabled] = useState<boolean>(
|
|
16
|
+
formContext.getValues(props.fieldConfig.name) ?? false
|
|
17
|
+
);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (props.fieldConfig.defaultValue && formContext.getValues(props.fieldConfig.name)==null || undefined) {
|
|
20
|
+
|
|
21
|
+
formContext.setValue(props.fieldConfig.name, props.fieldConfig.defaultValue);
|
|
22
|
+
setEnabled(props.fieldConfig.defaultValue);
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
}, []);
|
|
26
|
+
|
|
27
|
+
let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
|
|
28
|
+
|
|
29
|
+
let hookProps = formContext.register(
|
|
30
|
+
props.fieldConfig.name,
|
|
31
|
+
registerOptions
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
function getInput() {
|
|
35
|
+
return (
|
|
36
|
+
<Switch
|
|
37
|
+
defaultChecked={props.fieldConfig.defaultValue as boolean}
|
|
38
|
+
{...hookProps}
|
|
39
|
+
onChange={(checked: boolean) => {
|
|
40
|
+
handleChange(
|
|
41
|
+
checked,
|
|
42
|
+
formContext,
|
|
43
|
+
props.fieldConfig,
|
|
44
|
+
props.onChange
|
|
45
|
+
);
|
|
46
|
+
setEnabled(checked);
|
|
47
|
+
}}
|
|
48
|
+
checked={enabled}
|
|
49
|
+
className="group relative inline-flex h-4 w-9 shrink-0 cursor-pointer items-center justify-center rounded-full focus:outline-none switch-container"
|
|
50
|
+
>
|
|
51
|
+
<span className="sr-only">Use setting</span>
|
|
52
|
+
<span aria-hidden="true" className="pointer-events-none absolute size-full rounded-md bg-white switch-toggle-off" />
|
|
53
|
+
<span
|
|
54
|
+
aria-hidden="true"
|
|
55
|
+
className="pointer-events-none absolute mx-auto h-3 w-9 rounded-full bg-gray-200 transition-colors duration-200 ease-in-out group-data-[checked]:bg-[#4361ee] switch-toggle-on"
|
|
56
|
+
/>
|
|
57
|
+
<span
|
|
58
|
+
aria-hidden="true"
|
|
59
|
+
className="pointer-events-none absolute left-0 inline-block size-4 transform rounded-full border border-gray-200 bg-white shadow ring-0 transition-transform duration-200 ease-in-out group-data-[checked]:translate-x-5 switch-toggle-button"
|
|
60
|
+
/>
|
|
61
|
+
</Switch>
|
|
62
|
+
// <Switch
|
|
63
|
+
// defaultChecked={props.fieldConfig.defaultValue as boolean}
|
|
64
|
+
// {...hookProps}
|
|
65
|
+
// onChange={(checked: boolean) => {
|
|
66
|
+
// handleChange(
|
|
67
|
+
// checked,
|
|
68
|
+
// formContext,
|
|
69
|
+
// props.fieldConfig,
|
|
70
|
+
// props.onChange
|
|
71
|
+
// );
|
|
72
|
+
// setEnabled(checked);
|
|
73
|
+
// }}
|
|
74
|
+
// checked={enabled}
|
|
75
|
+
// style={{width:'44px'}}
|
|
76
|
+
// className={clsx(
|
|
77
|
+
// enabled ? 'switch-checked' : 'switch',
|
|
78
|
+
// 'relative inline-flex shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 !form-switch'
|
|
79
|
+
// )}>
|
|
80
|
+
// {({checked}) => (
|
|
81
|
+
// <>
|
|
82
|
+
// <span className="sr-only">Use setting</span>
|
|
83
|
+
// <span
|
|
84
|
+
// aria-hidden="true"
|
|
85
|
+
// style={{width:'20px', height:'20px'}}
|
|
86
|
+
// className={`${checked ? "translate-x-full" : "translate-x-0"}
|
|
87
|
+
// relative pointer-events-none inline-block transform rounded-full bg-white shadow-lg ring-0 transition duration-200 ease-in-out`}
|
|
88
|
+
// >
|
|
89
|
+
|
|
90
|
+
// <span className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
|
91
|
+
// {checked ? (
|
|
92
|
+
// <CheckIcon style={{width:'12px', height:'12px'}} />
|
|
93
|
+
// ) : (
|
|
94
|
+
// <XMarkIcon style={{width:'12px', height:'12px'}} />
|
|
95
|
+
// )}
|
|
96
|
+
// </span>
|
|
97
|
+
|
|
98
|
+
// </span>
|
|
99
|
+
// {/* <span className="sr-only"></span>
|
|
100
|
+
// <span
|
|
101
|
+
// aria-hidden="true"
|
|
102
|
+
// className="pointer-events-none absolute h-full w-full rounded-md bhite"
|
|
103
|
+
// />
|
|
104
|
+
// <span
|
|
105
|
+
// aria-hidden="true"
|
|
106
|
+
// className={clsx(
|
|
107
|
+
// checked
|
|
108
|
+
// ? "bg-[#377dff80]"
|
|
109
|
+
// : "bg-[#bdc1c6] shadow-md",
|
|
110
|
+
// "pointer-events-none absolute mx-auto h-3 w-8 rounded-full transition-colors duration-200 ease-in-out"
|
|
111
|
+
// )}
|
|
112
|
+
// />
|
|
113
|
+
// <span
|
|
114
|
+
// className={clsx(
|
|
115
|
+
// checked
|
|
116
|
+
// ? "translate-x-4 bg-[#377dff] shadow-md"
|
|
117
|
+
// : "translate-x-0 bg-white",
|
|
118
|
+
// "pointer-events-none inline-block h-4 w-4 transform rounded-full shadow ring-0 transition duration-200 ease-in-out"
|
|
119
|
+
// )}></span> */}
|
|
120
|
+
// </>
|
|
121
|
+
// )}
|
|
122
|
+
// </Switch>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<RenderFormField fieldConfig={props.fieldConfig} getInput={getInput}/>
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export default SwitchField;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React, { useContext } from "react";
|
|
2
|
+
import { RegisterOptions } from "react-hook-form";
|
|
3
|
+
import { FormContext } from "../context/FormContext";
|
|
4
|
+
import { FormFieldComponentPropSchema } from "../schema/FormFieldSchema";
|
|
5
|
+
import { Textarea } from "@headlessui/react";
|
|
6
|
+
import RenderFormField from "../util/RenderFormField";
|
|
7
|
+
import { handleChange, registerFormField } from "../util";
|
|
8
|
+
|
|
9
|
+
const TextAreaField: React.FC<FormFieldComponentPropSchema> = (
|
|
10
|
+
props: FormFieldComponentPropSchema
|
|
11
|
+
) => {
|
|
12
|
+
const formContext = useContext(FormContext);
|
|
13
|
+
|
|
14
|
+
let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
|
|
15
|
+
|
|
16
|
+
let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
|
|
17
|
+
|
|
18
|
+
function getInput() {
|
|
19
|
+
return (
|
|
20
|
+
<Textarea
|
|
21
|
+
spellCheck="false"
|
|
22
|
+
rows={props.fieldConfig.rows ? props.fieldConfig.rows : 5}
|
|
23
|
+
{...hookProps}
|
|
24
|
+
placeholder={props.fieldConfig?.placeholder}
|
|
25
|
+
readOnly={props.fieldConfig?.readOnly}
|
|
26
|
+
disabled={props.fieldConfig?.disabled}
|
|
27
|
+
autoComplete={props.fieldConfig?.autoComplete}
|
|
28
|
+
defaultValue={props.fieldConfig.defaultValue as string}
|
|
29
|
+
className={`form-input ${
|
|
30
|
+
props.fieldConfig.customClassNames?.fieldClassName || "flex-1"
|
|
31
|
+
}`}
|
|
32
|
+
onChange={(e) => {
|
|
33
|
+
handleChange(
|
|
34
|
+
e.target.value,
|
|
35
|
+
formContext,
|
|
36
|
+
props.fieldConfig,
|
|
37
|
+
props.onChange
|
|
38
|
+
);
|
|
39
|
+
}}
|
|
40
|
+
></Textarea>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<RenderFormField fieldConfig={props.fieldConfig} getInput={getInput} />
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
export default TextAreaField;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React, { useContext } from "react";
|
|
2
|
+
import { RegisterOptions } from "react-hook-form";
|
|
3
|
+
import { FormContext } from "../context/FormContext";
|
|
4
|
+
import { FormFieldComponentPropSchema } from "../schema/FormFieldSchema";
|
|
5
|
+
import { Input } from "@headlessui/react";
|
|
6
|
+
import RenderFormField from "../util/RenderFormField";
|
|
7
|
+
import { handleChange, registerFormField } from "../util";
|
|
8
|
+
|
|
9
|
+
const TimeField: React.FC<FormFieldComponentPropSchema> = (
|
|
10
|
+
props: FormFieldComponentPropSchema
|
|
11
|
+
) => {
|
|
12
|
+
const formContext = useContext(FormContext);
|
|
13
|
+
|
|
14
|
+
let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
|
|
15
|
+
|
|
16
|
+
let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Raw Form Field
|
|
20
|
+
*/
|
|
21
|
+
const getInput = () => {
|
|
22
|
+
return (
|
|
23
|
+
<Input
|
|
24
|
+
type="time"
|
|
25
|
+
{...hookProps}
|
|
26
|
+
placeholder={props.fieldConfig?.placeholder}
|
|
27
|
+
readOnly={props.fieldConfig?.readOnly}
|
|
28
|
+
disabled={props.fieldConfig?.disabled}
|
|
29
|
+
autoComplete={props.fieldConfig?.autoComplete}
|
|
30
|
+
defaultValue={props.fieldConfig.defaultValue as string}
|
|
31
|
+
className={`form-input ${
|
|
32
|
+
props.fieldConfig.customClassNames?.fieldClassName || "flex-1"
|
|
33
|
+
}`}
|
|
34
|
+
onChange={(e) => {
|
|
35
|
+
handleChange(
|
|
36
|
+
e.target.value,
|
|
37
|
+
formContext,
|
|
38
|
+
props.fieldConfig,
|
|
39
|
+
props.onChange
|
|
40
|
+
);
|
|
41
|
+
}}
|
|
42
|
+
onClick={(event) => {
|
|
43
|
+
event.currentTarget.showPicker();
|
|
44
|
+
}}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<RenderFormField fieldConfig={props.fieldConfig} getInput={getInput} />
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
export default TimeField;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from "react";
|
|
8
|
+
|
|
9
|
+
import { Listbox, ListboxButton } from "@headlessui/react";
|
|
10
|
+
import axios from "axios";
|
|
11
|
+
import { RegisterOptions } from "react-hook-form";
|
|
12
|
+
import { reachoAPI } from "../../api";
|
|
13
|
+
import { FormContext } from "../context/FormContext";
|
|
14
|
+
import { getListOption, getListOptions } from "../FormFieldUtils";
|
|
15
|
+
import {
|
|
16
|
+
FieldOptionsSchema,
|
|
17
|
+
FormFieldComponentPropSchema,
|
|
18
|
+
FormFieldType,
|
|
19
|
+
OutputFormatType,
|
|
20
|
+
} from "../schema/FormFieldSchema";
|
|
21
|
+
import { handleChange, registerFormField } from "../util";
|
|
22
|
+
import RenderFormField from "../util/RenderFormField";
|
|
23
|
+
import RenderListOptions, {
|
|
24
|
+
renderListBoxValue,
|
|
25
|
+
} from "../util/RenderListOptions";
|
|
26
|
+
|
|
27
|
+
const Typeahead: React.FC<FormFieldComponentPropSchema> = (
|
|
28
|
+
props: FormFieldComponentPropSchema
|
|
29
|
+
) => {
|
|
30
|
+
const dynamicSelectRef = useRef<HTMLUListElement>(null);
|
|
31
|
+
const formContext = useContext(FormContext);
|
|
32
|
+
let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
|
|
33
|
+
let hookProps = formContext.register(
|
|
34
|
+
props.fieldConfig.name,
|
|
35
|
+
registerOptions
|
|
36
|
+
);
|
|
37
|
+
const [listOptions, setListOptions] = useState<FieldOptionsSchema[]>([]);
|
|
38
|
+
const [selectedValues, setSelectedValues] = useState<FieldOptionsSchema[]>(
|
|
39
|
+
[]
|
|
40
|
+
);
|
|
41
|
+
const [loading, setLoading] = useState<boolean>(true);
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (
|
|
45
|
+
!formContext.getValues(props.fieldConfig.name) &&
|
|
46
|
+
props.fieldConfig.defaultValue
|
|
47
|
+
) {
|
|
48
|
+
formContext.setValue(
|
|
49
|
+
props.fieldConfig.name,
|
|
50
|
+
props.fieldConfig.defaultValue
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
fetchData(undefined);
|
|
54
|
+
}, []);
|
|
55
|
+
|
|
56
|
+
const fetchData = useCallback(
|
|
57
|
+
async (_query: string | undefined) => {
|
|
58
|
+
setLoading(true);
|
|
59
|
+
try {
|
|
60
|
+
if (!props.fieldConfig.fetchUrl) return;
|
|
61
|
+
|
|
62
|
+
let url = props.fieldConfig.fetchUrl;
|
|
63
|
+
if (_query) {
|
|
64
|
+
url = url.includes("?")
|
|
65
|
+
? url + "&q=" + _query
|
|
66
|
+
: url + "?q=" + _query;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let response = await (props.fieldConfig.disableHeaderInFetch
|
|
70
|
+
? axios.get(url)
|
|
71
|
+
: reachoAPI.get(url));
|
|
72
|
+
if (response.data) {
|
|
73
|
+
const data: FieldOptionsSchema[] = getListOptions(
|
|
74
|
+
response.data,
|
|
75
|
+
props.fieldConfig.optionsConfig
|
|
76
|
+
);
|
|
77
|
+
setListOptions([...data]);
|
|
78
|
+
let value = formContext.getValues(props.fieldConfig.name);
|
|
79
|
+
if (
|
|
80
|
+
value &&
|
|
81
|
+
data.find((i) => i.value !== value)
|
|
82
|
+
) {
|
|
83
|
+
if (selectedValues.find((i) => i.value !== value))
|
|
84
|
+
fetchValue(value);
|
|
85
|
+
}
|
|
86
|
+
if (props.fieldConfig.fetchCallback) {
|
|
87
|
+
props.fieldConfig.fetchCallback(response);
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
console.error(response.statusText);
|
|
91
|
+
}
|
|
92
|
+
} catch (err) {
|
|
93
|
+
} finally {
|
|
94
|
+
setLoading(false);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
[props.fieldConfig.fetchUrl]
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const fetchValue = async (value: string) => {
|
|
101
|
+
try {
|
|
102
|
+
if (
|
|
103
|
+
props.fieldConfig.ignoreFetchValue ||
|
|
104
|
+
!props.fieldConfig.fetchUrl
|
|
105
|
+
) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let url = props.fieldConfig.fetchUrl;
|
|
110
|
+
|
|
111
|
+
if (value)
|
|
112
|
+
url = url.includes("?")
|
|
113
|
+
? url + "&values=" + value
|
|
114
|
+
: url + "?values=" + value;
|
|
115
|
+
|
|
116
|
+
let response = await (
|
|
117
|
+
props.fieldConfig.disableHeaderInFetch
|
|
118
|
+
? axios.get(url)
|
|
119
|
+
: reachoAPI.get(url)
|
|
120
|
+
);
|
|
121
|
+
if (response.data) {
|
|
122
|
+
const data: FieldOptionsSchema[] = getListOptions(
|
|
123
|
+
response.data,
|
|
124
|
+
props.fieldConfig.optionsConfig
|
|
125
|
+
);
|
|
126
|
+
setSelectedValues([...data]);
|
|
127
|
+
}
|
|
128
|
+
} catch (err) { }
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const updateListOptions = (data: any) => {
|
|
132
|
+
const resData: FieldOptionsSchema = getListOption(
|
|
133
|
+
data,
|
|
134
|
+
props.fieldConfig.optionsConfig
|
|
135
|
+
);
|
|
136
|
+
setSelectedValues((perv) => [resData]);
|
|
137
|
+
formContext.setValue(props.fieldConfig.name, resData.value);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
function getInput() {
|
|
141
|
+
return (
|
|
142
|
+
<Listbox
|
|
143
|
+
as={"div"}
|
|
144
|
+
{...hookProps}
|
|
145
|
+
className={`relative form-listbox flex-1`}
|
|
146
|
+
value={
|
|
147
|
+
formContext.getValues(props.fieldConfig.name)
|
|
148
|
+
? props.fieldConfig.outputFormat ===
|
|
149
|
+
OutputFormatType.ARRAY
|
|
150
|
+
? formContext.getValues(props.fieldConfig.name)[0]
|
|
151
|
+
: formContext.getValues(props.fieldConfig.name)
|
|
152
|
+
: undefined
|
|
153
|
+
}
|
|
154
|
+
onChange={(val) => {
|
|
155
|
+
const currentValue = formContext.getValues(
|
|
156
|
+
props.fieldConfig.name
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// If the value matches, set it to null, otherwise set it to val
|
|
160
|
+
const newValue = currentValue === val ? null : val;
|
|
161
|
+
|
|
162
|
+
const selected = listOptions.find(o => o.value == newValue);
|
|
163
|
+
selected && setSelectedValues([selected]);
|
|
164
|
+
handleChange(
|
|
165
|
+
newValue,
|
|
166
|
+
formContext,
|
|
167
|
+
props.fieldConfig,
|
|
168
|
+
props.onChange
|
|
169
|
+
);
|
|
170
|
+
}}
|
|
171
|
+
name={props.fieldConfig.name}
|
|
172
|
+
disabled={props.fieldConfig.disabled}>
|
|
173
|
+
<ListboxButton
|
|
174
|
+
className={
|
|
175
|
+
props.fieldConfig.customClassNames?.fieldClassName
|
|
176
|
+
? "form-listbox-select " +
|
|
177
|
+
props.fieldConfig.customClassNames?.fieldClassName
|
|
178
|
+
: "form-listbox-select"
|
|
179
|
+
}>
|
|
180
|
+
{renderListBoxValue(
|
|
181
|
+
formContext,
|
|
182
|
+
props.fieldConfig,
|
|
183
|
+
[...selectedValues, ...listOptions],
|
|
184
|
+
props.onChange
|
|
185
|
+
)}
|
|
186
|
+
</ListboxButton>
|
|
187
|
+
<RenderListOptions
|
|
188
|
+
formContext={formContext}
|
|
189
|
+
onChange={props.onChange}
|
|
190
|
+
formField={FormFieldType.TYPEAHEAD}
|
|
191
|
+
ref={dynamicSelectRef}
|
|
192
|
+
fieldConfig={props.fieldConfig}
|
|
193
|
+
listOptions={[...selectedValues, ...listOptions]}
|
|
194
|
+
setListOptions={setListOptions}
|
|
195
|
+
loading={loading}
|
|
196
|
+
setLoading={setLoading}
|
|
197
|
+
createCallback={(data) => updateListOptions(data)}
|
|
198
|
+
queryCallback={(query) => fetchData(query)}
|
|
199
|
+
/>
|
|
200
|
+
</Listbox>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (props.fieldConfig.hideWhenNoResults && listOptions.length == 0) {
|
|
204
|
+
return <></>;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return (
|
|
208
|
+
<RenderFormField fieldConfig={props.fieldConfig} getInput={getInput} />
|
|
209
|
+
);
|
|
210
|
+
};
|
|
211
|
+
export default Typeahead;
|