ikoncomponents 1.6.9 → 1.7.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.
Files changed (38) hide show
  1. package/README.md +36 -36
  2. package/dist/ikoncomponents/fileUpload/index.d.ts +11 -12
  3. package/dist/ikoncomponents/fileUpload/index.js +117 -59
  4. package/dist/ikoncomponents/fileUploadApi/index.d.ts +31 -0
  5. package/dist/ikoncomponents/fileUploadApi/index.js +159 -0
  6. package/dist/ikoncomponents/main-layout/nav-main.js +3 -1
  7. package/dist/index.d.ts +8 -3
  8. package/dist/index.js +8 -2
  9. package/dist/styles.css +28 -0
  10. package/dist/utils/api/file-upload copy/index.d.ts +13 -0
  11. package/dist/utils/api/file-upload copy/index.js +120 -0
  12. package/package.json +2 -1
  13. package/dist/ikoncomponents/assistant-ui/Assistant.d.ts +0 -28
  14. package/dist/ikoncomponents/assistant-ui/Assistant.js +0 -306
  15. package/dist/ikoncomponents/assistant-ui/agent-dropdown.d.ts +0 -24
  16. package/dist/ikoncomponents/assistant-ui/agent-dropdown.js +0 -16
  17. package/dist/ikoncomponents/assistant-ui/agentTextChatTransport.d.ts +0 -30
  18. package/dist/ikoncomponents/assistant-ui/agentTextChatTransport.js +0 -208
  19. package/dist/ikoncomponents/assistant-ui/attachment.d.ts +0 -4
  20. package/dist/ikoncomponents/assistant-ui/attachment.js +0 -93
  21. package/dist/ikoncomponents/assistant-ui/markdown-text.d.ts +0 -2
  22. package/dist/ikoncomponents/assistant-ui/markdown-text.js +0 -126
  23. package/dist/ikoncomponents/assistant-ui/thread.d.ts +0 -10
  24. package/dist/ikoncomponents/assistant-ui/thread.js +0 -115
  25. package/dist/ikoncomponents/assistant-ui/tool-fallback.d.ts +0 -2
  26. package/dist/ikoncomponents/assistant-ui/tool-fallback.js +0 -18
  27. package/dist/ikoncomponents/assistant-ui/tooltip-icon-button.d.ts +0 -7
  28. package/dist/ikoncomponents/assistant-ui/tooltip-icon-button.js +0 -23
  29. package/dist/ikoncomponents/table/component/DataTable.d.ts +0 -14
  30. package/dist/ikoncomponents/table/component/DataTable.js +0 -10
  31. package/dist/ikoncomponents/table/component/DataTablePageSize.d.ts +0 -1
  32. package/dist/ikoncomponents/table/component/DataTablePageSize.js +0 -16
  33. package/dist/ikoncomponents/table/component/DataTablePagination.d.ts +0 -6
  34. package/dist/ikoncomponents/table/component/DataTablePagination.js +0 -14
  35. package/dist/ikoncomponents/table/component/DataTableSearch.d.ts +0 -1
  36. package/dist/ikoncomponents/table/component/DataTableSearch.js +0 -27
  37. package/dist/utils/userType.d.ts +0 -13
  38. package/dist/utils/userType.js +0 -1
