@addsign/moje-agenda-shared-lib 1.0.60 → 2.0.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/dist/Dialog-DZMfjbGC.js +421 -0
- package/dist/Dialog-DZMfjbGC.js.map +1 -0
- package/dist/assets/style.css +4369 -0
- package/dist/assets/tailwind.css +1365 -1193
- package/dist/check-B7dJm08z.js +12 -0
- package/dist/check-B7dJm08z.js.map +1 -0
- package/dist/components/Button.js +1 -1
- package/dist/components/datatable/DataTable.js +6 -2
- package/dist/components/datatable/DataTable.js.map +1 -1
- package/dist/components/datatable/DataTableServer.js +6 -2
- package/dist/components/datatable/DataTableServer.js.map +1 -1
- package/dist/components/form/AutocompleteSearchBar.js +6 -2
- package/dist/components/form/AutocompleteSearchBar.js.map +1 -1
- package/dist/components/form/AutocompleteSearchBarServer.js +6 -2
- package/dist/components/form/AutocompleteSearchBarServer.js.map +1 -1
- package/dist/components/form/FileInput.js +7 -3
- package/dist/components/form/FileInput.js.map +1 -1
- package/dist/components/form/FileInputMultiple.js +7 -3
- package/dist/components/form/FileInputMultiple.js.map +1 -1
- package/dist/components/form/FormField.js +6 -2
- package/dist/components/form/FormField.js.map +1 -1
- package/dist/components/form/PositionsSelectorSingle.js +6 -2
- package/dist/components/form/PositionsSelectorSingle.js.map +1 -1
- package/dist/components/form/SelectField.js +6 -2
- package/dist/components/form/SelectField.js.map +1 -1
- package/dist/components/profiles/ProfileOverview.js +6 -2
- package/dist/components/profiles/ProfileOverview.js.map +1 -1
- package/dist/components/ui/Combobox.d.ts +1 -0
- package/dist/components/ui/Combobox.js +138 -0
- package/dist/components/ui/Combobox.js.map +1 -0
- package/dist/components/ui/DateTimePicker.js +19 -5
- package/dist/components/ui/DateTimePicker.js.map +1 -1
- package/dist/components/ui/Dialog.js +15 -413
- package/dist/components/ui/Dialog.js.map +1 -1
- package/dist/components/ui/ScrollArea.js +2 -1
- package/dist/components/ui/ScrollArea.js.map +1 -1
- package/dist/components/ui/command.d.ts +80 -0
- package/dist/components/ui/command.js +643 -0
- package/dist/components/ui/command.js.map +1 -0
- package/dist/components/ui/datepicker.js +14 -1
- package/dist/components/ui/datepicker.js.map +1 -1
- package/dist/components/ui/popover.js +3 -2
- package/dist/components/ui/popover.js.map +1 -1
- package/dist/components/ui/radioGroup.d.ts +5 -0
- package/dist/components/ui/radioGroup.js +586 -0
- package/dist/components/ui/radioGroup.js.map +1 -0
- package/dist/components/ui/select.js +9 -144
- package/dist/components/ui/select.js.map +1 -1
- package/dist/index-BXrwe-_7.js +1395 -0
- package/dist/index-BXrwe-_7.js.map +1 -0
- package/dist/index-Bk8dRTPE.js +11 -0
- package/dist/index-Bk8dRTPE.js.map +1 -0
- package/dist/index-BlzC-wss.js +140 -0
- package/dist/index-BlzC-wss.js.map +1 -0
- package/dist/index-Bp9GiUkg.js +2266 -0
- package/dist/index-Bp9GiUkg.js.map +1 -0
- package/dist/index-BzVVosDl.js +57 -0
- package/dist/index-BzVVosDl.js.map +1 -0
- package/dist/index-CbAQSs_C.js +40 -0
- package/dist/index-CbAQSs_C.js.map +1 -0
- package/dist/index-Dz_fWpFA.js +2203 -0
- package/dist/index-Dz_fWpFA.js.map +1 -0
- package/dist/index-IXOTxK3N.js +7 -0
- package/dist/index-IXOTxK3N.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.js +29 -12
- package/dist/main.js.map +1 -1
- package/dist/parse-D2yb8751.js +1727 -0
- package/dist/parse-D2yb8751.js.map +1 -0
- package/dist/tailwind-l0sNRNKZ.js +2 -0
- package/dist/tailwind-l0sNRNKZ.js.map +1 -0
- package/lib/components/Button.tsx +57 -0
- package/lib/components/Calendar.tsx +242 -0
- package/lib/components/ConfirmationModalDialog.tsx +115 -0
- package/lib/components/Modal.tsx +73 -0
- package/lib/components/ModalDialog.tsx +63 -0
- package/lib/components/Spinner.tsx +25 -0
- package/lib/components/SpinnerIcon.tsx +12 -0
- package/lib/components/datatable/DataTable.tsx +442 -0
- package/lib/components/datatable/DataTableServer.tsx +939 -0
- package/lib/components/datatable/DatatableSettings.tsx +48 -0
- package/lib/components/datatable/Resizable.tsx +99 -0
- package/lib/components/datatable/types.ts +33 -0
- package/lib/components/form/AutocompleteSearchBar.tsx +424 -0
- package/lib/components/form/AutocompleteSearchBarServer.tsx +257 -0
- package/lib/components/form/DateField.tsx +124 -0
- package/lib/components/form/DateRangeField.tsx +116 -0
- package/lib/components/form/FileInput.tsx +188 -0
- package/lib/components/form/FileInputMultiple.tsx +186 -0
- package/lib/components/form/FormField.tsx +371 -0
- package/lib/components/form/InputField.tsx +230 -0
- package/lib/components/form/PositionsSelectorSingle.tsx +266 -0
- package/lib/components/form/RadioGroup.tsx +64 -0
- package/lib/components/form/SelectField.tsx +267 -0
- package/lib/components/layout/IconInCircle.tsx +29 -0
- package/lib/components/layout/PageTitle.tsx +19 -0
- package/lib/components/layout/SectionTitle.tsx +22 -0
- package/lib/components/profiles/ProfileOverview.tsx +212 -0
- package/lib/components/ui/Calendar.tsx +68 -0
- package/lib/components/ui/Combobox.tsx +122 -0
- package/lib/components/ui/DatePicker.tsx +124 -0
- package/lib/components/ui/DateTimePicker.tsx +187 -0
- package/lib/components/ui/Dialog.tsx +118 -0
- package/lib/components/ui/ScrollArea.tsx +45 -0
- package/lib/components/ui/button.tsx +56 -0
- package/lib/components/ui/command.tsx +153 -0
- package/lib/components/ui/form.tsx +177 -0
- package/lib/components/ui/input.tsx +22 -0
- package/lib/components/ui/label.tsx +24 -0
- package/lib/components/ui/popover.tsx +31 -0
- package/lib/components/ui/radioGroup.tsx +44 -0
- package/lib/components/ui/select.tsx +158 -0
- package/lib/contexts/FederationContext.tsx +28 -0
- package/lib/contexts/useFederationContext.ts +4 -0
- package/lib/css/tailwind.css +10 -0
- package/lib/fonts/arial.ts +3 -0
- package/lib/fonts/arialBold.ts +4 -0
- package/lib/main.ts +64 -0
- package/lib/types.ts +492 -0
- package/lib/utils/PdfManager.ts +224 -0
- package/lib/utils/getFullName.tsx +83 -0
- package/lib/utils/getIntersectingDays.ts +28 -0
- package/lib/utils/handleErrors.ts +28 -0
- package/lib/utils/hasRightInModule.ts +17 -0
- package/lib/utils/hasRole.ts +12 -0
- package/lib/utils/utils.ts +6 -0
- package/lib/vite-env.d.ts +1 -0
- package/package.json +5 -2
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import React, { useState, useCallback } from "react";
|
|
2
|
+
import { useDropzone } from "react-dropzone";
|
|
3
|
+
import { MdDeleteOutline, MdInsertDriveFile } from "react-icons/md";
|
|
4
|
+
import { IAttachment } from "../../types";
|
|
5
|
+
import { handleErrors, useFederationContext } from "../../main";
|
|
6
|
+
import { AxiosError } from "axios";
|
|
7
|
+
|
|
8
|
+
interface FileInputMultipleProps {
|
|
9
|
+
name: string;
|
|
10
|
+
label?: string;
|
|
11
|
+
initialFiles?: IAttachment[];
|
|
12
|
+
onFilesChanged: (e: any) => void;
|
|
13
|
+
required?: boolean;
|
|
14
|
+
description?: string;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
errors?: { [key: string]: { message: string } };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface IAttachmentReadOnly extends IAttachment {
|
|
20
|
+
readonly?: boolean;
|
|
21
|
+
}
|
|
22
|
+
const FileInputMultiple: React.FC<FileInputMultipleProps> = ({
|
|
23
|
+
initialFiles = [],
|
|
24
|
+
onFilesChanged,
|
|
25
|
+
label,
|
|
26
|
+
name,
|
|
27
|
+
required,
|
|
28
|
+
description,
|
|
29
|
+
disabled,
|
|
30
|
+
errors = {},
|
|
31
|
+
}) => {
|
|
32
|
+
const [fileDataList, setFileDataList] = useState<IAttachmentReadOnly[]>(
|
|
33
|
+
[...initialFiles].map((file) => ({ ...file, readonly: true }))
|
|
34
|
+
);
|
|
35
|
+
const federationContext = useFederationContext();
|
|
36
|
+
|
|
37
|
+
const onDrop = useCallback(
|
|
38
|
+
async (acceptedFiles: File[]) => {
|
|
39
|
+
const uploadedFiles = await Promise.all(
|
|
40
|
+
acceptedFiles.map(async (file) => {
|
|
41
|
+
const formData = new FormData();
|
|
42
|
+
formData.append("file", file);
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const response =
|
|
46
|
+
await federationContext.apiClient.post<IAttachment>(
|
|
47
|
+
"/files/upload",
|
|
48
|
+
formData,
|
|
49
|
+
{
|
|
50
|
+
headers: {
|
|
51
|
+
"Content-Type": "multipart/form-data",
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
return response.data;
|
|
56
|
+
} catch (error) {
|
|
57
|
+
handleErrors(error as AxiosError, federationContext.emitter);
|
|
58
|
+
console.error("There was an error!", error);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const validFiles = uploadedFiles.filter(
|
|
65
|
+
(file) => file !== null
|
|
66
|
+
) as IAttachment[];
|
|
67
|
+
const updatedFileDataList = [...fileDataList, ...validFiles];
|
|
68
|
+
setFileDataList(updatedFileDataList);
|
|
69
|
+
onFilesChanged({
|
|
70
|
+
target: { name, value: updatedFileDataList.map((file) => file.id) },
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
[
|
|
74
|
+
fileDataList,
|
|
75
|
+
federationContext.apiClient,
|
|
76
|
+
onFilesChanged,
|
|
77
|
+
name,
|
|
78
|
+
federationContext.emitter,
|
|
79
|
+
]
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
|
83
|
+
onDrop,
|
|
84
|
+
disabled,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const handleRemove = (fileId: number) => {
|
|
88
|
+
const updatedFileDataList = fileDataList.filter(
|
|
89
|
+
(file) => file.id !== fileId
|
|
90
|
+
);
|
|
91
|
+
setFileDataList(updatedFileDataList);
|
|
92
|
+
onFilesChanged({
|
|
93
|
+
target: {
|
|
94
|
+
name,
|
|
95
|
+
value: updatedFileDataList.map((file) => file.id.toString()),
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
if (disabled === true && fileDataList.length === 0) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<div className="w-full min-h-30 flex-col justify-start items-start gap-1.5 inline-flex sharedLibrary">
|
|
105
|
+
<div className="self-stretch flex-col justify-start items-start gap-1.5 flex">
|
|
106
|
+
{label && (
|
|
107
|
+
<label
|
|
108
|
+
className="text-slate-700 text-sm leading-tight font-medium"
|
|
109
|
+
htmlFor={name}
|
|
110
|
+
>
|
|
111
|
+
{label} {required ? "*" : ""}
|
|
112
|
+
</label>
|
|
113
|
+
)}
|
|
114
|
+
<div
|
|
115
|
+
className={
|
|
116
|
+
`self-stretch px-3 py-2 rounded-lg justify-start items-center gap-2 outline-none border bg-transparent ` +
|
|
117
|
+
` ${errors[name]?.message ? "border-red-200" : "border-gray-300"} `
|
|
118
|
+
}
|
|
119
|
+
>
|
|
120
|
+
{!disabled && (
|
|
121
|
+
<div
|
|
122
|
+
{...getRootProps()}
|
|
123
|
+
className={`w-full p-4 border-dashed cursor-pointer
|
|
124
|
+
border-2 rounded-lg text-center hover:bg-gray-100
|
|
125
|
+
${isDragActive ? "border-indigo-300 bg-indigo-50" : "border-gray-300"}`}
|
|
126
|
+
>
|
|
127
|
+
<input {...getInputProps()} id={name} />
|
|
128
|
+
<p className="text-gray-500">
|
|
129
|
+
{isDragActive
|
|
130
|
+
? "Sem přetáhněte soubory"
|
|
131
|
+
: "Klikněte pro nahrání, nebo nahrajte přetažením souborů"}
|
|
132
|
+
</p>
|
|
133
|
+
</div>
|
|
134
|
+
)}
|
|
135
|
+
<div className="w-full">
|
|
136
|
+
{fileDataList.map((file) => (
|
|
137
|
+
<div
|
|
138
|
+
key={file.id}
|
|
139
|
+
className="w-full flex items-center justify-between py-2 border-b "
|
|
140
|
+
>
|
|
141
|
+
<div className="flex items-center content-center">
|
|
142
|
+
<MdInsertDriveFile style={{ fontSize: "2rem" }} />
|
|
143
|
+
<a
|
|
144
|
+
href={`/api/files/download/${file.id}`}
|
|
145
|
+
className="pl-2 text-left underline text-primary"
|
|
146
|
+
target="_blank"
|
|
147
|
+
>
|
|
148
|
+
{file.filename}
|
|
149
|
+
</a>
|
|
150
|
+
</div>
|
|
151
|
+
{!disabled && file.readonly !== true && (
|
|
152
|
+
<div
|
|
153
|
+
onClick={() => handleRemove(file.id)}
|
|
154
|
+
className="text-gray-600 cursor-pointer hover:text-primary hover:bg-gray-200 rounded-full ml-4"
|
|
155
|
+
>
|
|
156
|
+
<MdDeleteOutline
|
|
157
|
+
style={{ fontSize: "1.5rem", margin: "10px" }}
|
|
158
|
+
/>
|
|
159
|
+
</div>
|
|
160
|
+
)}
|
|
161
|
+
</div>
|
|
162
|
+
))}
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
{description && (
|
|
167
|
+
<div
|
|
168
|
+
className="HintText self-stretch text-slate-600 text-sm font-normal leading-tight"
|
|
169
|
+
id={name + ":description"}
|
|
170
|
+
>
|
|
171
|
+
{description}
|
|
172
|
+
</div>
|
|
173
|
+
)}
|
|
174
|
+
{errors[name] && (
|
|
175
|
+
<div
|
|
176
|
+
className="HintText self-stretch text-red-600 text-sm font-normal leading-tight"
|
|
177
|
+
id={name + ":error"}
|
|
178
|
+
>
|
|
179
|
+
{errors[name]?.message}
|
|
180
|
+
</div>
|
|
181
|
+
)}
|
|
182
|
+
</div>
|
|
183
|
+
);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export default FileInputMultiple;
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { MdClose } from "react-icons/md";
|
|
4
|
+
import { IOptionItem, useFederationContext } from "../../main";
|
|
5
|
+
|
|
6
|
+
export interface FormFieldProps {
|
|
7
|
+
label?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
name: string;
|
|
10
|
+
type: string;
|
|
11
|
+
value?: any;
|
|
12
|
+
register?: any;
|
|
13
|
+
|
|
14
|
+
errors?: any;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
required?: boolean;
|
|
17
|
+
clearable?: boolean;
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
options?: IOptionItem[];
|
|
20
|
+
children?: React.ReactNode;
|
|
21
|
+
fetchUrl?: string;
|
|
22
|
+
maxLength?: number;
|
|
23
|
+
|
|
24
|
+
className?: string;
|
|
25
|
+
valueKey?: string;
|
|
26
|
+
labelKey?: string;
|
|
27
|
+
minDate?: string;
|
|
28
|
+
maxDate?: string;
|
|
29
|
+
onInputChange: (
|
|
30
|
+
e: React.ChangeEvent<
|
|
31
|
+
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | any
|
|
32
|
+
>
|
|
33
|
+
) => void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const FormField: React.FC<FormFieldProps> = ({
|
|
37
|
+
label,
|
|
38
|
+
name,
|
|
39
|
+
type,
|
|
40
|
+
register,
|
|
41
|
+
disabled,
|
|
42
|
+
errors = {},
|
|
43
|
+
required,
|
|
44
|
+
clearable,
|
|
45
|
+
value,
|
|
46
|
+
description,
|
|
47
|
+
onInputChange,
|
|
48
|
+
options,
|
|
49
|
+
placeholder,
|
|
50
|
+
children,
|
|
51
|
+
fetchUrl,
|
|
52
|
+
valueKey,
|
|
53
|
+
labelKey,
|
|
54
|
+
maxLength,
|
|
55
|
+
className,
|
|
56
|
+
minDate,
|
|
57
|
+
maxDate,
|
|
58
|
+
}) => {
|
|
59
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
60
|
+
|
|
61
|
+
const [localOptions, setLocalOptions] = useState(options);
|
|
62
|
+
const fallbackRef = useRef(null); // Create a fallback ref
|
|
63
|
+
const {
|
|
64
|
+
ref: registeredRef = fallbackRef,
|
|
65
|
+
onBlur: formOnBlur = () => {} /* default function */,
|
|
66
|
+
...rest
|
|
67
|
+
} = register ? register(name) : {};
|
|
68
|
+
|
|
69
|
+
const apiClient = useFederationContext()?.apiClient;
|
|
70
|
+
const ref = registeredRef || fallbackRef;
|
|
71
|
+
const focusInput = () => {
|
|
72
|
+
if (ref.current) {
|
|
73
|
+
ref.current.focus();
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const handleMultiSelectChange = (
|
|
77
|
+
event: React.ChangeEvent<HTMLSelectElement>
|
|
78
|
+
) => {
|
|
79
|
+
const selectedOptions = Array.from(
|
|
80
|
+
event.target.selectedOptions,
|
|
81
|
+
(option) => option.value
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
onInputChange({
|
|
85
|
+
...event,
|
|
86
|
+
target: {
|
|
87
|
+
value: selectedOptions,
|
|
88
|
+
name: event.target.name,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const handleCheckBoxChange = (
|
|
94
|
+
event: React.ChangeEvent<HTMLSelectElement>
|
|
95
|
+
) => {
|
|
96
|
+
onInputChange({
|
|
97
|
+
...event,
|
|
98
|
+
target: {
|
|
99
|
+
value: event.target.value == "on" ? true : false,
|
|
100
|
+
name: event.target.name,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const handleClear = (e: any) => {
|
|
106
|
+
value;
|
|
107
|
+
onInputChange({
|
|
108
|
+
...e,
|
|
109
|
+
target: {
|
|
110
|
+
value: "",
|
|
111
|
+
name: name,
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
const fetchOptions = async (fetchUrl: string) => {
|
|
117
|
+
const { data } = await apiClient.get(fetchUrl);
|
|
118
|
+
|
|
119
|
+
// Check if the first item in the data array is a number to determine the data type
|
|
120
|
+
const isArrayOfNumbers = typeof data[0] === "number";
|
|
121
|
+
|
|
122
|
+
// Transform data based on its type
|
|
123
|
+
const transformedOptions = data.map((item: any) => {
|
|
124
|
+
if (isArrayOfNumbers) {
|
|
125
|
+
// If it's a number, use the number for both value and label
|
|
126
|
+
return { value: item, label: item.toString() };
|
|
127
|
+
} else {
|
|
128
|
+
// Otherwise, extract using predefined keys or defaults
|
|
129
|
+
return {
|
|
130
|
+
value: item[valueKey || "id"],
|
|
131
|
+
label: item[labelKey || "name"],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
setLocalOptions([
|
|
137
|
+
{ value: null, label: " " }, // Add an empty option as the first item
|
|
138
|
+
...transformedOptions,
|
|
139
|
+
]);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
if (fetchUrl) fetchOptions(fetchUrl);
|
|
143
|
+
if (options) setLocalOptions(options);
|
|
144
|
+
}, [fetchUrl, options, apiClient, valueKey, labelKey]); // ensure valueKey and labelKey are also in the dependency array if they are dynamic
|
|
145
|
+
|
|
146
|
+
const renderInput = () => {
|
|
147
|
+
switch (type) {
|
|
148
|
+
case "select":
|
|
149
|
+
return (
|
|
150
|
+
<>
|
|
151
|
+
<select
|
|
152
|
+
id={name}
|
|
153
|
+
className="grow shrink basis-0 text-gray-900 text-sm font-normal leading-tight focus:border-none bg-transparent w-full"
|
|
154
|
+
disabled={disabled}
|
|
155
|
+
value={value}
|
|
156
|
+
{...rest} // Spread the rest of register's return value
|
|
157
|
+
ref={ref}
|
|
158
|
+
onChange={onInputChange}
|
|
159
|
+
onFocus={() => setIsFocused(true)}
|
|
160
|
+
// Combine custom onBlur with form's onBlur
|
|
161
|
+
onBlur={(e) => {
|
|
162
|
+
formOnBlur(e); // Call React Hook Form's onBlur
|
|
163
|
+
setIsFocused(false); // Then call your custom onBlur logic
|
|
164
|
+
}}
|
|
165
|
+
>
|
|
166
|
+
{placeholder && <option label={placeholder}></option>}
|
|
167
|
+
{localOptions?.map((option, index) => (
|
|
168
|
+
<option
|
|
169
|
+
key={index}
|
|
170
|
+
value={
|
|
171
|
+
option.value !== undefined && option.value !== null
|
|
172
|
+
? option.value.toString()
|
|
173
|
+
: ""
|
|
174
|
+
}
|
|
175
|
+
>
|
|
176
|
+
{option.label}
|
|
177
|
+
</option>
|
|
178
|
+
))}
|
|
179
|
+
</select>
|
|
180
|
+
</>
|
|
181
|
+
);
|
|
182
|
+
case "multiSelect":
|
|
183
|
+
return (
|
|
184
|
+
<>
|
|
185
|
+
<select
|
|
186
|
+
id={name}
|
|
187
|
+
multiple
|
|
188
|
+
className="grow shrink basis-0 text-gray-900 text-sm font-normal leading-tight focus:border-none bg-transparent w-max-full "
|
|
189
|
+
disabled={disabled}
|
|
190
|
+
value={Array.isArray(value) ? value : []} // Ensure value is always an array
|
|
191
|
+
{...rest}
|
|
192
|
+
ref={ref}
|
|
193
|
+
onChange={handleMultiSelectChange} // Use the custom multi-select handler
|
|
194
|
+
onFocus={() => setIsFocused(true)}
|
|
195
|
+
onBlur={(e) => {
|
|
196
|
+
formOnBlur(e);
|
|
197
|
+
setIsFocused(false);
|
|
198
|
+
}}
|
|
199
|
+
>
|
|
200
|
+
{options?.map((option) => (
|
|
201
|
+
<option
|
|
202
|
+
key={option.value}
|
|
203
|
+
value={option.value ? option.value : undefined}
|
|
204
|
+
>
|
|
205
|
+
{option.label}
|
|
206
|
+
</option>
|
|
207
|
+
))}
|
|
208
|
+
</select>
|
|
209
|
+
</>
|
|
210
|
+
);
|
|
211
|
+
case "radioGroup":
|
|
212
|
+
return (
|
|
213
|
+
<div className="flex flex-col" id={name}>
|
|
214
|
+
{options?.map((option, index) => (
|
|
215
|
+
<label
|
|
216
|
+
key={index}
|
|
217
|
+
className="inline-flex items-center space-x-2 my-2"
|
|
218
|
+
>
|
|
219
|
+
<input
|
|
220
|
+
type="radio"
|
|
221
|
+
name={name}
|
|
222
|
+
value={option.value}
|
|
223
|
+
checked={value === option.value}
|
|
224
|
+
disabled={disabled}
|
|
225
|
+
{...register(name)} // Spread the rest of register's return value
|
|
226
|
+
onChange={onInputChange}
|
|
227
|
+
className="text-indigo-600 border-gray-300 focus:ring-indigo-500 mr-2"
|
|
228
|
+
/>
|
|
229
|
+
<span className="text-gray-900 text-sm font-normal leading-tight">
|
|
230
|
+
{option.label}
|
|
231
|
+
</span>
|
|
232
|
+
</label>
|
|
233
|
+
))}
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
case "textarea":
|
|
237
|
+
return (
|
|
238
|
+
<textarea
|
|
239
|
+
id={name}
|
|
240
|
+
className="grow shrink basis-0 text-gray-900 text-sm font-normal leading-tight focus:border-none "
|
|
241
|
+
disabled={disabled}
|
|
242
|
+
value={value}
|
|
243
|
+
rows={3}
|
|
244
|
+
{...rest} // Spread the rest of register's return value
|
|
245
|
+
ref={ref}
|
|
246
|
+
onChange={onInputChange}
|
|
247
|
+
onFocus={() => setIsFocused(true)}
|
|
248
|
+
maxLength={maxLength || 4000}
|
|
249
|
+
// Combine custom onBlur with form's onBlur
|
|
250
|
+
onBlur={(e) => {
|
|
251
|
+
formOnBlur(e); // Call React Hook Form's onBlur
|
|
252
|
+
setIsFocused(false); // Then call your custom onBlur logic
|
|
253
|
+
}}
|
|
254
|
+
/>
|
|
255
|
+
);
|
|
256
|
+
case "checkbox":
|
|
257
|
+
return (
|
|
258
|
+
<>
|
|
259
|
+
<input
|
|
260
|
+
type="checkbox"
|
|
261
|
+
id={name}
|
|
262
|
+
className="shrink basis-0 text-gray-900 text-sm font-normal leading-tight focus:border-none"
|
|
263
|
+
checked={value}
|
|
264
|
+
disabled={disabled}
|
|
265
|
+
{...rest} // Spread the rest of register's return value
|
|
266
|
+
ref={ref}
|
|
267
|
+
onChange={handleCheckBoxChange}
|
|
268
|
+
onFocus={() => setIsFocused(true)}
|
|
269
|
+
// Combine custom onBlur with form's onBlur
|
|
270
|
+
onBlur={(e) => {
|
|
271
|
+
formOnBlur(e); // Call React Hook Form's onBlur
|
|
272
|
+
setIsFocused(false); // Then call your custom onBlur logic
|
|
273
|
+
}}
|
|
274
|
+
/>
|
|
275
|
+
<label htmlFor={name}>{label}</label>
|
|
276
|
+
</>
|
|
277
|
+
);
|
|
278
|
+
default:
|
|
279
|
+
return (
|
|
280
|
+
<>
|
|
281
|
+
<input
|
|
282
|
+
className="grow shrink basis-0 text-gray-900 text-sm font-normal leading-tight focus:border-none bg-transparent w-full"
|
|
283
|
+
id={name}
|
|
284
|
+
readOnly={disabled}
|
|
285
|
+
value={value}
|
|
286
|
+
type={type}
|
|
287
|
+
{...rest} // Spread the rest of register's return value
|
|
288
|
+
ref={ref}
|
|
289
|
+
placeholder={placeholder}
|
|
290
|
+
onChange={onInputChange}
|
|
291
|
+
min={minDate}
|
|
292
|
+
max={maxDate}
|
|
293
|
+
maxLength={maxLength}
|
|
294
|
+
onFocus={() => setIsFocused(true)}
|
|
295
|
+
// Combine custom onBlur with form's onBlur
|
|
296
|
+
onBlur={(e) => {
|
|
297
|
+
formOnBlur(e); // Call React Hook Form's onBlur
|
|
298
|
+
setIsFocused(false); // Then call your custom onBlur logic
|
|
299
|
+
}}
|
|
300
|
+
/>
|
|
301
|
+
</>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
return (
|
|
307
|
+
<div className="w-full min-h-30 flex-col justify-start items-start gap-1.5 sharedLibrary">
|
|
308
|
+
<div className="self-stretch flex-col justify-start items-start gap-1.5 flex ">
|
|
309
|
+
{label && (
|
|
310
|
+
<label
|
|
311
|
+
className="text-slate-700 text-sm leading-tight font-medium"
|
|
312
|
+
htmlFor={name}
|
|
313
|
+
>
|
|
314
|
+
{label} {required ? "*" : ""}
|
|
315
|
+
</label>
|
|
316
|
+
)}
|
|
317
|
+
<div
|
|
318
|
+
className={
|
|
319
|
+
`self-stretch px-3 py-1 rounded-lg justify-start items-center inline-flex outline-none border ` +
|
|
320
|
+
` ${
|
|
321
|
+
isFocused && !errors[name]?.message
|
|
322
|
+
? "outline-4 outline-indigo-200 outline-offset-0 border-indigo-300"
|
|
323
|
+
: ""
|
|
324
|
+
}` +
|
|
325
|
+
` ${
|
|
326
|
+
isFocused && errors[name]?.message
|
|
327
|
+
? "outline-4 outline-red-200 outline-offset-0 border-none"
|
|
328
|
+
: ""
|
|
329
|
+
} ` +
|
|
330
|
+
` ${!isFocused && errors[name]?.message ? "border-red-200" : ""} ` +
|
|
331
|
+
` ${disabled ? "bg-gray-100" : "bg-white"}` +
|
|
332
|
+
" " +
|
|
333
|
+
className
|
|
334
|
+
}
|
|
335
|
+
>
|
|
336
|
+
<div className="flex relative grow shrink basis-0 min-h-5 lg:min-h-[32px] justify-start items-stretch gap-1 w-full ">
|
|
337
|
+
{renderInput()}
|
|
338
|
+
{children && <div onClick={focusInput}>{children}</div>}
|
|
339
|
+
{clearable && value && (
|
|
340
|
+
<div className="flex items-center justify-center">
|
|
341
|
+
<MdClose
|
|
342
|
+
onClick={handleClear}
|
|
343
|
+
size={20}
|
|
344
|
+
id={name + ":clear"}
|
|
345
|
+
></MdClose>
|
|
346
|
+
</div>
|
|
347
|
+
)}{" "}
|
|
348
|
+
</div>
|
|
349
|
+
</div>
|
|
350
|
+
</div>
|
|
351
|
+
{description && (
|
|
352
|
+
<div
|
|
353
|
+
className="HintText self-stretch text-slate-600 text-sm font-normal leading-tight"
|
|
354
|
+
id={name + ":description"}
|
|
355
|
+
>
|
|
356
|
+
{description}
|
|
357
|
+
</div>
|
|
358
|
+
)}
|
|
359
|
+
{errors[name] && (
|
|
360
|
+
<div
|
|
361
|
+
className="HintText self-stretch text-red-600 text-sm font-normal leading-tight"
|
|
362
|
+
id={name + ":error"}
|
|
363
|
+
>
|
|
364
|
+
{errors[name]?.message}
|
|
365
|
+
</div>
|
|
366
|
+
)}
|
|
367
|
+
</div>
|
|
368
|
+
);
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
export default FormField;
|