@addsign/moje-agenda-shared-lib 2.0.63 → 2.0.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileInput.js","sources":["../../../lib/components/form/FileInput.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback } from \"react\";\nimport { useDropzone } from \"react-dropzone\";\nimport { handleErrors, useFederationContext } from \"../../main\";\nimport { MdDeleteOutline, MdInsertDriveFile } from \"react-icons/md\";\nimport { AxiosError } from \"axios\";\nimport { cn } from \"../../utils/utils\";\n\nexport interface FileData {\n id: number;\n mimeType: string;\n size: number;\n filename: string;\n createdByEmpId: string;\n created: string;\n}\n\nexport interface FileInputProps {\n name: string;\n label?: string;\n initialFile?: FileData;\n onFileChanged: (e: any) => void;\n required?: boolean;\n description?: string;\n disabled?: boolean;\n attachmentName?: string;\n attachmentType?: string;\n hasError?: boolean;\n}\n\nconst MAX_FILE_SIZE = 1024 * 1024; // 1MB\n\nconst FileInput: React.FC<FileInputProps> = ({\n initialFile,\n onFileChanged,\n label,\n name,\n required,\n description,\n disabled,\n attachmentName,\n attachmentType,\n hasError,\n}) => {\n const [fileData, setFileData] = useState<FileData | null>(\n initialFile || null\n );\n const [isFocused, setIsFocused] = useState(false);\n\n const federationContext = useFederationContext();\n useEffect(() => {\n if (initialFile) {\n setFileData(initialFile);\n }\n }, [initialFile]);\n\n const onDrop = useCallback(\n async (acceptedFiles: File[]) => {\n if (acceptedFiles.length > 0) {\n const file = acceptedFiles[0];\n\n if (file.size > MAX_FILE_SIZE) {\n // Handle the case when the file size is exceeded\n federationContext.emitter.emit(\"message\", {\n title: \"Velikost souboru byla překročena\",\n message: `Maximální povolená velikost je ${MAX_FILE_SIZE / (1024 * 1024)} MB.`,\n classes: \"bg-danger \",\n timeout: 0,\n type: \"error\",\n });\n return;\n }\n\n const formData = new FormData();\n\n // Add the JSON data object\n const dataObject = {\n ...(attachmentName && { attachmentName }),\n ...(attachmentType && { attachmentType }),\n };\n\n formData.append(\n \"data\",\n new Blob([JSON.stringify(dataObject)], { type: \"application/json\" })\n );\n formData.append(\"file\", file);\n\n try {\n const response = await federationContext.apiClient.post<FileData>(\n \"/files/upload\",\n formData,\n {\n headers: {\n \"Content-Type\": \"multipart/form-data\",\n },\n }\n );\n setFileData(response.data);\n onFileChanged({\n target: { name, value: response.data.id.toString() },\n });\n setIsFocused(false);\n } catch (error) {\n handleErrors(error as AxiosError, federationContext.emitter);\n console.error(\"There was an error!\", error);\n }\n }\n },\n [\n federationContext.apiClient,\n federationContext.emitter,\n onFileChanged,\n name,\n attachmentName,\n attachmentType,\n ]\n );\n\n const { getRootProps, getInputProps, isDragActive } = useDropzone({\n onDrop,\n disabled,\n multiple: false,\n });\n\n const handleRemove = () => {\n setFileData(null);\n onFileChanged({ target: { name, value: null } });\n };\n\n return (\n <div className=\"w-full min-h-30 flex-col justify-start items-start gap-1.5 inline-flex sharedLibrary\">\n <div className=\"self-stretch flex-col justify-start items-start gap-1.5 flex\">\n {label && (\n <label\n className=\"text-slate-700 text-sm leading-tight font-medium\"\n htmlFor={name}\n >\n {label} {required ? \"*\" : \"\"}\n </label>\n )}\n <div\n className={cn(\n `self-stretch px-2 py-2 rounded-lg justify-start items-center gap-2 inline-flex outline-none border`,\n isFocused &&\n !hasError &&\n \"outline-4 outline-indigo-200 outline-offset-0 border-indigo-300\",\n\n hasError &&\n \"outline-4 outline-red-200 outline-offset-0 border-none\",\n !isFocused && hasError && \"border-red-200 \",\n disabled ? \"bg-gray-100\" : \"bg-transparent\"\n )}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n >\n <div className=\"flex relative grow shrink basis-0 min-h-5 lg:min-h-[32px] justify-start items-stretch gap-2 max-w-full \">\n {!fileData ? (\n <div\n {...getRootProps()}\n className={`w-full p-4 border-dashed border-2 rounded-lg text-center ${\n isDragActive\n ? \"border-indigo-300 bg-indigo-50\"\n : \"border-gray-300\"\n }`}\n >\n <input {...getInputProps()} id={name} />\n <p className=\"text-gray-500\">\n {isDragActive\n ? \"Sem přetáhněte soubor\"\n : \"Klikněte pro nahrání, nebo nahrajte přetažením souboru\"}\n </p>\n </div>\n ) : (\n <div className=\"w-full flex items-center justify-between\">\n <div className=\" flex\">\n <MdInsertDriveFile style={{ fontSize: \"2rem\" }} />\n <a\n href={`/api/files/download/${fileData.id}`}\n className=\"pl-2 text-left underline text-primary\"\n target=\"_blank\"\n >\n {fileData.filename}\n </a>\n </div>\n {!disabled && (\n <div\n onClick={handleRemove}\n className=\"text-gray-600 cursor-pointer hover:text-primary hover:bg-gray-200 rounded-full ml-4\"\n >\n <MdDeleteOutline\n style={{ fontSize: \"1.5rem\", margin: \"15px\" }}\n />\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n {description && (\n <div\n className=\"HintText self-stretch text-slate-600 text-sm font-normal leading-tight\"\n id={name + \":description\"}\n >\n {description}\n </div>\n )}\n </div>\n );\n};\n\nexport default FileInput;\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FileInput.js","sources":["../../../lib/components/form/FileInput.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback } from \"react\";\r\nimport { useDropzone } from \"react-dropzone\";\r\nimport { handleErrors, useFederationContext } from \"../../main\";\r\nimport { MdDeleteOutline, MdInsertDriveFile } from \"react-icons/md\";\r\nimport { AxiosError } from \"axios\";\r\nimport { cn } from \"../../utils/utils\";\r\n\r\nexport interface FileData {\r\n id: number;\r\n mimeType: string;\r\n size: number;\r\n filename: string;\r\n createdByEmpId: string;\r\n created: string;\r\n}\r\n\r\nexport interface FileInputProps {\r\n name: string;\r\n label?: string;\r\n initialFile?: FileData;\r\n onFileChanged: (e: any) => void;\r\n required?: boolean;\r\n description?: string;\r\n disabled?: boolean;\r\n attachmentName?: string;\r\n attachmentType?: string;\r\n hasError?: boolean;\r\n}\r\n\r\nconst MAX_FILE_SIZE = 1024 * 1024; // 1MB\r\n\r\nconst FileInput: React.FC<FileInputProps> = ({\r\n initialFile,\r\n onFileChanged,\r\n label,\r\n name,\r\n required,\r\n description,\r\n disabled,\r\n attachmentName,\r\n attachmentType,\r\n hasError,\r\n}) => {\r\n const [fileData, setFileData] = useState<FileData | null>(\r\n initialFile || null\r\n );\r\n const [isFocused, setIsFocused] = useState(false);\r\n\r\n const federationContext = useFederationContext();\r\n useEffect(() => {\r\n if (initialFile) {\r\n setFileData(initialFile);\r\n }\r\n }, [initialFile]);\r\n\r\n const onDrop = useCallback(\r\n async (acceptedFiles: File[]) => {\r\n if (acceptedFiles.length > 0) {\r\n const file = acceptedFiles[0];\r\n\r\n if (file.size > MAX_FILE_SIZE) {\r\n // Handle the case when the file size is exceeded\r\n federationContext.emitter.emit(\"message\", {\r\n title: \"Velikost souboru byla překročena\",\r\n message: `Maximální povolená velikost je ${MAX_FILE_SIZE / (1024 * 1024)} MB.`,\r\n classes: \"bg-danger \",\r\n timeout: 0,\r\n type: \"error\",\r\n });\r\n return;\r\n }\r\n\r\n const formData = new FormData();\r\n\r\n // Add the JSON data object\r\n const dataObject = {\r\n ...(attachmentName && { attachmentName }),\r\n ...(attachmentType && { attachmentType }),\r\n };\r\n\r\n formData.append(\r\n \"data\",\r\n new Blob([JSON.stringify(dataObject)], { type: \"application/json\" })\r\n );\r\n formData.append(\"file\", file);\r\n\r\n try {\r\n const response = await federationContext.apiClient.post<FileData>(\r\n \"/files/upload\",\r\n formData,\r\n {\r\n headers: {\r\n \"Content-Type\": \"multipart/form-data\",\r\n },\r\n }\r\n );\r\n setFileData(response.data);\r\n onFileChanged({\r\n target: { name, value: response.data.id.toString() },\r\n });\r\n setIsFocused(false);\r\n } catch (error) {\r\n handleErrors(error as AxiosError, federationContext.emitter);\r\n console.error(\"There was an error!\", error);\r\n }\r\n }\r\n },\r\n [\r\n federationContext.apiClient,\r\n federationContext.emitter,\r\n onFileChanged,\r\n name,\r\n attachmentName,\r\n attachmentType,\r\n ]\r\n );\r\n\r\n const { getRootProps, getInputProps, isDragActive } = useDropzone({\r\n onDrop,\r\n disabled,\r\n multiple: false,\r\n });\r\n\r\n const handleRemove = () => {\r\n setFileData(null);\r\n onFileChanged({ target: { name, value: null } });\r\n };\r\n\r\n return (\r\n <div className=\"w-full min-h-30 flex-col justify-start items-start gap-1.5 inline-flex sharedLibrary\">\r\n <div className=\"self-stretch flex-col justify-start items-start gap-1.5 flex\">\r\n {label && (\r\n <label\r\n className=\"text-slate-700 text-sm leading-tight font-medium\"\r\n htmlFor={name}\r\n >\r\n {label} {required ? \"*\" : \"\"}\r\n </label>\r\n )}\r\n <div\r\n className={cn(\r\n `self-stretch px-2 py-2 rounded-lg justify-start items-center gap-2 inline-flex outline-none border`,\r\n isFocused &&\r\n !hasError &&\r\n \"outline-4 outline-indigo-200 outline-offset-0 border-indigo-300\",\r\n\r\n hasError &&\r\n \"outline-4 outline-red-200 outline-offset-0 border-none\",\r\n !isFocused && hasError && \"border-red-200 \",\r\n disabled ? \"bg-gray-100\" : \"bg-transparent\"\r\n )}\r\n onFocus={() => setIsFocused(true)}\r\n onBlur={() => setIsFocused(false)}\r\n >\r\n <div className=\"flex relative grow shrink basis-0 min-h-5 lg:min-h-[32px] justify-start items-stretch gap-2 max-w-full \">\r\n {!fileData ? (\r\n <div\r\n {...getRootProps()}\r\n className={`w-full p-4 border-dashed border-2 rounded-lg text-center ${\r\n isDragActive\r\n ? \"border-indigo-300 bg-indigo-50\"\r\n : \"border-gray-300\"\r\n }`}\r\n >\r\n <input {...getInputProps()} id={name} />\r\n <p className=\"text-gray-500\">\r\n {isDragActive\r\n ? \"Sem přetáhněte soubor\"\r\n : \"Klikněte pro nahrání, nebo nahrajte přetažením souboru\"}\r\n </p>\r\n </div>\r\n ) : (\r\n <div className=\"w-full flex items-center justify-between\">\r\n <div className=\" flex\">\r\n <MdInsertDriveFile style={{ fontSize: \"2rem\" }} />\r\n <a\r\n href={`/api/files/download/${fileData.id}`}\r\n className=\"pl-2 text-left underline text-primary\"\r\n target=\"_blank\"\r\n >\r\n {fileData.filename}\r\n </a>\r\n </div>\r\n {!disabled && (\r\n <div\r\n onClick={handleRemove}\r\n className=\"text-gray-600 cursor-pointer hover:text-primary hover:bg-gray-200 rounded-full ml-4\"\r\n >\r\n <MdDeleteOutline\r\n style={{ fontSize: \"1.5rem\", margin: \"15px\" }}\r\n />\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n {description && (\r\n <div\r\n className=\"HintText self-stretch text-slate-600 text-sm font-normal leading-tight\"\r\n id={name + \":description\"}\r\n >\r\n {description}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\nexport default FileInput;\r\n"],"names":[],"mappings":"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"}
|
|
@@ -52,7 +52,7 @@ const MultiSelect = React.forwardRef(
|
|
|
52
52
|
}, ref) => {
|
|
53
53
|
var _a;
|
|
54
54
|
const [selectedValues, setSelectedValues] = React.useState(
|
|
55
|
-
propValue ?? defaultValue
|
|
55
|
+
propValue ?? defaultValue ?? []
|
|
56
56
|
);
|
|
57
57
|
const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);
|
|
58
58
|
React.useEffect(() => {
|
|
@@ -71,18 +71,18 @@ const MultiSelect = React.forwardRef(
|
|
|
71
71
|
if (option === null)
|
|
72
72
|
return;
|
|
73
73
|
const optionStr = String(option);
|
|
74
|
-
const newSelectedValues = selectedValues.includes(optionStr) ? selectedValues.filter((value) => value !== optionStr) : [...selectedValues, optionStr];
|
|
75
|
-
handleValueChange(newSelectedValues);
|
|
74
|
+
const newSelectedValues = (selectedValues == null ? void 0 : selectedValues.includes(optionStr)) ? selectedValues == null ? void 0 : selectedValues.filter((value) => value !== optionStr) : [...selectedValues, optionStr];
|
|
75
|
+
handleValueChange(newSelectedValues || []);
|
|
76
76
|
};
|
|
77
77
|
const handleClear = () => {
|
|
78
78
|
handleValueChange([]);
|
|
79
79
|
};
|
|
80
80
|
const clearExtraOptions = () => {
|
|
81
|
-
const newSelectedValues = selectedValues.slice(0, maxCount);
|
|
81
|
+
const newSelectedValues = selectedValues == null ? void 0 : selectedValues.slice(0, maxCount);
|
|
82
82
|
handleValueChange(newSelectedValues);
|
|
83
83
|
};
|
|
84
84
|
const toggleAll = () => {
|
|
85
|
-
if (selectedValues.length === options.length) {
|
|
85
|
+
if ((selectedValues == null ? void 0 : selectedValues.length) === options.length) {
|
|
86
86
|
handleClear();
|
|
87
87
|
} else {
|
|
88
88
|
const allValues = options.map((option) => option.value);
|
|
@@ -106,11 +106,11 @@ const MultiSelect = React.forwardRef(
|
|
|
106
106
|
"flex w-full p-1 rounded-md border min-h-10 h-auto items-center justify-between hover:bg-inherit [&_svg]:pointer-events-auto font-normal bg-background text-muted-foreground",
|
|
107
107
|
className
|
|
108
108
|
),
|
|
109
|
-
children: selectedValues.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center w-full", children: [
|
|
109
|
+
children: (selectedValues == null ? void 0 : selectedValues.length) > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center w-full", children: [
|
|
110
110
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center", children: [
|
|
111
|
-
maxCount === 0 && selectedValues.length == 1 && /* @__PURE__ */ jsx("span", { className: "px-2", children: (_a = options.find((o) => o.value === selectedValues[0])) == null ? void 0 : _a.label }),
|
|
112
|
-
maxCount === 0 && selectedValues.length > 1 && /* @__PURE__ */ jsx("span", { className: "px-2", children: `Více (${selectedValues.length})` }),
|
|
113
|
-
maxCount > 0 && selectedValues.slice(0, maxCount).map((value) => {
|
|
111
|
+
maxCount === 0 && (selectedValues == null ? void 0 : selectedValues.length) == 1 && /* @__PURE__ */ jsx("span", { className: "px-2", children: (_a = options.find((o) => o.value === selectedValues[0])) == null ? void 0 : _a.label }),
|
|
112
|
+
maxCount === 0 && (selectedValues == null ? void 0 : selectedValues.length) > 1 && /* @__PURE__ */ jsx("span", { className: "px-2", children: `Více (${selectedValues == null ? void 0 : selectedValues.length})` }),
|
|
113
|
+
maxCount > 0 && (selectedValues == null ? void 0 : selectedValues.slice(0, maxCount).map((value) => {
|
|
114
114
|
const option = options.find((o) => o.value === value);
|
|
115
115
|
return /* @__PURE__ */ jsxs(
|
|
116
116
|
Badge,
|
|
@@ -132,8 +132,8 @@ const MultiSelect = React.forwardRef(
|
|
|
132
132
|
},
|
|
133
133
|
value
|
|
134
134
|
);
|
|
135
|
-
}),
|
|
136
|
-
maxCount > 0 && selectedValues.length > maxCount && /* @__PURE__ */ jsxs(
|
|
135
|
+
})),
|
|
136
|
+
maxCount > 0 && (selectedValues == null ? void 0 : selectedValues.length) > maxCount && /* @__PURE__ */ jsxs(
|
|
137
137
|
Badge,
|
|
138
138
|
{
|
|
139
139
|
className: cn(
|
|
@@ -141,7 +141,7 @@ const MultiSelect = React.forwardRef(
|
|
|
141
141
|
multiSelectVariants({ variant })
|
|
142
142
|
),
|
|
143
143
|
children: [
|
|
144
|
-
`Více (${selectedValues.length - maxCount})`,
|
|
144
|
+
`Více (${(selectedValues == null ? void 0 : selectedValues.length) - maxCount})`,
|
|
145
145
|
/* @__PURE__ */ jsx(
|
|
146
146
|
CircleX,
|
|
147
147
|
{
|
|
@@ -197,7 +197,7 @@ const MultiSelect = React.forwardRef(
|
|
|
197
197
|
if (e.key === "Enter") {
|
|
198
198
|
setIsPopoverOpen(true);
|
|
199
199
|
} else if (e.key === "Backspace" && !e.currentTarget.value) {
|
|
200
|
-
const newSelectedValues = [...selectedValues];
|
|
200
|
+
const newSelectedValues = [...selectedValues || []];
|
|
201
201
|
newSelectedValues.pop();
|
|
202
202
|
handleValueChange(newSelectedValues);
|
|
203
203
|
}
|
|
@@ -218,7 +218,7 @@ const MultiSelect = React.forwardRef(
|
|
|
218
218
|
{
|
|
219
219
|
className: cn(
|
|
220
220
|
"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
|
|
221
|
-
selectedValues && selectedValues.length === options.length ? "bg-primary text-primary-foreground" : "opacity-50 [&_svg]:invisible"
|
|
221
|
+
selectedValues && (selectedValues == null ? void 0 : selectedValues.length) === options.length ? "bg-primary text-primary-foreground" : "opacity-50 [&_svg]:invisible"
|
|
222
222
|
),
|
|
223
223
|
children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" })
|
|
224
224
|
}
|
|
@@ -256,7 +256,7 @@ const MultiSelect = React.forwardRef(
|
|
|
256
256
|
] }),
|
|
257
257
|
/* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
258
258
|
/* @__PURE__ */ jsx(CommandGroup, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
259
|
-
selectedValues.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
259
|
+
(selectedValues == null ? void 0 : selectedValues.length) > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
260
260
|
/* @__PURE__ */ jsx(
|
|
261
261
|
CommandItem,
|
|
262
262
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multi-select.js","sources":["../../../node_modules/lucide-react/dist/esm/icons/circle-x.js","../../../lib/components/ui/multi-select.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.456.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleX = createLucideIcon(\"CircleX\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"m15 9-6 6\", key: \"1uzhvr\" }],\n [\"path\", { d: \"m9 9 6 6\", key: \"z0biqf\" }]\n]);\n\nexport { CircleX as default };\n//# sourceMappingURL=circle-x.js.map\n","// src/components/multi-select.tsx\r\n\r\nimport * as React from \"react\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { CheckIcon, XCircle, ChevronDown, XIcon } from \"lucide-react\";\r\n\r\nimport { cn } from \"../../utils/utils\";\r\nimport { Separator } from \"./separator\";\r\nimport { Button } from \"./button\";\r\nimport { Badge } from \"./badge\";\r\nimport { Popover, PopoverContent, PopoverTrigger } from \"./popover\";\r\nimport {\r\n Command,\r\n CommandEmpty,\r\n CommandGroup,\r\n CommandInput,\r\n CommandItem,\r\n CommandList,\r\n CommandSeparator,\r\n} from \"./command\";\r\nimport { IOptionItem } from \"../../types\";\r\n\r\n/**\r\n * Variants for the multi-select component to handle different styles.\r\n * Uses class-variance-authority (cva) to define different styles based on \"variant\" prop.\r\n */\r\nconst multiSelectVariants = cva(\"m-1 transition ease-in-out delay-150 \", {\r\n variants: {\r\n variant: {\r\n default:\r\n \"border-foreground/10 text-foreground bg-card hover:bg-card/80 font-normal\",\r\n secondary:\r\n \"border-foreground/10 bg-secondary text-secondary-foreground hover:bg-secondary/80 font-normal\",\r\n destructive:\r\n \"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80 font-normal\",\r\n inverted: \"inverted\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n },\r\n});\r\n\r\n/**\r\n * Props for MultiSelect component\r\n */\r\ninterface MultiSelectProps\r\n extends Omit<\r\n React.ButtonHTMLAttributes<HTMLButtonElement>,\r\n \"onChange\" | \"value\"\r\n >,\r\n VariantProps<typeof multiSelectVariants> {\r\n /**\r\n * An array of option objects to be displayed in the multi-select component.\r\n * Each option object has a label, value, and an optional icon.\r\n */\r\n options: IOptionItem[];\r\n\r\n /**\r\n * Callback function triggered when the selected values change.\r\n * Receives an array of the new selected values.\r\n */\r\n onChange: (value: string[]) => void;\r\n\r\n /** The controlled value of the component */\r\n value?: string[];\r\n\r\n /** The default selected values when the component mounts (uncontrolled mode) */\r\n defaultValue?: string[];\r\n\r\n /**\r\n * Placeholder text to be displayed when no values are selected.\r\n * Optional, defaults to \"Select options\".\r\n */\r\n placeholder?: string;\r\n\r\n /**\r\n * Placeholder text to be displayed when no values are selected.\r\n * Optional, defaults to \"Select options\".\r\n */\r\n placeholderSearch?: string;\r\n\r\n /**\r\n * Maximum number of items to display. Extra selected items will be summarized.\r\n * Optional, defaults to 3.\r\n */\r\n maxCount?: number;\r\n\r\n /**\r\n * The modality of the popover. When set to true, interaction with outside elements\r\n * will be disabled and only popover content will be visible to screen readers.\r\n * Optional, defaults to false.\r\n */\r\n modalPopover?: boolean;\r\n\r\n /**\r\n * If true, renders the multi-select component as a child of another component.\r\n * Optional, defaults to false.\r\n */\r\n asChild?: boolean;\r\n\r\n /**\r\n * Additional class names to apply custom styles to the multi-select component.\r\n * Optional, can be used to add custom styles.\r\n */\r\n className?: string;\r\n\r\n /**\r\n * If true, the multi-select component will be disabled.\r\n * Optional, defaults to false.\r\n */\r\n disabled?: boolean;\r\n\r\n /**\r\n * value?: string;\r\n onChange?: (value: string | undefined) => void;\r\n */\r\n}\r\n\r\nexport const MultiSelect = React.forwardRef<\r\n HTMLButtonElement,\r\n MultiSelectProps\r\n>(\r\n (\r\n {\r\n options,\r\n onChange,\r\n value: propValue,\r\n variant,\r\n defaultValue = [],\r\n placeholder = \"Vyberte možnosti\",\r\n placeholderSearch = \"Vyhledejte\",\r\n maxCount = 3,\r\n modalPopover = false,\r\n asChild = false,\r\n className,\r\n ...props\r\n },\r\n ref\r\n ) => {\r\n const [selectedValues, setSelectedValues] = React.useState<string[]>(\r\n propValue ?? defaultValue\r\n );\r\n const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);\r\n\r\n // Update internal state when controlled value changes\r\n React.useEffect(() => {\r\n if (propValue !== undefined) {\r\n setSelectedValues(propValue);\r\n }\r\n }, [propValue]);\r\n\r\n const handleValueChange = (newValues: string[]) => {\r\n setSelectedValues(newValues);\r\n onChange(newValues);\r\n };\r\n\r\n const handleTogglePopover = () => {\r\n setIsPopoverOpen((prev) => !prev);\r\n };\r\n\r\n const toggleOption = (option: string | number | null) => {\r\n if (option === null) return;\r\n const optionStr = String(option);\r\n const newSelectedValues = selectedValues.includes(optionStr)\r\n ? selectedValues.filter((value) => value !== optionStr)\r\n : [...selectedValues, optionStr];\r\n handleValueChange(newSelectedValues);\r\n };\r\n\r\n const handleClear = () => {\r\n handleValueChange([]);\r\n };\r\n\r\n const clearExtraOptions = () => {\r\n const newSelectedValues = selectedValues.slice(0, maxCount);\r\n handleValueChange(newSelectedValues);\r\n };\r\n\r\n const toggleAll = () => {\r\n if (selectedValues.length === options.length) {\r\n handleClear();\r\n } else {\r\n const allValues = options.map((option) => option.value as string);\r\n handleValueChange(allValues);\r\n }\r\n };\r\n\r\n return (\r\n <Popover\r\n open={isPopoverOpen}\r\n onOpenChange={setIsPopoverOpen}\r\n modal={modalPopover}\r\n >\r\n <PopoverTrigger asChild>\r\n <Button\r\n ref={ref}\r\n {...props}\r\n onClick={handleTogglePopover}\r\n className={cn(\r\n \"flex w-full p-1 rounded-md border min-h-10 h-auto items-center justify-between hover:bg-inherit [&_svg]:pointer-events-auto font-normal bg-background text-muted-foreground\",\r\n className\r\n )}\r\n >\r\n {selectedValues.length > 0 ? (\r\n <div className=\"flex justify-between items-center w-full\">\r\n <div className=\"flex flex-wrap items-center\">\r\n {maxCount === 0 && selectedValues.length == 1 && (\r\n <span className=\"px-2\">\r\n {\r\n options.find((o) => o.value === selectedValues[0])\r\n ?.label\r\n }\r\n </span>\r\n )}\r\n {maxCount === 0 && selectedValues.length > 1 && (\r\n <span className=\"px-2\">\r\n {`Více (${selectedValues.length})`}\r\n </span>\r\n )}\r\n {maxCount > 0 &&\r\n selectedValues.slice(0, maxCount).map((value) => {\r\n const option = options.find((o) => o.value === value);\r\n return (\r\n <Badge\r\n key={value}\r\n className={cn(multiSelectVariants({ variant }))}\r\n >\r\n {option?.label}\r\n <XCircle\r\n className=\"ml-2 h-4 w-4 cursor-pointer text-muted-foreground\"\r\n onClick={(event) => {\r\n event.stopPropagation();\r\n toggleOption(value);\r\n }}\r\n />\r\n </Badge>\r\n );\r\n })}\r\n\r\n {maxCount > 0 && selectedValues.length > maxCount && (\r\n <Badge\r\n className={cn(\r\n \"bg-transparent text-foreground border-foreground/1 hover:bg-transparent\",\r\n multiSelectVariants({ variant })\r\n )}\r\n >\r\n {`Více (${selectedValues.length - maxCount})`}\r\n <XCircle\r\n className=\"ml-2 h-4 w-4 cursor-pointer text-muted-foreground\"\r\n onClick={(event) => {\r\n event.stopPropagation();\r\n clearExtraOptions();\r\n }}\r\n />\r\n </Badge>\r\n )}\r\n </div>\r\n <div className=\"flex items-center justify-between\">\r\n <XIcon\r\n className=\"h-4 mx-2 cursor-pointer text-muted-foreground\"\r\n onClick={(event) => {\r\n event.stopPropagation();\r\n handleClear();\r\n }}\r\n />\r\n <Separator\r\n orientation=\"vertical\"\r\n className=\"flex min-h-6 h-full\"\r\n />\r\n <ChevronDown className=\"h-4 mx-2 cursor-pointer text-muted-foreground\" />\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"flex items-center justify-between w-full mx-auto\">\r\n <span className=\"text-sm text-muted-foreground mx-3\">\r\n {placeholder}\r\n </span>\r\n <ChevronDown className=\"h-4 cursor-pointer text-muted-foreground mx-2\" />\r\n </div>\r\n )}\r\n </Button>\r\n </PopoverTrigger>\r\n <PopoverContent\r\n className=\"w-auto p-0\"\r\n align=\"start\"\r\n onEscapeKeyDown={() => setIsPopoverOpen(false)}\r\n >\r\n <Command>\r\n <CommandInput\r\n placeholder={placeholderSearch}\r\n onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {\r\n if (e.key === \"Enter\") {\r\n setIsPopoverOpen(true);\r\n } else if (e.key === \"Backspace\" && !e.currentTarget.value) {\r\n const newSelectedValues = [...selectedValues];\r\n newSelectedValues.pop();\r\n handleValueChange(newSelectedValues);\r\n }\r\n }}\r\n />\r\n <CommandList>\r\n <CommandEmpty>No results found.</CommandEmpty>\r\n <CommandGroup>\r\n <CommandItem\r\n key=\"all\"\r\n onSelect={toggleAll}\r\n className=\"cursor-pointer\"\r\n >\r\n <div\r\n className={cn(\r\n \"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary\",\r\n selectedValues && selectedValues.length === options.length\r\n ? \"bg-primary text-primary-foreground\"\r\n : \"opacity-50 [&_svg]:invisible\"\r\n )}\r\n >\r\n <CheckIcon className=\"h-4 w-4\" />\r\n </div>\r\n <span>(Vyberte vše)</span>\r\n </CommandItem>\r\n {options.map((option) => {\r\n const optionStr = String(option.value);\r\n const isSelected =\r\n selectedValues?.includes(optionStr) || false;\r\n return (\r\n <CommandItem\r\n key={optionStr}\r\n onSelect={() => toggleOption(option.value)}\r\n className=\"cursor-pointer\"\r\n >\r\n <div\r\n className={cn(\r\n \"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary\",\r\n isSelected\r\n ? \"bg-primary text-primary-foreground\"\r\n : \"opacity-50 [&_svg]:invisible\"\r\n )}\r\n >\r\n <CheckIcon className=\"h-4 w-4\" />\r\n </div>\r\n\r\n <span>{option.label}</span>\r\n </CommandItem>\r\n );\r\n })}\r\n </CommandGroup>\r\n <CommandSeparator />\r\n <CommandGroup>\r\n <div className=\"flex items-center justify-between\">\r\n {selectedValues.length > 0 && (\r\n <>\r\n <CommandItem\r\n onSelect={handleClear}\r\n className=\"flex-1 justify-center cursor-pointer\"\r\n >\r\n Odebrat vše\r\n </CommandItem>\r\n <Separator\r\n orientation=\"vertical\"\r\n className=\"flex min-h-6 h-full\"\r\n />\r\n </>\r\n )}\r\n <CommandItem\r\n onSelect={() => setIsPopoverOpen(false)}\r\n className=\"flex-1 justify-center cursor-pointer max-w-full\"\r\n >\r\n Zavřít\r\n </CommandItem>\r\n </div>\r\n </CommandGroup>\r\n </CommandList>\r\n </Command>\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n }\r\n);\r\n\r\nMultiSelect.displayName = \"MultiSelect\";\r\n"],"names":["XCircle","XIcon","CheckIcon"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"multi-select.js","sources":["../../../node_modules/lucide-react/dist/esm/icons/circle-x.js","../../../lib/components/ui/multi-select.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.456.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleX = createLucideIcon(\"CircleX\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"m15 9-6 6\", key: \"1uzhvr\" }],\n [\"path\", { d: \"m9 9 6 6\", key: \"z0biqf\" }]\n]);\n\nexport { CircleX as default };\n//# sourceMappingURL=circle-x.js.map\n","// src/components/multi-select.tsx\r\n\r\nimport * as React from \"react\";\r\nimport { cva, type VariantProps } from \"class-variance-authority\";\r\nimport { CheckIcon, XCircle, ChevronDown, XIcon } from \"lucide-react\";\r\n\r\nimport { cn } from \"../../utils/utils\";\r\nimport { Separator } from \"./separator\";\r\nimport { Button } from \"./button\";\r\nimport { Badge } from \"./badge\";\r\nimport { Popover, PopoverContent, PopoverTrigger } from \"./popover\";\r\nimport {\r\n Command,\r\n CommandEmpty,\r\n CommandGroup,\r\n CommandInput,\r\n CommandItem,\r\n CommandList,\r\n CommandSeparator,\r\n} from \"./command\";\r\nimport { IOptionItem } from \"../../types\";\r\n\r\n/**\r\n * Variants for the multi-select component to handle different styles.\r\n * Uses class-variance-authority (cva) to define different styles based on \"variant\" prop.\r\n */\r\nconst multiSelectVariants = cva(\"m-1 transition ease-in-out delay-150 \", {\r\n variants: {\r\n variant: {\r\n default:\r\n \"border-foreground/10 text-foreground bg-card hover:bg-card/80 font-normal\",\r\n secondary:\r\n \"border-foreground/10 bg-secondary text-secondary-foreground hover:bg-secondary/80 font-normal\",\r\n destructive:\r\n \"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80 font-normal\",\r\n inverted: \"inverted\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n },\r\n});\r\n\r\n/**\r\n * Props for MultiSelect component\r\n */\r\ninterface MultiSelectProps\r\n extends Omit<\r\n React.ButtonHTMLAttributes<HTMLButtonElement>,\r\n \"onChange\" | \"value\"\r\n >,\r\n VariantProps<typeof multiSelectVariants> {\r\n /**\r\n * An array of option objects to be displayed in the multi-select component.\r\n * Each option object has a label, value, and an optional icon.\r\n */\r\n options: IOptionItem[];\r\n\r\n /**\r\n * Callback function triggered when the selected values change.\r\n * Receives an array of the new selected values.\r\n */\r\n onChange: (value: string[]) => void;\r\n\r\n /** The controlled value of the component */\r\n value?: string[];\r\n\r\n /** The default selected values when the component mounts (uncontrolled mode) */\r\n defaultValue?: string[];\r\n\r\n /**\r\n * Placeholder text to be displayed when no values are selected.\r\n * Optional, defaults to \"Select options\".\r\n */\r\n placeholder?: string;\r\n\r\n /**\r\n * Placeholder text to be displayed when no values are selected.\r\n * Optional, defaults to \"Select options\".\r\n */\r\n placeholderSearch?: string;\r\n\r\n /**\r\n * Maximum number of items to display. Extra selected items will be summarized.\r\n * Optional, defaults to 3.\r\n */\r\n maxCount?: number;\r\n\r\n /**\r\n * The modality of the popover. When set to true, interaction with outside elements\r\n * will be disabled and only popover content will be visible to screen readers.\r\n * Optional, defaults to false.\r\n */\r\n modalPopover?: boolean;\r\n\r\n /**\r\n * If true, renders the multi-select component as a child of another component.\r\n * Optional, defaults to false.\r\n */\r\n asChild?: boolean;\r\n\r\n /**\r\n * Additional class names to apply custom styles to the multi-select component.\r\n * Optional, can be used to add custom styles.\r\n */\r\n className?: string;\r\n\r\n /**\r\n * If true, the multi-select component will be disabled.\r\n * Optional, defaults to false.\r\n */\r\n disabled?: boolean;\r\n\r\n /**\r\n * value?: string;\r\n onChange?: (value: string | undefined) => void;\r\n */\r\n}\r\n\r\nexport const MultiSelect = React.forwardRef<\r\n HTMLButtonElement,\r\n MultiSelectProps\r\n>(\r\n (\r\n {\r\n options,\r\n onChange,\r\n value: propValue,\r\n variant,\r\n defaultValue = [],\r\n placeholder = \"Vyberte možnosti\",\r\n placeholderSearch = \"Vyhledejte\",\r\n maxCount = 3,\r\n modalPopover = false,\r\n asChild = false,\r\n className,\r\n ...props\r\n },\r\n ref\r\n ) => {\r\n const [selectedValues, setSelectedValues] = React.useState<string[]>(\r\n propValue ?? defaultValue ?? []\r\n );\r\n const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);\r\n\r\n // Update internal state when controlled value changes\r\n React.useEffect(() => {\r\n if (propValue !== undefined) {\r\n setSelectedValues(propValue);\r\n }\r\n }, [propValue]);\r\n\r\n const handleValueChange = (newValues: string[]) => {\r\n setSelectedValues(newValues);\r\n onChange(newValues);\r\n };\r\n\r\n const handleTogglePopover = () => {\r\n setIsPopoverOpen((prev) => !prev);\r\n };\r\n\r\n const toggleOption = (option: string | number | null) => {\r\n if (option === null) return;\r\n const optionStr = String(option);\r\n const newSelectedValues = selectedValues?.includes(optionStr)\r\n ? selectedValues?.filter((value) => value !== optionStr)\r\n : [...selectedValues, optionStr];\r\n handleValueChange(newSelectedValues || []);\r\n };\r\n\r\n const handleClear = () => {\r\n handleValueChange([]);\r\n };\r\n\r\n const clearExtraOptions = () => {\r\n const newSelectedValues = selectedValues?.slice(0, maxCount);\r\n handleValueChange(newSelectedValues);\r\n };\r\n\r\n const toggleAll = () => {\r\n if (selectedValues?.length === options.length) {\r\n handleClear();\r\n } else {\r\n const allValues = options.map((option) => option.value as string);\r\n handleValueChange(allValues);\r\n }\r\n };\r\n\r\n return (\r\n <Popover\r\n open={isPopoverOpen}\r\n onOpenChange={setIsPopoverOpen}\r\n modal={modalPopover}\r\n >\r\n <PopoverTrigger asChild>\r\n <Button\r\n ref={ref}\r\n {...props}\r\n onClick={handleTogglePopover}\r\n className={cn(\r\n \"flex w-full p-1 rounded-md border min-h-10 h-auto items-center justify-between hover:bg-inherit [&_svg]:pointer-events-auto font-normal bg-background text-muted-foreground\",\r\n className\r\n )}\r\n >\r\n {selectedValues?.length > 0 ? (\r\n <div className=\"flex justify-between items-center w-full\">\r\n <div className=\"flex flex-wrap items-center\">\r\n {maxCount === 0 && selectedValues?.length == 1 && (\r\n <span className=\"px-2\">\r\n {\r\n options.find((o) => o.value === selectedValues[0])\r\n ?.label\r\n }\r\n </span>\r\n )}\r\n {maxCount === 0 && selectedValues?.length > 1 && (\r\n <span className=\"px-2\">\r\n {`Více (${selectedValues?.length})`}\r\n </span>\r\n )}\r\n {maxCount > 0 &&\r\n selectedValues?.slice(0, maxCount).map((value) => {\r\n const option = options.find((o) => o.value === value);\r\n return (\r\n <Badge\r\n key={value}\r\n className={cn(multiSelectVariants({ variant }))}\r\n >\r\n {option?.label}\r\n <XCircle\r\n className=\"ml-2 h-4 w-4 cursor-pointer text-muted-foreground\"\r\n onClick={(event) => {\r\n event.stopPropagation();\r\n toggleOption(value);\r\n }}\r\n />\r\n </Badge>\r\n );\r\n })}\r\n\r\n {maxCount > 0 && selectedValues?.length > maxCount && (\r\n <Badge\r\n className={cn(\r\n \"bg-transparent text-foreground border-foreground/1 hover:bg-transparent\",\r\n multiSelectVariants({ variant })\r\n )}\r\n >\r\n {`Více (${selectedValues?.length - maxCount})`}\r\n <XCircle\r\n className=\"ml-2 h-4 w-4 cursor-pointer text-muted-foreground\"\r\n onClick={(event) => {\r\n event.stopPropagation();\r\n clearExtraOptions();\r\n }}\r\n />\r\n </Badge>\r\n )}\r\n </div>\r\n <div className=\"flex items-center justify-between\">\r\n <XIcon\r\n className=\"h-4 mx-2 cursor-pointer text-muted-foreground\"\r\n onClick={(event) => {\r\n event.stopPropagation();\r\n handleClear();\r\n }}\r\n />\r\n <Separator\r\n orientation=\"vertical\"\r\n className=\"flex min-h-6 h-full\"\r\n />\r\n <ChevronDown className=\"h-4 mx-2 cursor-pointer text-muted-foreground\" />\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"flex items-center justify-between w-full mx-auto\">\r\n <span className=\"text-sm text-muted-foreground mx-3\">\r\n {placeholder}\r\n </span>\r\n <ChevronDown className=\"h-4 cursor-pointer text-muted-foreground mx-2\" />\r\n </div>\r\n )}\r\n </Button>\r\n </PopoverTrigger>\r\n <PopoverContent\r\n className=\"w-auto p-0\"\r\n align=\"start\"\r\n onEscapeKeyDown={() => setIsPopoverOpen(false)}\r\n >\r\n <Command>\r\n <CommandInput\r\n placeholder={placeholderSearch}\r\n onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {\r\n if (e.key === \"Enter\") {\r\n setIsPopoverOpen(true);\r\n } else if (e.key === \"Backspace\" && !e.currentTarget.value) {\r\n const newSelectedValues = [...(selectedValues || [])];\r\n newSelectedValues.pop();\r\n handleValueChange(newSelectedValues);\r\n }\r\n }}\r\n />\r\n <CommandList>\r\n <CommandEmpty>No results found.</CommandEmpty>\r\n <CommandGroup>\r\n <CommandItem\r\n key=\"all\"\r\n onSelect={toggleAll}\r\n className=\"cursor-pointer\"\r\n >\r\n <div\r\n className={cn(\r\n \"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary\",\r\n selectedValues &&\r\n selectedValues?.length === options.length\r\n ? \"bg-primary text-primary-foreground\"\r\n : \"opacity-50 [&_svg]:invisible\"\r\n )}\r\n >\r\n <CheckIcon className=\"h-4 w-4\" />\r\n </div>\r\n <span>(Vyberte vše)</span>\r\n </CommandItem>\r\n {options.map((option) => {\r\n const optionStr = String(option.value);\r\n const isSelected =\r\n selectedValues?.includes(optionStr) || false;\r\n return (\r\n <CommandItem\r\n key={optionStr}\r\n onSelect={() => toggleOption(option.value)}\r\n className=\"cursor-pointer\"\r\n >\r\n <div\r\n className={cn(\r\n \"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary\",\r\n isSelected\r\n ? \"bg-primary text-primary-foreground\"\r\n : \"opacity-50 [&_svg]:invisible\"\r\n )}\r\n >\r\n <CheckIcon className=\"h-4 w-4\" />\r\n </div>\r\n\r\n <span>{option.label}</span>\r\n </CommandItem>\r\n );\r\n })}\r\n </CommandGroup>\r\n <CommandSeparator />\r\n <CommandGroup>\r\n <div className=\"flex items-center justify-between\">\r\n {selectedValues?.length > 0 && (\r\n <>\r\n <CommandItem\r\n onSelect={handleClear}\r\n className=\"flex-1 justify-center cursor-pointer\"\r\n >\r\n Odebrat vše\r\n </CommandItem>\r\n <Separator\r\n orientation=\"vertical\"\r\n className=\"flex min-h-6 h-full\"\r\n />\r\n </>\r\n )}\r\n <CommandItem\r\n onSelect={() => setIsPopoverOpen(false)}\r\n className=\"flex-1 justify-center cursor-pointer max-w-full\"\r\n >\r\n Zavřít\r\n </CommandItem>\r\n </div>\r\n </CommandGroup>\r\n </CommandList>\r\n </Command>\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n }\r\n);\r\n\r\nMultiSelect.displayName = \"MultiSelect\";\r\n"],"names":["XCircle","XIcon","CheckIcon"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1,211 +1,211 @@
|
|
|
1
|
-
import React, { useState, useEffect, useCallback } from "react";
|
|
2
|
-
import { useDropzone } from "react-dropzone";
|
|
3
|
-
import { handleErrors, useFederationContext } from "../../main";
|
|
4
|
-
import { MdDeleteOutline, MdInsertDriveFile } from "react-icons/md";
|
|
5
|
-
import { AxiosError } from "axios";
|
|
6
|
-
import { cn } from "../../utils/utils";
|
|
7
|
-
|
|
8
|
-
export interface FileData {
|
|
9
|
-
id: number;
|
|
10
|
-
mimeType: string;
|
|
11
|
-
size: number;
|
|
12
|
-
filename: string;
|
|
13
|
-
createdByEmpId: string;
|
|
14
|
-
created: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface FileInputProps {
|
|
18
|
-
name: string;
|
|
19
|
-
label?: string;
|
|
20
|
-
initialFile?: FileData;
|
|
21
|
-
onFileChanged: (e: any) => void;
|
|
22
|
-
required?: boolean;
|
|
23
|
-
description?: string;
|
|
24
|
-
disabled?: boolean;
|
|
25
|
-
attachmentName?: string;
|
|
26
|
-
attachmentType?: string;
|
|
27
|
-
hasError?: boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const MAX_FILE_SIZE = 1024 * 1024; // 1MB
|
|
31
|
-
|
|
32
|
-
const FileInput: React.FC<FileInputProps> = ({
|
|
33
|
-
initialFile,
|
|
34
|
-
onFileChanged,
|
|
35
|
-
label,
|
|
36
|
-
name,
|
|
37
|
-
required,
|
|
38
|
-
description,
|
|
39
|
-
disabled,
|
|
40
|
-
attachmentName,
|
|
41
|
-
attachmentType,
|
|
42
|
-
hasError,
|
|
43
|
-
}) => {
|
|
44
|
-
const [fileData, setFileData] = useState<FileData | null>(
|
|
45
|
-
initialFile || null
|
|
46
|
-
);
|
|
47
|
-
const [isFocused, setIsFocused] = useState(false);
|
|
48
|
-
|
|
49
|
-
const federationContext = useFederationContext();
|
|
50
|
-
useEffect(() => {
|
|
51
|
-
if (initialFile) {
|
|
52
|
-
setFileData(initialFile);
|
|
53
|
-
}
|
|
54
|
-
}, [initialFile]);
|
|
55
|
-
|
|
56
|
-
const onDrop = useCallback(
|
|
57
|
-
async (acceptedFiles: File[]) => {
|
|
58
|
-
if (acceptedFiles.length > 0) {
|
|
59
|
-
const file = acceptedFiles[0];
|
|
60
|
-
|
|
61
|
-
if (file.size > MAX_FILE_SIZE) {
|
|
62
|
-
// Handle the case when the file size is exceeded
|
|
63
|
-
federationContext.emitter.emit("message", {
|
|
64
|
-
title: "Velikost souboru byla překročena",
|
|
65
|
-
message: `Maximální povolená velikost je ${MAX_FILE_SIZE / (1024 * 1024)} MB.`,
|
|
66
|
-
classes: "bg-danger ",
|
|
67
|
-
timeout: 0,
|
|
68
|
-
type: "error",
|
|
69
|
-
});
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const formData = new FormData();
|
|
74
|
-
|
|
75
|
-
// Add the JSON data object
|
|
76
|
-
const dataObject = {
|
|
77
|
-
...(attachmentName && { attachmentName }),
|
|
78
|
-
...(attachmentType && { attachmentType }),
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
formData.append(
|
|
82
|
-
"data",
|
|
83
|
-
new Blob([JSON.stringify(dataObject)], { type: "application/json" })
|
|
84
|
-
);
|
|
85
|
-
formData.append("file", file);
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
const response = await federationContext.apiClient.post<FileData>(
|
|
89
|
-
"/files/upload",
|
|
90
|
-
formData,
|
|
91
|
-
{
|
|
92
|
-
headers: {
|
|
93
|
-
"Content-Type": "multipart/form-data",
|
|
94
|
-
},
|
|
95
|
-
}
|
|
96
|
-
);
|
|
97
|
-
setFileData(response.data);
|
|
98
|
-
onFileChanged({
|
|
99
|
-
target: { name, value: response.data.id.toString() },
|
|
100
|
-
});
|
|
101
|
-
setIsFocused(false);
|
|
102
|
-
} catch (error) {
|
|
103
|
-
handleErrors(error as AxiosError, federationContext.emitter);
|
|
104
|
-
console.error("There was an error!", error);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
[
|
|
109
|
-
federationContext.apiClient,
|
|
110
|
-
federationContext.emitter,
|
|
111
|
-
onFileChanged,
|
|
112
|
-
name,
|
|
113
|
-
attachmentName,
|
|
114
|
-
attachmentType,
|
|
115
|
-
]
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
|
119
|
-
onDrop,
|
|
120
|
-
disabled,
|
|
121
|
-
multiple: false,
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
const handleRemove = () => {
|
|
125
|
-
setFileData(null);
|
|
126
|
-
onFileChanged({ target: { name, value: null } });
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
return (
|
|
130
|
-
<div className="w-full min-h-30 flex-col justify-start items-start gap-1.5 inline-flex sharedLibrary">
|
|
131
|
-
<div className="self-stretch flex-col justify-start items-start gap-1.5 flex">
|
|
132
|
-
{label && (
|
|
133
|
-
<label
|
|
134
|
-
className="text-slate-700 text-sm leading-tight font-medium"
|
|
135
|
-
htmlFor={name}
|
|
136
|
-
>
|
|
137
|
-
{label} {required ? "*" : ""}
|
|
138
|
-
</label>
|
|
139
|
-
)}
|
|
140
|
-
<div
|
|
141
|
-
className={cn(
|
|
142
|
-
`self-stretch px-2 py-2 rounded-lg justify-start items-center gap-2 inline-flex outline-none border`,
|
|
143
|
-
isFocused &&
|
|
144
|
-
!hasError &&
|
|
145
|
-
"outline-4 outline-indigo-200 outline-offset-0 border-indigo-300",
|
|
146
|
-
|
|
147
|
-
hasError &&
|
|
148
|
-
"outline-4 outline-red-200 outline-offset-0 border-none",
|
|
149
|
-
!isFocused && hasError && "border-red-200 ",
|
|
150
|
-
disabled ? "bg-gray-100" : "bg-transparent"
|
|
151
|
-
)}
|
|
152
|
-
onFocus={() => setIsFocused(true)}
|
|
153
|
-
onBlur={() => setIsFocused(false)}
|
|
154
|
-
>
|
|
155
|
-
<div className="flex relative grow shrink basis-0 min-h-5 lg:min-h-[32px] justify-start items-stretch gap-2 max-w-full ">
|
|
156
|
-
{!fileData ? (
|
|
157
|
-
<div
|
|
158
|
-
{...getRootProps()}
|
|
159
|
-
className={`w-full p-4 border-dashed border-2 rounded-lg text-center ${
|
|
160
|
-
isDragActive
|
|
161
|
-
? "border-indigo-300 bg-indigo-50"
|
|
162
|
-
: "border-gray-300"
|
|
163
|
-
}`}
|
|
164
|
-
>
|
|
165
|
-
<input {...getInputProps()} id={name} />
|
|
166
|
-
<p className="text-gray-500">
|
|
167
|
-
{isDragActive
|
|
168
|
-
? "Sem přetáhněte soubor"
|
|
169
|
-
: "Klikněte pro nahrání, nebo nahrajte přetažením souboru"}
|
|
170
|
-
</p>
|
|
171
|
-
</div>
|
|
172
|
-
) : (
|
|
173
|
-
<div className="w-full flex items-center justify-between">
|
|
174
|
-
<div className=" flex">
|
|
175
|
-
<MdInsertDriveFile style={{ fontSize: "2rem" }} />
|
|
176
|
-
<a
|
|
177
|
-
href={`/api/files/download/${fileData.id}`}
|
|
178
|
-
className="pl-2 text-left underline text-primary"
|
|
179
|
-
target="_blank"
|
|
180
|
-
>
|
|
181
|
-
{fileData.filename}
|
|
182
|
-
</a>
|
|
183
|
-
</div>
|
|
184
|
-
{!disabled && (
|
|
185
|
-
<div
|
|
186
|
-
onClick={handleRemove}
|
|
187
|
-
className="text-gray-600 cursor-pointer hover:text-primary hover:bg-gray-200 rounded-full ml-4"
|
|
188
|
-
>
|
|
189
|
-
<MdDeleteOutline
|
|
190
|
-
style={{ fontSize: "1.5rem", margin: "15px" }}
|
|
191
|
-
/>
|
|
192
|
-
</div>
|
|
193
|
-
)}
|
|
194
|
-
</div>
|
|
195
|
-
)}
|
|
196
|
-
</div>
|
|
197
|
-
</div>
|
|
198
|
-
</div>
|
|
199
|
-
{description && (
|
|
200
|
-
<div
|
|
201
|
-
className="HintText self-stretch text-slate-600 text-sm font-normal leading-tight"
|
|
202
|
-
id={name + ":description"}
|
|
203
|
-
>
|
|
204
|
-
{description}
|
|
205
|
-
</div>
|
|
206
|
-
)}
|
|
207
|
-
</div>
|
|
208
|
-
);
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
export default FileInput;
|
|
1
|
+
import React, { useState, useEffect, useCallback } from "react";
|
|
2
|
+
import { useDropzone } from "react-dropzone";
|
|
3
|
+
import { handleErrors, useFederationContext } from "../../main";
|
|
4
|
+
import { MdDeleteOutline, MdInsertDriveFile } from "react-icons/md";
|
|
5
|
+
import { AxiosError } from "axios";
|
|
6
|
+
import { cn } from "../../utils/utils";
|
|
7
|
+
|
|
8
|
+
export interface FileData {
|
|
9
|
+
id: number;
|
|
10
|
+
mimeType: string;
|
|
11
|
+
size: number;
|
|
12
|
+
filename: string;
|
|
13
|
+
createdByEmpId: string;
|
|
14
|
+
created: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface FileInputProps {
|
|
18
|
+
name: string;
|
|
19
|
+
label?: string;
|
|
20
|
+
initialFile?: FileData;
|
|
21
|
+
onFileChanged: (e: any) => void;
|
|
22
|
+
required?: boolean;
|
|
23
|
+
description?: string;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
attachmentName?: string;
|
|
26
|
+
attachmentType?: string;
|
|
27
|
+
hasError?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const MAX_FILE_SIZE = 1024 * 1024; // 1MB
|
|
31
|
+
|
|
32
|
+
const FileInput: React.FC<FileInputProps> = ({
|
|
33
|
+
initialFile,
|
|
34
|
+
onFileChanged,
|
|
35
|
+
label,
|
|
36
|
+
name,
|
|
37
|
+
required,
|
|
38
|
+
description,
|
|
39
|
+
disabled,
|
|
40
|
+
attachmentName,
|
|
41
|
+
attachmentType,
|
|
42
|
+
hasError,
|
|
43
|
+
}) => {
|
|
44
|
+
const [fileData, setFileData] = useState<FileData | null>(
|
|
45
|
+
initialFile || null
|
|
46
|
+
);
|
|
47
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
48
|
+
|
|
49
|
+
const federationContext = useFederationContext();
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (initialFile) {
|
|
52
|
+
setFileData(initialFile);
|
|
53
|
+
}
|
|
54
|
+
}, [initialFile]);
|
|
55
|
+
|
|
56
|
+
const onDrop = useCallback(
|
|
57
|
+
async (acceptedFiles: File[]) => {
|
|
58
|
+
if (acceptedFiles.length > 0) {
|
|
59
|
+
const file = acceptedFiles[0];
|
|
60
|
+
|
|
61
|
+
if (file.size > MAX_FILE_SIZE) {
|
|
62
|
+
// Handle the case when the file size is exceeded
|
|
63
|
+
federationContext.emitter.emit("message", {
|
|
64
|
+
title: "Velikost souboru byla překročena",
|
|
65
|
+
message: `Maximální povolená velikost je ${MAX_FILE_SIZE / (1024 * 1024)} MB.`,
|
|
66
|
+
classes: "bg-danger ",
|
|
67
|
+
timeout: 0,
|
|
68
|
+
type: "error",
|
|
69
|
+
});
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const formData = new FormData();
|
|
74
|
+
|
|
75
|
+
// Add the JSON data object
|
|
76
|
+
const dataObject = {
|
|
77
|
+
...(attachmentName && { attachmentName }),
|
|
78
|
+
...(attachmentType && { attachmentType }),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
formData.append(
|
|
82
|
+
"data",
|
|
83
|
+
new Blob([JSON.stringify(dataObject)], { type: "application/json" })
|
|
84
|
+
);
|
|
85
|
+
formData.append("file", file);
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const response = await federationContext.apiClient.post<FileData>(
|
|
89
|
+
"/files/upload",
|
|
90
|
+
formData,
|
|
91
|
+
{
|
|
92
|
+
headers: {
|
|
93
|
+
"Content-Type": "multipart/form-data",
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
setFileData(response.data);
|
|
98
|
+
onFileChanged({
|
|
99
|
+
target: { name, value: response.data.id.toString() },
|
|
100
|
+
});
|
|
101
|
+
setIsFocused(false);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
handleErrors(error as AxiosError, federationContext.emitter);
|
|
104
|
+
console.error("There was an error!", error);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
[
|
|
109
|
+
federationContext.apiClient,
|
|
110
|
+
federationContext.emitter,
|
|
111
|
+
onFileChanged,
|
|
112
|
+
name,
|
|
113
|
+
attachmentName,
|
|
114
|
+
attachmentType,
|
|
115
|
+
]
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
|
119
|
+
onDrop,
|
|
120
|
+
disabled,
|
|
121
|
+
multiple: false,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const handleRemove = () => {
|
|
125
|
+
setFileData(null);
|
|
126
|
+
onFileChanged({ target: { name, value: null } });
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<div className="w-full min-h-30 flex-col justify-start items-start gap-1.5 inline-flex sharedLibrary">
|
|
131
|
+
<div className="self-stretch flex-col justify-start items-start gap-1.5 flex">
|
|
132
|
+
{label && (
|
|
133
|
+
<label
|
|
134
|
+
className="text-slate-700 text-sm leading-tight font-medium"
|
|
135
|
+
htmlFor={name}
|
|
136
|
+
>
|
|
137
|
+
{label} {required ? "*" : ""}
|
|
138
|
+
</label>
|
|
139
|
+
)}
|
|
140
|
+
<div
|
|
141
|
+
className={cn(
|
|
142
|
+
`self-stretch px-2 py-2 rounded-lg justify-start items-center gap-2 inline-flex outline-none border`,
|
|
143
|
+
isFocused &&
|
|
144
|
+
!hasError &&
|
|
145
|
+
"outline-4 outline-indigo-200 outline-offset-0 border-indigo-300",
|
|
146
|
+
|
|
147
|
+
hasError &&
|
|
148
|
+
"outline-4 outline-red-200 outline-offset-0 border-none",
|
|
149
|
+
!isFocused && hasError && "border-red-200 ",
|
|
150
|
+
disabled ? "bg-gray-100" : "bg-transparent"
|
|
151
|
+
)}
|
|
152
|
+
onFocus={() => setIsFocused(true)}
|
|
153
|
+
onBlur={() => setIsFocused(false)}
|
|
154
|
+
>
|
|
155
|
+
<div className="flex relative grow shrink basis-0 min-h-5 lg:min-h-[32px] justify-start items-stretch gap-2 max-w-full ">
|
|
156
|
+
{!fileData ? (
|
|
157
|
+
<div
|
|
158
|
+
{...getRootProps()}
|
|
159
|
+
className={`w-full p-4 border-dashed border-2 rounded-lg text-center ${
|
|
160
|
+
isDragActive
|
|
161
|
+
? "border-indigo-300 bg-indigo-50"
|
|
162
|
+
: "border-gray-300"
|
|
163
|
+
}`}
|
|
164
|
+
>
|
|
165
|
+
<input {...getInputProps()} id={name} />
|
|
166
|
+
<p className="text-gray-500">
|
|
167
|
+
{isDragActive
|
|
168
|
+
? "Sem přetáhněte soubor"
|
|
169
|
+
: "Klikněte pro nahrání, nebo nahrajte přetažením souboru"}
|
|
170
|
+
</p>
|
|
171
|
+
</div>
|
|
172
|
+
) : (
|
|
173
|
+
<div className="w-full flex items-center justify-between">
|
|
174
|
+
<div className=" flex">
|
|
175
|
+
<MdInsertDriveFile style={{ fontSize: "2rem" }} />
|
|
176
|
+
<a
|
|
177
|
+
href={`/api/files/download/${fileData.id}`}
|
|
178
|
+
className="pl-2 text-left underline text-primary"
|
|
179
|
+
target="_blank"
|
|
180
|
+
>
|
|
181
|
+
{fileData.filename}
|
|
182
|
+
</a>
|
|
183
|
+
</div>
|
|
184
|
+
{!disabled && (
|
|
185
|
+
<div
|
|
186
|
+
onClick={handleRemove}
|
|
187
|
+
className="text-gray-600 cursor-pointer hover:text-primary hover:bg-gray-200 rounded-full ml-4"
|
|
188
|
+
>
|
|
189
|
+
<MdDeleteOutline
|
|
190
|
+
style={{ fontSize: "1.5rem", margin: "15px" }}
|
|
191
|
+
/>
|
|
192
|
+
</div>
|
|
193
|
+
)}
|
|
194
|
+
</div>
|
|
195
|
+
)}
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
{description && (
|
|
200
|
+
<div
|
|
201
|
+
className="HintText self-stretch text-slate-600 text-sm font-normal leading-tight"
|
|
202
|
+
id={name + ":description"}
|
|
203
|
+
>
|
|
204
|
+
{description}
|
|
205
|
+
</div>
|
|
206
|
+
)}
|
|
207
|
+
</div>
|
|
208
|
+
);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export default FileInput;
|
|
@@ -139,7 +139,7 @@ export const MultiSelect = React.forwardRef<
|
|
|
139
139
|
ref
|
|
140
140
|
) => {
|
|
141
141
|
const [selectedValues, setSelectedValues] = React.useState<string[]>(
|
|
142
|
-
propValue ?? defaultValue
|
|
142
|
+
propValue ?? defaultValue ?? []
|
|
143
143
|
);
|
|
144
144
|
const [isPopoverOpen, setIsPopoverOpen] = React.useState(false);
|
|
145
145
|
|
|
@@ -162,10 +162,10 @@ export const MultiSelect = React.forwardRef<
|
|
|
162
162
|
const toggleOption = (option: string | number | null) => {
|
|
163
163
|
if (option === null) return;
|
|
164
164
|
const optionStr = String(option);
|
|
165
|
-
const newSelectedValues = selectedValues
|
|
166
|
-
? selectedValues
|
|
165
|
+
const newSelectedValues = selectedValues?.includes(optionStr)
|
|
166
|
+
? selectedValues?.filter((value) => value !== optionStr)
|
|
167
167
|
: [...selectedValues, optionStr];
|
|
168
|
-
handleValueChange(newSelectedValues);
|
|
168
|
+
handleValueChange(newSelectedValues || []);
|
|
169
169
|
};
|
|
170
170
|
|
|
171
171
|
const handleClear = () => {
|
|
@@ -173,12 +173,12 @@ export const MultiSelect = React.forwardRef<
|
|
|
173
173
|
};
|
|
174
174
|
|
|
175
175
|
const clearExtraOptions = () => {
|
|
176
|
-
const newSelectedValues = selectedValues
|
|
176
|
+
const newSelectedValues = selectedValues?.slice(0, maxCount);
|
|
177
177
|
handleValueChange(newSelectedValues);
|
|
178
178
|
};
|
|
179
179
|
|
|
180
180
|
const toggleAll = () => {
|
|
181
|
-
if (selectedValues
|
|
181
|
+
if (selectedValues?.length === options.length) {
|
|
182
182
|
handleClear();
|
|
183
183
|
} else {
|
|
184
184
|
const allValues = options.map((option) => option.value as string);
|
|
@@ -202,10 +202,10 @@ export const MultiSelect = React.forwardRef<
|
|
|
202
202
|
className
|
|
203
203
|
)}
|
|
204
204
|
>
|
|
205
|
-
{selectedValues
|
|
205
|
+
{selectedValues?.length > 0 ? (
|
|
206
206
|
<div className="flex justify-between items-center w-full">
|
|
207
207
|
<div className="flex flex-wrap items-center">
|
|
208
|
-
{maxCount === 0 && selectedValues
|
|
208
|
+
{maxCount === 0 && selectedValues?.length == 1 && (
|
|
209
209
|
<span className="px-2">
|
|
210
210
|
{
|
|
211
211
|
options.find((o) => o.value === selectedValues[0])
|
|
@@ -213,13 +213,13 @@ export const MultiSelect = React.forwardRef<
|
|
|
213
213
|
}
|
|
214
214
|
</span>
|
|
215
215
|
)}
|
|
216
|
-
{maxCount === 0 && selectedValues
|
|
216
|
+
{maxCount === 0 && selectedValues?.length > 1 && (
|
|
217
217
|
<span className="px-2">
|
|
218
|
-
{`Více (${selectedValues
|
|
218
|
+
{`Více (${selectedValues?.length})`}
|
|
219
219
|
</span>
|
|
220
220
|
)}
|
|
221
221
|
{maxCount > 0 &&
|
|
222
|
-
selectedValues
|
|
222
|
+
selectedValues?.slice(0, maxCount).map((value) => {
|
|
223
223
|
const option = options.find((o) => o.value === value);
|
|
224
224
|
return (
|
|
225
225
|
<Badge
|
|
@@ -238,14 +238,14 @@ export const MultiSelect = React.forwardRef<
|
|
|
238
238
|
);
|
|
239
239
|
})}
|
|
240
240
|
|
|
241
|
-
{maxCount > 0 && selectedValues
|
|
241
|
+
{maxCount > 0 && selectedValues?.length > maxCount && (
|
|
242
242
|
<Badge
|
|
243
243
|
className={cn(
|
|
244
244
|
"bg-transparent text-foreground border-foreground/1 hover:bg-transparent",
|
|
245
245
|
multiSelectVariants({ variant })
|
|
246
246
|
)}
|
|
247
247
|
>
|
|
248
|
-
{`Více (${selectedValues
|
|
248
|
+
{`Více (${selectedValues?.length - maxCount})`}
|
|
249
249
|
<XCircle
|
|
250
250
|
className="ml-2 h-4 w-4 cursor-pointer text-muted-foreground"
|
|
251
251
|
onClick={(event) => {
|
|
@@ -293,7 +293,7 @@ export const MultiSelect = React.forwardRef<
|
|
|
293
293
|
if (e.key === "Enter") {
|
|
294
294
|
setIsPopoverOpen(true);
|
|
295
295
|
} else if (e.key === "Backspace" && !e.currentTarget.value) {
|
|
296
|
-
const newSelectedValues = [...selectedValues];
|
|
296
|
+
const newSelectedValues = [...(selectedValues || [])];
|
|
297
297
|
newSelectedValues.pop();
|
|
298
298
|
handleValueChange(newSelectedValues);
|
|
299
299
|
}
|
|
@@ -310,7 +310,8 @@ export const MultiSelect = React.forwardRef<
|
|
|
310
310
|
<div
|
|
311
311
|
className={cn(
|
|
312
312
|
"mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-primary",
|
|
313
|
-
selectedValues &&
|
|
313
|
+
selectedValues &&
|
|
314
|
+
selectedValues?.length === options.length
|
|
314
315
|
? "bg-primary text-primary-foreground"
|
|
315
316
|
: "opacity-50 [&_svg]:invisible"
|
|
316
317
|
)}
|
|
@@ -348,7 +349,7 @@ export const MultiSelect = React.forwardRef<
|
|
|
348
349
|
<CommandSeparator />
|
|
349
350
|
<CommandGroup>
|
|
350
351
|
<div className="flex items-center justify-between">
|
|
351
|
-
{selectedValues
|
|
352
|
+
{selectedValues?.length > 0 && (
|
|
352
353
|
<>
|
|
353
354
|
<CommandItem
|
|
354
355
|
onSelect={handleClear}
|