package/README.md CHANGED
@@ -1,36 +1,36 @@
1
- This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
2
-
3
- ## Getting Started
4
-
5
- First, run the development server:
6
-
7
- ```bash
8
- npm run dev
9
- # or
10
- yarn dev
11
- # or
12
- pnpm dev
13
- # or
14
- bun dev
15
- ```
16
-
17
- Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18
-
19
- You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20
-
21
- This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
22
-
23
- ## Learn More
24
-
25
- To learn more about Next.js, take a look at the following resources:
26
-
27
- - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28
- - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29
-
30
- You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
31
-
32
- ## Deploy on Vercel
33
-
34
- The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35
-
36
- Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
1
+ This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
2
+
3
+ ## Getting Started
4
+
5
+ First, run the development server:
6
+
7
+ ```bash
8
+ npm run dev
9
+ # or
10
+ yarn dev
11
+ # or
12
+ pnpm dev
13
+ # or
14
+ bun dev
15
+ ```
16
+
17
+ Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
18
+
19
+ You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
20
+
21
+ This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
22
+
23
+ ## Learn More
24
+
25
+ To learn more about Next.js, take a look at the following resources:
26
+
27
+ - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
28
+ - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
29
+
30
+ You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
31
+
32
+ ## Deploy on Vercel
33
+
34
+ The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
35
+
36
+ Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
@@ -1,15 +1,14 @@
1
- export interface FileUploaderProps {
1
+ export declare const convertFileToObject: (file: File) => Promise<any>;
2
+ interface FileUploaderProps {
2
3
  label?: string;
3
4
  isDrag?: boolean;
4
- onFileSelect: (fileObj: any) => Promise<any> | void;
5
+ fileInput?: boolean;
6
+ isMultiple?: boolean;
7
+ tooltipContent?: string;
8
+ fileNamePlaceholder?: string;
9
+ showPreview?: boolean;
10
+ onFileSelect: (files: any[]) => Promise<any> | void;
5
11
  }
6
- export declare const convertFileToObject: (file: File) => Promise<{
7
- message: string;
8
- fileName: string;
9
- size: number;
10
- type: string;
11
- lastModified: number;
12
- base64: string;
13
- }>;
14
- export declare function FileUploader({ label, isDrag, onFileSelect, }: FileUploaderProps): import("react/jsx-runtime").JSX.Element;
15
- export declare function getImageFromObject(obj: any): string;
12
+ export default function FileUploader({ label, isDrag, fileInput, isMultiple, tooltipContent, fileNamePlaceholder, showPreview, onFileSelect, }: FileUploaderProps): import("react/jsx-runtime").JSX.Element;
13
+ export declare function getFileUrlFromObject(obj: any): string;
14
+ export {};
@@ -1,69 +1,127 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState } from "react";
4
- import { UploadCloud, FileUp } from "lucide-react";
5
- // --- Helper: Convert File to Object with Base64 ---
6
- export const convertFileToObject = async (file) => {
7
- const arrayBuffer = await file.arrayBuffer();
8
- const base64 = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
9
- return {
10
- message: "File processed successfully",
11
- fileName: file.name,
12
- size: file.size,
13
- type: file.type,
14
- lastModified: file.lastModified,
15
- base64: base64,
16
- };
17
- };
18
- export function FileUploader({ label = "Upload File", isDrag = false, onFileSelect, }) {
19
- const [isDragging, setIsDragging] = useState(false);
20
- const handleFile = async (file) => {
21
- if (!file)
22
- return;
23
- const fileObj = await convertFileToObject(file); // convert to object
24
- await onFileSelect(fileObj); // pass object to parent
25
- };
26
- // ---- DRAG HANDLERS ----
27
- const handleDrop = (e) => {
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useState, useRef } from "react";
4
+ import { UploadCloud, FileUp, Upload, X } from "lucide-react";
5
+ import { v4 as uuidv4 } from "uuid";
6
+ import { Input } from "@/shadcn/input";
7
+ import { IconButtonWithTooltip } from "../buttons";
8
+ /* ----------------------------------------------------
9
+ SAFE Base64 Converter
10
+ ---------------------------------------------------- */
11
+ export const convertFileToObject = (file) => new Promise((resolve, reject) => {
12
+ const reader = new FileReader();
13
+ reader.onload = () => {
28
14
  var _a;
29
- if (!isDrag)
30
- return;
31
- e.preventDefault();
32
- setIsDragging(false);
33
- const file = (_a = e.dataTransfer.files) === null || _a === void 0 ? void 0 : _a[0];
34
- if (file)
35
- handleFile(file);
15
+ const result = reader.result;
16
+ const base64 = result.split(",")[1];
17
+ const nameParts = file.name.split(".");
18
+ const ext = nameParts.length >= 2 ? (_a = nameParts.pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase() : "";
19
+ const fileType = file.type || (ext ? `${ext}` : "application/octet-stream");
20
+ resolve({
21
+ resourceId: uuidv4(),
22
+ message: "File processed successfully",
23
+ fileName: file.name,
24
+ fileSize: file.size,
25
+ fileType, // ✅ FIXED
26
+ base64,
27
+ });
36
28
  };
37
- const handleDragOver = (e) => {
38
- if (!isDrag)
29
+ reader.onerror = reject;
30
+ reader.readAsDataURL(file);
31
+ });
32
+ /* ----------------------------------------------------
33
+ FileInput UI (Text + Button Input)
34
+ ---------------------------------------------------- */
35
+ function FileInputUI({ tooltipContent, fileNames, fileNamePlaceholder, onFileNamesChange, onFileSelect, isMultiple, }) {
36
+ const inputRef = useRef(null);
37
+ const handleChange = async (e) => {
38
+ const files = e.target.files;
39
+ if (!(files === null || files === void 0 ? void 0 : files.length))
39
40
  return;
40
- e.preventDefault();
41
- setIsDragging(true);
41
+ const fileObjects = await Promise.all(Array.from(files).map((f) => convertFileToObject(f)));
42
+ const names = fileObjects.map((f) => f.fileName).join(", ");
43
+ onFileNamesChange === null || onFileNamesChange === void 0 ? void 0 : onFileNamesChange(names);
44
+ onFileSelect === null || onFileSelect === void 0 ? void 0 : onFileSelect(fileObjects);
42
45
  };
43
- const handleDragLeave = () => {
44
- if (!isDrag)
45
- return;
46
- setIsDragging(false);
46
+ const filesCount = fileNames ? fileNames.split(", ").length : 0;
47
+ return (_jsxs("div", { className: "flex w-full", children: [_jsx(Input, { ref: inputRef, type: "file", multiple: isMultiple, className: "hidden", onChange: handleChange }), _jsx(Input, { className: "rounded-e-none", placeholder: fileNamePlaceholder, value: filesCount === 0
48
+ ? ""
49
+ : filesCount === 1
50
+ ? fileNames
51
+ : `${filesCount} files selected`, readOnly: true }), _jsx(IconButtonWithTooltip, { tooltipContent: tooltipContent || "Browse File", onClick: () => { var _a; return (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, className: "border-s-0 rounded-s-none", children: _jsx(Upload, {}) })] }));
52
+ }
53
+ /* ----------------------------------------------------
54
+ Image Preview Component
55
+ ---------------------------------------------------- */
56
+ function ImagePreview({ previews, onRemove, }) {
57
+ if (!previews.length)
58
+ return null;
59
+ return (_jsx("div", { className: "flex flex-wrap gap-2 mt-2 justify-center", children: previews.map((preview, i) => (_jsxs("div", { className: "relative group", children: [_jsx("img", { src: preview.url, alt: preview.name, className: "h-16 w-16 object-cover rounded-md border p-1" }), onRemove && (_jsx("button", { onClick: (e) => {
60
+ e.stopPropagation();
61
+ onRemove(i);
62
+ }, className: "absolute -top-1.5 -right-1.5 bg-red-500 text-white rounded-full w-4 h-4 \r\n flex items-center justify-center opacity-0 group-hover:opacity-100 \r\n transition-opacity shadow-sm", children: _jsx(X, { className: "w-2.5 h-2.5" }) })), _jsx("p", { className: "text-xs text-gray-500 text-center mt-0.5 max-w-[64px] truncate", children: preview.name })] }, i))) }));
63
+ }
64
+ export default function FileUploader({ label = "Upload File", isDrag = false, fileInput = false, isMultiple = false, tooltipContent, fileNamePlaceholder = "Choose files...", showPreview = true, onFileSelect, }) {
65
+ const [isDragging, setIsDragging] = useState(false);
66
+ const [fileNames, setFileNames] = useState("");
67
+ const [previews, setPreviews] = useState([]);
68
+ const filesCount = fileNames ? fileNames.split(", ").length : 0;
69
+ /* ------------ GENERATE PREVIEWS ------------ */
70
+ const generatePreviews = (files) => {
71
+ previews.forEach((p) => URL.revokeObjectURL(p.url));
72
+ const newPreviews = files
73
+ .filter((f) => f.type.startsWith("image/"))
74
+ .map((f) => ({ url: URL.createObjectURL(f), name: f.name }));
75
+ setPreviews(newPreviews);
47
76
  };
48
- const handleInputChange = (e) => {
49
- var _a;
50
- const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
51
- if (file)
52
- handleFile(file);
77
+ /* ------------ REMOVE A SINGLE PREVIEW ------------ */
78
+ const handleRemovePreview = (index) => {
79
+ URL.revokeObjectURL(previews[index].url);
80
+ setPreviews((prev) => prev.filter((_, i) => i !== index));
81
+ };
82
+ /* ------------ COMMON FILE HANDLER ------------ */
83
+ const handleFiles = async (files) => {
84
+ const fileArray = Array.from(files);
85
+ const fileList = isMultiple ? fileArray : [fileArray[0]];
86
+ const fileObjects = await Promise.all(fileList.map((file) => convertFileToObject(file)));
87
+ setFileNames(fileObjects.map((f) => f.fileName).join(", "));
88
+ if (showPreview)
89
+ generatePreviews(fileList);
90
+ onFileSelect(fileObjects);
53
91
  };
54
- return (_jsxs("div", { className: "flex flex-col gap-2 w-full", children: [_jsx("label", { className: "text-sm font-medium", children: label }), _jsx("input", { type: "file", id: "fileInput", className: "hidden", onChange: handleInputChange }), isDrag ? (_jsx("div", { className: `border-2 border-dashed rounded-lg p-6 text-center cursor-pointer transition
55
- ${isDragging ? "border-blue-600 bg-blue-50" : "border-gray-300"}
56
- `, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, onClick: () => { var _a; return (_a = document.getElementById("fileInput")) === null || _a === void 0 ? void 0 : _a.click(); }, children: _jsxs("div", { className: "flex flex-col items-center gap-3", children: [_jsx(UploadCloud, { className: "w-10 h-10 text-blue-600" }), _jsxs("p", { className: "text-gray-600", children: ["Drag & drop your file here or", " ", _jsx("span", { className: "text-blue-600 underline", children: "browse" })] })] }) })) : (
57
- // ----- SIMPLE UPLOAD BOX -----
58
- _jsxs("div", { className: "border rounded-lg p-4 flex flex-col items-center gap-2 cursor-pointer text-center", onClick: () => { var _a; return (_a = document.getElementById("fileInput")) === null || _a === void 0 ? void 0 : _a.click(); }, children: [_jsx(FileUp, { className: "w-8 h-8 text-blue-600" }), _jsx("span", { className: "text-blue-600 underline", children: "Browse File" })] }))] }));
92
+ /* ------------ DRAG HANDLERS ------------ */
93
+ const dragHandlers = isDrag
94
+ ? {
95
+ onDragOver: (e) => {
96
+ e.preventDefault();
97
+ setIsDragging(true);
98
+ },
99
+ onDragLeave: () => setIsDragging(false),
100
+ onDrop: (e) => {
101
+ e.preventDefault();
102
+ setIsDragging(false);
103
+ if (e.dataTransfer.files.length) {
104
+ handleFiles(e.dataTransfer.files);
105
+ }
106
+ },
107
+ }
108
+ : {};
109
+ return (_jsxs("div", Object.assign({}, dragHandlers, { className: `flex flex-col ${fileInput ? "items-start text-left" : "items-center text-center"} justify-center gap-2 cursor-pointer px-4 pb-4 rounded-lg transition ${fileInput
110
+ ? ""
111
+ : `border-2 border-dashed ${isDragging ? "border-blue-600 bg-blue-50" : "border-gray-300"}`}`, children: [_jsx("label", { className: "text-md mt-4 font-bold", children: label }), fileInput && (_jsxs(_Fragment, { children: [_jsx(FileInputUI, { fileNames: fileNames, fileNamePlaceholder: fileNamePlaceholder, tooltipContent: tooltipContent, onFileNamesChange: setFileNames, onFileSelect: onFileSelect, isMultiple: isMultiple }), isDrag && (_jsx("p", { className: "text-sm text-gray-500", children: isDragging ? "Drop files here..." : "or drag & drop files here" })), filesCount > 1 && (_jsxs("p", { className: "text-sm font-medium", children: [filesCount, " files selected"] }))] })), !fileInput && (_jsxs(_Fragment, { children: [_jsx("input", { type: "file", id: "fileInput", className: "hidden", multiple: isMultiple, onChange: (e) => e.target.files && handleFiles(e.target.files) }), isDrag ? (_jsxs("div", { className: "mt-3 p-6 w-full text-center cursor-pointer", onClick: () => { var _a; return (_a = document.getElementById("fileInput")) === null || _a === void 0 ? void 0 : _a.click(); }, children: [filesCount === 0 && (_jsxs("div", { className: "flex flex-col items-center gap-3", children: [_jsx(UploadCloud, { className: "w-10 h-10 text-blue-600" }), _jsxs("p", { className: "text-gray-600", children: ["Drag & drop ", isMultiple ? "files" : "a file", " or", " ", _jsx("span", { className: "text-blue-600 underline", children: "browse" })] })] })), filesCount > 0 && (_jsx("p", { className: "mt-3 text-sm font-medium", children: filesCount === 1
112
+ ? fileNames
113
+ : `${filesCount} files selected` }))] })) : (_jsxs("div", { className: "border rounded-lg p-4 flex flex-col items-center gap-2 cursor-pointer text-center", onClick: () => { var _a; return (_a = document.getElementById("fileInput")) === null || _a === void 0 ? void 0 : _a.click(); }, children: [filesCount === 0 && (_jsxs(_Fragment, { children: [_jsx(FileUp, { className: "w-8 h-8 text-blue-600" }), _jsx("span", { className: "text-blue-600 underline", children: isMultiple ? "Browse Files" : "Browse File" })] })), filesCount > 0 && (_jsx("p", { className: "text-sm font-medium", children: filesCount === 1
114
+ ? fileNames
115
+ : `${filesCount} files selected` }))] })), showPreview && (_jsx(ImagePreview, { previews: previews, onRemove: handleRemovePreview }))] }))] })));
59
116
  }
60
- // --- Helper Function: Recreate Image from File Object ---
61
- export function getImageFromObject(obj) {
117
+ /* ----------------------------------------------------
118
+ Convert Base64 back to Blob URL
119
+ ---------------------------------------------------- */
120
+ export function getFileUrlFromObject(obj) {
62
121
  const byteCharacters = atob(obj.base64);
63
- const byteNumbers = new Array(byteCharacters.length)
64
- .fill(0)
65
- .map((_, i) => byteCharacters.charCodeAt(i));
66
- const byteArray = new Uint8Array(byteNumbers);
67
- const blob = new Blob([byteArray], { type: obj.type });
68
- return URL.createObjectURL(blob); // usable in <img src="..." />
122
+ const byteNumbers = Array.from(byteCharacters).map((c) => c.charCodeAt(0));
123
+ const blob = new Blob([new Uint8Array(byteNumbers)], {
124
+ type: obj.resourceType,
125
+ });
126
+ return URL.createObjectURL(blob);
69
127
  }
@@ -0,0 +1,31 @@
1
+ import React from "react";
2
+ export declare const convertFileToObject: (file: File) => Promise<any>;
3
+ export interface FileUploader2Ref {
4
+ /** Triggers the upload for already-selected files. Resolves when done. */
5
+ upload: () => Promise<void>;
6
+ }
7
+ export interface FileUploader2Props {
8
+ label?: string;
9
+ isDrag?: boolean;
10
+ onUploadComplete?: (response: any | any[]) => void;
11
+ imageUrl?: string;
12
+ fileInput?: boolean;
13
+ isMultiple?: boolean;
14
+ tooltipContent?: string;
15
+ fileNamePlaceholder?: string;
16
+ /** Called with the raw File objects before upload */
17
+ onFileSelect?: (files: File[]) => void;
18
+ /**
19
+ * Custom upload endpoint. When provided, files are POSTed as multipart/form-data
20
+ * and the full JSON response is passed to onUploadComplete.
21
+ * Falls back to uploadFilePublic() when omitted.
22
+ */
23
+ apiUrl?: string;
24
+ /**
25
+ * When true, the upload does NOT start automatically on file selection.
26
+ * Instead, call ref.upload() to trigger it manually.
27
+ */
28
+ manual?: boolean;
29
+ }
30
+ export declare const FileUploaderApi: React.ForwardRefExoticComponent<FileUploader2Props & React.RefAttributes<FileUploader2Ref>>;
31
+ export declare function getFileUrlFromObject(obj: any): string;
@@ -0,0 +1,159 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useState, useRef, useImperativeHandle, forwardRef } from "react";
4
+ import { UploadCloud, FileUp, Upload } from "lucide-react";
5
+ import { v4 as uuidv4 } from "uuid";
6
+ import { Input } from "@/shadcn/input";
7
+ import { IconButtonWithTooltip } from "../buttons";
8
+ import { uploadFilePublic } from "../../utils/api/file-upload copy";
9
+ /* ----------------------------------------------------
10
+ SAFE Base64 Converter (kept for local preview use)
11
+ ---------------------------------------------------- */
12
+ export const convertFileToObject = (file) => new Promise((resolve, reject) => {
13
+ const reader = new FileReader();
14
+ reader.onload = () => {
15
+ const result = reader.result;
16
+ const base64 = result.split(",")[1];
17
+ resolve({
18
+ resourceId: uuidv4(),
19
+ message: "File processed successfully",
20
+ resourceName: file.name,
21
+ resourceSize: file.size,
22
+ resourceType: file.type,
23
+ base64,
24
+ });
25
+ };
26
+ reader.onerror = reject;
27
+ reader.readAsDataURL(file);
28
+ });
29
+ /* ----------------------------------------------------
30
+ FileInput UI (Text + Button Input)
31
+ ---------------------------------------------------- */
32
+ function FileInputUI({ tooltipContent, fileNames, fileNamePlaceholder, onFileNamesChange, onFileSelect, isMultiple, inputId, }) {
33
+ const inputRef = useRef(null);
34
+ const handleChange = (e) => {
35
+ const files = e.target.files;
36
+ if (!(files === null || files === void 0 ? void 0 : files.length))
37
+ return;
38
+ const fileList = isMultiple ? Array.from(files) : [files[0]];
39
+ const names = fileList.map((f) => f.name).join(", ");
40
+ onFileNamesChange === null || onFileNamesChange === void 0 ? void 0 : onFileNamesChange(names);
41
+ onFileSelect === null || onFileSelect === void 0 ? void 0 : onFileSelect(fileList);
42
+ };
43
+ const filesCount = fileNames ? fileNames.split(", ").length : 0;
44
+ return (_jsxs("div", { className: "flex w-full", children: [_jsx(Input, { ref: inputRef, type: "file", multiple: isMultiple, className: "hidden", onChange: handleChange, id: inputId }), _jsx(Input, { className: "rounded-e-none", placeholder: fileNamePlaceholder, value: filesCount === 0
45
+ ? ""
46
+ : filesCount === 1
47
+ ? fileNames
48
+ : `${filesCount} files selected`, readOnly: true }), _jsx(IconButtonWithTooltip, { tooltipContent: tooltipContent || "Browse File", onClick: () => { var _a; return (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, className: "border-s-0 rounded-s-none", children: _jsx(Upload, {}) })] }));
49
+ }
50
+ /* ----------------------------------------------------
51
+ Main FileUploader2 Component
52
+ ---------------------------------------------------- */
53
+ export const FileUploaderApi = forwardRef(function FileUploaderApi({ label = "Upload File", isDrag = false, onUploadComplete, imageUrl, fileInput = false, isMultiple = false, tooltipContent, fileNamePlaceholder = "Choose files...", onFileSelect, apiUrl, manual = false, }, ref) {
54
+ const [isDragging, setIsDragging] = useState(false);
55
+ const [previews, setPreviews] = useState([]);
56
+ const [fileNames, setFileNames] = useState("");
57
+ const [loading, setLoading] = useState(false);
58
+ // Holds files pending upload when manual=true
59
+ const pendingFilesRef = useRef([]);
60
+ const inputId = `fileInput-${label.replace(/\s+/g, "-").toLowerCase()}`;
61
+ const filesCount = fileNames ? fileNames.split(", ").length : 0;
62
+ /* ------------ UPLOAD EXECUTOR ------------ */
63
+ const executeUpload = async (fileList) => {
64
+ try {
65
+ setLoading(true);
66
+ const responses = await Promise.all(fileList.map((f) => {
67
+ if (apiUrl) {
68
+ const formData = new FormData();
69
+ formData.append("file", f);
70
+ return fetch(apiUrl, { method: "POST", body: formData })
71
+ .then((res) => {
72
+ if (!res.ok)
73
+ throw new Error(`Upload failed: ${res.statusText}`);
74
+ return res.json();
75
+ })
76
+ .then((data) => data);
77
+ }
78
+ return uploadFilePublic(f);
79
+ }));
80
+ onUploadComplete === null || onUploadComplete === void 0 ? void 0 : onUploadComplete(isMultiple ? responses : responses[0]);
81
+ }
82
+ catch (err) {
83
+ console.error("Upload failed:", err);
84
+ }
85
+ finally {
86
+ setLoading(false);
87
+ }
88
+ };
89
+ /* ------------ EXPOSE upload() TO PARENT ------------ */
90
+ useImperativeHandle(ref, () => ({
91
+ upload: async () => {
92
+ if (!pendingFilesRef.current.length) {
93
+ console.warn("FileUploader2: no files selected to upload.");
94
+ return;
95
+ }
96
+ await executeUpload(pendingFilesRef.current);
97
+ },
98
+ }));
99
+ /* ------------ CORE FILE HANDLER ------------ */
100
+ const handleFiles = async (files) => {
101
+ const fileList = isMultiple ? files : [files[0]];
102
+ // Local previews for images
103
+ const newPreviews = fileList.map((f) => f.type.startsWith("image/") ? URL.createObjectURL(f) : "");
104
+ setPreviews(newPreviews.filter(Boolean));
105
+ setFileNames(fileList.map((f) => f.name).join(", "));
106
+ // Notify parent of raw files
107
+ onFileSelect === null || onFileSelect === void 0 ? void 0 : onFileSelect(fileList);
108
+ if (manual) {
109
+ // Store files for later — upload() will consume them
110
+ pendingFilesRef.current = fileList;
111
+ }
112
+ else {
113
+ await executeUpload(fileList);
114
+ }
115
+ };
116
+ /* ------------ INPUT CHANGE ------------ */
117
+ const handleInputChange = (e) => {
118
+ const files = e.target.files;
119
+ if (files === null || files === void 0 ? void 0 : files.length)
120
+ handleFiles(Array.from(files));
121
+ };
122
+ /* ------------ DRAG HANDLERS ------------ */
123
+ const dragHandlers = isDrag
124
+ ? {
125
+ onDragOver: (e) => {
126
+ e.preventDefault();
127
+ setIsDragging(true);
128
+ },
129
+ onDragLeave: () => setIsDragging(false),
130
+ onDrop: (e) => {
131
+ e.preventDefault();
132
+ setIsDragging(false);
133
+ if (e.dataTransfer.files.length) {
134
+ handleFiles(Array.from(e.dataTransfer.files));
135
+ }
136
+ },
137
+ }
138
+ : {};
139
+ /* ------------ DISPLAY PREVIEWS ------------ */
140
+ const displayPreviews = previews.length > 0 ? previews : imageUrl ? [imageUrl] : [];
141
+ return (_jsxs("div", Object.assign({}, dragHandlers, { className: `flex flex-col ${fileInput ? "items-start text-left" : "items-center text-center"} justify-center gap-2 cursor-pointer px-4 pb-4 rounded-lg transition ${fileInput
142
+ ? ""
143
+ : `border-2 border-dashed ${isDragging ? "border-blue-600 bg-blue-50" : "border-gray-300"}`}`, children: [_jsx("label", { className: "text-md mt-4 font-bold", children: label }), _jsx("input", { type: "file", id: inputId, className: "hidden", multiple: isMultiple, onChange: handleInputChange }), fileInput && (_jsxs(_Fragment, { children: [_jsx(FileInputUI, { fileNames: fileNames, fileNamePlaceholder: fileNamePlaceholder, tooltipContent: tooltipContent, onFileNamesChange: setFileNames, onFileSelect: (files) => handleFiles(files), isMultiple: isMultiple, inputId: `${inputId}-fileinput` }), isDrag && (_jsx("p", { className: "text-sm text-gray-500", children: isDragging ? "Drop files here..." : "or drag & drop files here" })), loading && (_jsx("p", { className: "text-sm text-blue-500 animate-pulse", children: "Uploading..." })), filesCount > 1 && !loading && (_jsxs("p", { className: "text-sm font-medium", children: [filesCount, " files selected"] }))] })), !fileInput && (_jsx(_Fragment, { children: isDrag ? (_jsxs("div", { className: "mt-3 p-6 w-full text-center cursor-pointer", onClick: () => { var _a; return (_a = document.getElementById(inputId)) === null || _a === void 0 ? void 0 : _a.click(); }, children: [filesCount === 0 && !loading && (_jsxs("div", { className: "flex flex-col items-center gap-3", children: [_jsx(UploadCloud, { className: "w-10 h-10 text-blue-600" }), _jsxs("p", { className: "text-gray-600", children: ["Drag & drop ", isMultiple ? "files" : "a file", " or", " ", _jsx("span", { className: "text-blue-600 underline", children: "browse" })] })] })), loading && (_jsx("p", { className: "text-sm text-blue-500 animate-pulse", children: "Uploading..." })), filesCount > 0 && !loading && (_jsx("p", { className: "mt-3 text-sm font-medium", children: filesCount === 1
144
+ ? fileNames
145
+ : `${filesCount} files selected` }))] })) : (_jsxs("div", { className: "border rounded-lg p-4 flex flex-col items-center gap-2 cursor-pointer text-center", onClick: () => { var _a; return (_a = document.getElementById(inputId)) === null || _a === void 0 ? void 0 : _a.click(); }, children: [filesCount === 0 && !loading && (_jsxs(_Fragment, { children: [_jsx(FileUp, { className: "w-8 h-8 text-blue-600" }), _jsx("span", { className: "text-blue-600 underline", children: isMultiple ? "Browse Files" : "Browse File" })] })), loading && (_jsx("p", { className: "text-sm text-blue-500 animate-pulse", children: "Uploading..." })), filesCount > 0 && !loading && (_jsx("p", { className: "text-sm font-medium", children: filesCount === 1
146
+ ? fileNames
147
+ : `${filesCount} files selected` }))] })) })), !fileInput && displayPreviews.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2 mt-1 justify-center", children: displayPreviews.map((src, i) => (_jsx("img", { src: src, alt: `preview-${i}`, className: "h-10 object-cover rounded-md border p-1" }, i))) }))] })));
148
+ });
149
+ /* ----------------------------------------------------
150
+ Convert Base64 back to Blob URL (utility, kept for compat)
151
+ ---------------------------------------------------- */
152
+ export function getFileUrlFromObject(obj) {
153
+ const byteCharacters = atob(obj.base64);
154
+ const byteNumbers = Array.from(byteCharacters).map((c) => c.charCodeAt(0));
155
+ const blob = new Blob([new Uint8Array(byteNumbers)], {
156
+ type: obj.resourceType,
157
+ });
158
+ return URL.createObjectURL(blob);
159
+ }
@@ -5,13 +5,15 @@ import { ChevronRight } from "lucide-react";
5
5
  import { SidebarGroup, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem } from "../../shadcn/sidebar";
6
6
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../shadcn/collapsible";
7
7
  import Link from "next/link";
8
+ import { usePathname } from "next/navigation";
8
9
  import { useSidebarNav } from "./SidebarNavContext";
9
10
  export function NavMain() {
10
11
  const { navItems } = useSidebarNav();
12
+ const pathname = usePathname();
11
13
  // if (!navItems || navItems.length === 0) {
12
14
  // return null;
13
15
  // }
14
- return (_jsx(SidebarGroup, { children: _jsx(SidebarMenu, { children: navItems.map((item) => item.items && item.items.length > 0 ? (_jsx(Collapsible, { asChild: true, defaultOpen: item.isActive, className: "group/collapsible", children: _jsxs(SidebarMenuItem, { children: [_jsx(CollapsibleTrigger, { asChild: true, children: _jsxs(SidebarMenuButton, { tooltip: item.title, children: [item.icon && _jsx(item.icon, {}), _jsx("span", { children: item.title }), _jsx(ChevronRight, { className: "ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" })] }) }), _jsx(CollapsibleContent, { children: _jsx(SidebarMenuSub, { children: item.items.map((subItem) => (_jsx(SidebarMenuSubItem, { children: _jsx(SidebarMenuSubButton, { asChild: true, children: _jsx(Link, { href: subItem.url, children: _jsx("span", { children: subItem.title }) }) }) }, subItem.title))) }) })] }) }, item.title)) : (_jsx(SidebarMenuItem, { children: _jsx(SidebarMenuButton, { asChild: true, tooltip: item.title, children: _jsxs(Link, { href: item.url, className: "flex items-center gap-2 w-full", children: [item.icon && _jsx(item.icon, {}), _jsx("span", { children: item.title })] }) }) }, item.title))) }) }));
16
+ return (_jsx(SidebarGroup, { children: _jsx(SidebarMenu, { children: navItems.map((item) => item.items && item.items.length > 0 ? (_jsx(Collapsible, { asChild: true, defaultOpen: item.isActive || item.items.some(sub => pathname.startsWith(sub.url)), className: "group/collapsible", children: _jsxs(SidebarMenuItem, { children: [_jsx(CollapsibleTrigger, { asChild: true, children: _jsxs(SidebarMenuButton, { tooltip: item.title, isActive: pathname.startsWith(item.url) || item.items.some(sub => pathname.startsWith(sub.url)), children: [item.icon && _jsx(item.icon, {}), _jsx("span", { children: item.title }), _jsx(ChevronRight, { className: "ml-auto transition-transform duration-200 group-data-[state=open]/collapsible:rotate-90" })] }) }), _jsx(CollapsibleContent, { children: _jsx(SidebarMenuSub, { children: item.items.map((subItem) => (_jsx(SidebarMenuSubItem, { children: _jsx(SidebarMenuSubButton, { asChild: true, isActive: pathname === subItem.url || pathname.startsWith(`${subItem.url}/`), children: _jsx(Link, { href: subItem.url, children: _jsx("span", { children: subItem.title }) }) }) }, subItem.title))) }) })] }) }, item.title)) : (_jsx(SidebarMenuItem, { children: _jsx(SidebarMenuButton, { asChild: true, tooltip: item.title, isActive: pathname === item.url || pathname.startsWith(`${item.url}/`), children: _jsxs(Link, { href: item.url, className: "flex items-center gap-2 w-full", children: [item.icon && _jsx(item.icon, {}), _jsx("span", { children: item.title })] }) }) }, item.title))) }) }));
15
17
  }
16
18
  // Helper component to set nav items from pages
17
19
  export function RenderSidebarNav({ items, sidebarHeader, sidebarFooter }) {
package/dist/index.d.ts CHANGED
@@ -53,8 +53,6 @@ export type { ComboBoxInputProps, ComboboxItemProps, } from "./ikoncomponents/co
53
53
  export { DataTableColumnFilter } from "./ikoncomponents/data-table/datatable-column-filter";
54
54
  export { DataTableFacetedFilter } from "./ikoncomponents/data-table/datatable-faceted-filter";
55
55
  export { DataTableFilterMenu } from "./ikoncomponents/data-table/datatable-filter-menu";
56
- export { convertFileToObject, FileUploader, getImageFromObject, } from "./ikoncomponents/fileUpload";
57
- export type { FileUploaderProps } from "./ikoncomponents/fileUpload";
58
56
  export { DataTablePagination } from "./ikoncomponents/data-table/datatable-pagination";
59
57
  export { DataTableToolbar } from "./ikoncomponents/data-table/datatable-toolbar";
60
58
  export { getDataTableColumnTitle } from "./ikoncomponents/data-table/function";
@@ -129,7 +127,6 @@ export { NewImageForm } from "./ikoncomponents/image-cropper-upload/components/n
129
127
  export type { ImageFormProps } from "./ikoncomponents/image-cropper-upload/components/newImageUploadForm";
130
128
  export { WorkInProgress } from "./ikoncomponents/work-in-progress";
131
129
  export { CustomComboboxInput } from "./ikoncomponents/custom-combo-dropdown";
132
- export { AssistantComponent } from "./ikoncomponents/assistant-ui/Assistant";
133
130
  export { ThemeProvider } from "./utils/theme-provider";
134
131
  export { RadiusProvider, useRadius } from "./utils/border-radius-provider";
135
132
  export { FontProvider, useFont } from "./utils/font-provider";
@@ -140,3 +137,11 @@ export { getValidAccessToken, refreshAccessToken, decodeAccessToken, logOut } fr
140
137
  export type { TokenResponse } from "./utils/token-management/types";
141
138
  export { useIsMobile } from "./hooks/use-mobile";
142
139
  export { useRefresh } from "./ikoncomponents/main-layout/RefreshContext";
140
+ export { FileUploaderApi } from "./ikoncomponents/fileUploadApi";
141
+ export type { FileUploader2Ref, FileUploader2Props } from "./ikoncomponents/fileUploadApi";
142
+ export { fetchFileAsBase64 } from "./utils/api/file-upload copy/index";
143
+ export { downloadFileByResourceId } from "./utils/api/file-upload copy/index";
144
+ export { fetchImagePreview } from "./utils/api/file-upload copy/index";
145
+ export { convertFileToObject } from "./ikoncomponents/fileUpload";
146
+ export { getFileUrlFromObject } from "./ikoncomponents/fileUpload";
147
+ export { default as FileUploader } from "./ikoncomponents/fileUpload";
package/dist/index.js CHANGED
@@ -50,7 +50,6 @@ export { ComboboxInput } from "./ikoncomponents/combobox-input";
50
50
  export { DataTableColumnFilter } from "./ikoncomponents/data-table/datatable-column-filter";
51
51
  export { DataTableFacetedFilter } from "./ikoncomponents/data-table/datatable-faceted-filter";
52
52
  export { DataTableFilterMenu } from "./ikoncomponents/data-table/datatable-filter-menu";
53
- export { convertFileToObject, FileUploader, getImageFromObject, } from "./ikoncomponents/fileUpload";
54
53
  export { DataTablePagination } from "./ikoncomponents/data-table/datatable-pagination";
55
54
  export { DataTableToolbar } from "./ikoncomponents/data-table/datatable-toolbar";
56
55
  export { getDataTableColumnTitle } from "./ikoncomponents/data-table/function";
@@ -108,7 +107,7 @@ export { NewCropperImg } from "./ikoncomponents/image-cropper-upload/components/
108
107
  export { NewImageForm } from "./ikoncomponents/image-cropper-upload/components/newImageUploadForm";
109
108
  export { WorkInProgress } from "./ikoncomponents/work-in-progress";
110
109
  export { CustomComboboxInput } from "./ikoncomponents/custom-combo-dropdown";
111
- export { AssistantComponent } from "./ikoncomponents/assistant-ui/Assistant";
110
+ // export { AssistantComponent } from "./ikoncomponents/assistant-ui/Assistant";
112
111
  export { ThemeProvider } from "./utils/theme-provider";
113
112
  export { RadiusProvider, useRadius } from "./utils/border-radius-provider";
114
113
  export { FontProvider, useFont } from "./utils/font-provider";
@@ -117,3 +116,10 @@ export { setCookieSession, getCookieSession, clearCookieSession, clearAllCookieS
117
116
  export { getValidAccessToken, refreshAccessToken, decodeAccessToken, logOut } from "./utils/token-management";
118
117
  export { useIsMobile } from "./hooks/use-mobile";
119
118
  export { useRefresh } from "./ikoncomponents/main-layout/RefreshContext";
119
+ export { FileUploaderApi } from "./ikoncomponents/fileUploadApi";
120
+ export { fetchFileAsBase64 } from "./utils/api/file-upload copy/index";
121
+ export { downloadFileByResourceId } from "./utils/api/file-upload copy/index";
122
+ export { fetchImagePreview } from "./utils/api/file-upload copy/index";
123
+ export { convertFileToObject } from "./ikoncomponents/fileUpload";
124
+ export { getFileUrlFromObject } from "./ikoncomponents/fileUpload";
125
+ export { default as FileUploader } from "./ikoncomponents/fileUpload";