gbs-add-block 0.0.23-beta → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/source/components/select/index.tsx +1 -1
- package/source/components/uploader/UploadedFilePreview.tsx +128 -0
- package/source/components/uploader/Uploader.tsx +56 -117
- package/source/components/uploader/types.ts +16 -1
- package/source/components/uploader/uploaderIcon.tsx +2 -2
- package/source/components/uploader/uploaderService.ts +13 -3
package/package.json
CHANGED
|
@@ -20,7 +20,7 @@ import { check, search, upDown, x } from "../icon/iconPaths";
|
|
|
20
20
|
import { getSourceData } from "../utils";
|
|
21
21
|
import type { ItemsProps, SelectProps } from "./types";
|
|
22
22
|
import { selectStyle } from "./style";
|
|
23
|
-
import { popUp, primary } from "
|
|
23
|
+
import { popUp, primary } from "../globalStyle";
|
|
24
24
|
|
|
25
25
|
const Select = forwardRef<any, SelectProps>((props, ref) => {
|
|
26
26
|
const {
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Icon from "../icon/Icon";
|
|
3
|
+
import { cloudDownload, x } from "../icon/iconPaths";
|
|
4
|
+
import { GetFileIcon } from "./uploaderIcon";
|
|
5
|
+
import type { UploadedFilePreview } from "./types";
|
|
6
|
+
|
|
7
|
+
export default function UploadedFilePreview({
|
|
8
|
+
files = [],
|
|
9
|
+
UploadedFileData,
|
|
10
|
+
apiURL,
|
|
11
|
+
showImagePreview,
|
|
12
|
+
previewUrls,
|
|
13
|
+
onFileRemove,
|
|
14
|
+
isRemovable,
|
|
15
|
+
removedId,
|
|
16
|
+
}: UploadedFilePreview) {
|
|
17
|
+
const handleDownload = (fileId: any, fileName: any) => {
|
|
18
|
+
const downloadUrl = constructDownloadUrl(fileId);
|
|
19
|
+
window.open(downloadUrl, "_blank");
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const constructDownloadUrl = (fileId: any) => {
|
|
23
|
+
const url = new URL("download", apiURL);
|
|
24
|
+
url.searchParams.append("id", fileId);
|
|
25
|
+
return url.href;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const isImageFile = (fileName: any) => {
|
|
29
|
+
const imageExtensions = [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"];
|
|
30
|
+
return imageExtensions.some((ext) => fileName.toLowerCase().endsWith(ext));
|
|
31
|
+
};
|
|
32
|
+
return (
|
|
33
|
+
<div>
|
|
34
|
+
{/* Rendering Uploded Local Files */}
|
|
35
|
+
{files.length > 0 && (
|
|
36
|
+
<div className="mt-4 space-y-2">
|
|
37
|
+
{files.map((file: any, index: number) => (
|
|
38
|
+
<div
|
|
39
|
+
key={index}
|
|
40
|
+
className="flex items-center justify-between bg-gray-50 p-2 rounded-md"
|
|
41
|
+
>
|
|
42
|
+
<div className="flex items-center space-x-2">
|
|
43
|
+
<GetFileIcon
|
|
44
|
+
file={file}
|
|
45
|
+
showImagePreview={showImagePreview}
|
|
46
|
+
previewUrls={previewUrls}
|
|
47
|
+
/>
|
|
48
|
+
<div>
|
|
49
|
+
<p className="text-sm font-medium text-gray-700">
|
|
50
|
+
{file.name}
|
|
51
|
+
</p>
|
|
52
|
+
<p className="text-xs text-gray-500">
|
|
53
|
+
{(file.size / 1024 / 1024).toFixed(2)} MB
|
|
54
|
+
</p>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
<button
|
|
58
|
+
type="button"
|
|
59
|
+
onClick={() => {
|
|
60
|
+
if (onFileRemove) onFileRemove(index);
|
|
61
|
+
}}
|
|
62
|
+
className="text-red-500 hover:text-red-700 transition-colors"
|
|
63
|
+
>
|
|
64
|
+
<Icon
|
|
65
|
+
dimensions={{ width: "16", height: "16" }}
|
|
66
|
+
elements={x}
|
|
67
|
+
svgClass={"stroke-red-500 fill-none dark:stroke-white"}
|
|
68
|
+
/>
|
|
69
|
+
</button>
|
|
70
|
+
</div>
|
|
71
|
+
))}
|
|
72
|
+
</div>
|
|
73
|
+
)}
|
|
74
|
+
|
|
75
|
+
{/* Rendering Uploded Remote Files Preview */}
|
|
76
|
+
{UploadedFileData.length > 0 &&
|
|
77
|
+
UploadedFileData.map((item: any, index: any) => (
|
|
78
|
+
<div
|
|
79
|
+
key={index}
|
|
80
|
+
className="flex items-center justify-between bg-gray-50 p-2 rounded-md mt-2"
|
|
81
|
+
>
|
|
82
|
+
<div className="flex items-center space-x-2">
|
|
83
|
+
{isImageFile(item.FileName) && (
|
|
84
|
+
<img
|
|
85
|
+
src={constructDownloadUrl(item.FileID)}
|
|
86
|
+
alt={item.FileName}
|
|
87
|
+
className="mt-2 w-8 h-8 object-cover rounded-lg"
|
|
88
|
+
/>
|
|
89
|
+
)}
|
|
90
|
+
<div>
|
|
91
|
+
<p className="text-sm font-medium text-gray-700">
|
|
92
|
+
{item.FileName}
|
|
93
|
+
</p>
|
|
94
|
+
<p className="text-xs text-gray-500">
|
|
95
|
+
{(item.FileSize / 1024 / 1024).toFixed(2)} MB
|
|
96
|
+
</p>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
<div className="flex gap-2">
|
|
100
|
+
<button
|
|
101
|
+
onClick={() => handleDownload(item.FileID, item.FileName)}
|
|
102
|
+
>
|
|
103
|
+
<Icon
|
|
104
|
+
dimensions={{ width: "18", height: "18" }}
|
|
105
|
+
elements={cloudDownload}
|
|
106
|
+
svgClass={"stroke-blue-800 fill-none dark:stroke-white"}
|
|
107
|
+
/>
|
|
108
|
+
</button>
|
|
109
|
+
{isRemovable && (
|
|
110
|
+
<button
|
|
111
|
+
aria-label="Remove"
|
|
112
|
+
onClick={() => {
|
|
113
|
+
if (removedId) removedId(item.FileID);
|
|
114
|
+
}}
|
|
115
|
+
>
|
|
116
|
+
<Icon
|
|
117
|
+
dimensions={{ width: "16", height: "16" }}
|
|
118
|
+
elements={x}
|
|
119
|
+
svgClass={"stroke-red-500 fill-none dark:stroke-white"}
|
|
120
|
+
/>
|
|
121
|
+
</button>
|
|
122
|
+
)}
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
))}
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
@@ -9,13 +9,12 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import React, { useState, useRef, useEffect } from "react";
|
|
12
|
-
import { upload,
|
|
12
|
+
import { upload, circleCheck } from "../icon/iconPaths";
|
|
13
13
|
import Icon from "../icon/Icon";
|
|
14
|
-
import { GetFileIcon } from "./uploaderIcon";
|
|
15
14
|
import AestheticProcessingAnimationWithStyles from "./ProgressAnimation";
|
|
16
|
-
import { sendFiles } from "./uploaderService";
|
|
17
|
-
import { cloudDownload } from "../icon/iconPaths";
|
|
15
|
+
import { getFilesById, sendFiles } from "./uploaderService";
|
|
18
16
|
import type { FileUploadProps } from "./types";
|
|
17
|
+
import UploadedFilePreview from "./UploadedFilePreview";
|
|
19
18
|
|
|
20
19
|
export const FileUploader = ({
|
|
21
20
|
showImagePreview = false,
|
|
@@ -23,14 +22,16 @@ export const FileUploader = ({
|
|
|
23
22
|
onChange,
|
|
24
23
|
selectedFiles = [],
|
|
25
24
|
accept,
|
|
26
|
-
fileCount =
|
|
25
|
+
fileCount = Infinity,
|
|
27
26
|
disabled = false,
|
|
28
27
|
inputFileSize, // Max file size in MB
|
|
29
28
|
startUpload = false,
|
|
30
29
|
apiURL = "",
|
|
31
30
|
chunk_size = 1024 * 1024,
|
|
32
31
|
uploadedFileIdArray = () => {},
|
|
33
|
-
|
|
32
|
+
documentId = [],
|
|
33
|
+
isRemovable = true,
|
|
34
|
+
removedIds,
|
|
34
35
|
}: FileUploadProps) => {
|
|
35
36
|
const [files, setFiles] = useState<any[]>([]);
|
|
36
37
|
const [previewUrls, setPreviewUrls] = useState<{ [key: string]: string }>({});
|
|
@@ -42,32 +43,47 @@ export const FileUploader = ({
|
|
|
42
43
|
undefined
|
|
43
44
|
);
|
|
44
45
|
const [progress, setProgress] = useState(0);
|
|
46
|
+
const [fileData, setFileData] = useState<any[]>([]);
|
|
45
47
|
const fileInputRef = useRef<any>(null);
|
|
46
48
|
const dropZoneRef = useRef<any>(null);
|
|
47
49
|
|
|
50
|
+
// Upload Handler
|
|
51
|
+
const handleUpload = async () => {
|
|
52
|
+
if (files.length > 0) {
|
|
53
|
+
setFileUploadStatus(undefined);
|
|
54
|
+
await sendFiles(
|
|
55
|
+
files,
|
|
56
|
+
chunk_size,
|
|
57
|
+
apiURL,
|
|
58
|
+
({ uploading, progress, uploadedFileIds }) => {
|
|
59
|
+
setIsUploading(uploading);
|
|
60
|
+
if (progress !== undefined) setProgress(progress);
|
|
61
|
+
// Returns Uploaded File ID's
|
|
62
|
+
if (uploadedFileIds) uploadedFileIdArray(uploadedFileIds);
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
setFileUploadStatus("Upload completed");
|
|
66
|
+
} else {
|
|
67
|
+
setFileUploadStatus("No files selected");
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Getting Files by ID
|
|
72
|
+
const getFiles = async () => {
|
|
73
|
+
const files = await getFilesById(apiURL, documentId);
|
|
74
|
+
setFileData(files);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Fetching by FileId
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (documentId.length) {
|
|
80
|
+
getFiles();
|
|
81
|
+
}
|
|
82
|
+
}, [documentId]);
|
|
83
|
+
|
|
48
84
|
// Starts uploads to server
|
|
49
85
|
useEffect(() => {
|
|
50
86
|
if (startUpload) {
|
|
51
|
-
// Upload Handler
|
|
52
|
-
const handleUpload = async () => {
|
|
53
|
-
if (files.length > 0) {
|
|
54
|
-
setFileUploadStatus(undefined);
|
|
55
|
-
await sendFiles(
|
|
56
|
-
files,
|
|
57
|
-
chunk_size,
|
|
58
|
-
apiURL,
|
|
59
|
-
({ uploading, progress, uploadedFileIds }) => {
|
|
60
|
-
setIsUploading(uploading);
|
|
61
|
-
if (progress !== undefined) setProgress(progress);
|
|
62
|
-
// Returns Uploaded File ID's
|
|
63
|
-
if (uploadedFileIds) uploadedFileIdArray(uploadedFileIds);
|
|
64
|
-
}
|
|
65
|
-
);
|
|
66
|
-
setFileUploadStatus("Upload completed");
|
|
67
|
-
} else {
|
|
68
|
-
setFileUploadStatus("No files selected");
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
87
|
handleUpload();
|
|
72
88
|
}
|
|
73
89
|
}, [startUpload]);
|
|
@@ -170,22 +186,6 @@ export const FileUploader = ({
|
|
|
170
186
|
handleFileChange(multiple ? droppedFiles : [droppedFiles[0]]);
|
|
171
187
|
};
|
|
172
188
|
|
|
173
|
-
const handleDownload = (fileId: any, fileName: any) => {
|
|
174
|
-
const downloadUrl = constructDownloadUrl(fileId);
|
|
175
|
-
window.open(downloadUrl, "_blank");
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
const constructDownloadUrl = (fileId: any) => {
|
|
179
|
-
const url = new URL("download", apiURL);
|
|
180
|
-
url.searchParams.append("id", fileId);
|
|
181
|
-
return url.href;
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
const isImageFile = (fileName: any) => {
|
|
185
|
-
const imageExtensions = [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"];
|
|
186
|
-
return imageExtensions.some((ext) => fileName.toLowerCase().endsWith(ext));
|
|
187
|
-
};
|
|
188
|
-
|
|
189
189
|
return (
|
|
190
190
|
<div className="w-full max-w-md mx-auto">
|
|
191
191
|
<div
|
|
@@ -261,81 +261,20 @@ export const FileUploader = ({
|
|
|
261
261
|
<AestheticProcessingAnimationWithStyles progressPercentage={progress} />
|
|
262
262
|
)}
|
|
263
263
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
<p className="text-sm font-medium text-gray-700">
|
|
279
|
-
{file.name}
|
|
280
|
-
</p>
|
|
281
|
-
<p className="text-xs text-gray-500">
|
|
282
|
-
{(file.size / 1024 / 1024).toFixed(2)} MB
|
|
283
|
-
</p>
|
|
284
|
-
</div>
|
|
285
|
-
</div>
|
|
286
|
-
<button
|
|
287
|
-
type="button"
|
|
288
|
-
onClick={() => removeFile(index)}
|
|
289
|
-
className="text-red-500 hover:text-red-700 transition-colors"
|
|
290
|
-
>
|
|
291
|
-
<Icon
|
|
292
|
-
dimensions={{ width: "16", height: "16" }}
|
|
293
|
-
elements={x}
|
|
294
|
-
svgClass={"stroke-red-500 fill-none dark:stroke-white"}
|
|
295
|
-
/>
|
|
296
|
-
</button>
|
|
297
|
-
</div>
|
|
298
|
-
))}
|
|
299
|
-
</div>
|
|
300
|
-
)}
|
|
301
|
-
|
|
302
|
-
{fileData.length > 0 &&
|
|
303
|
-
fileData.map((item: any, index: any) => (
|
|
304
|
-
<div
|
|
305
|
-
key={index}
|
|
306
|
-
className="flex items-center justify-between bg-gray-50 p-2 rounded-md mt-2"
|
|
307
|
-
>
|
|
308
|
-
<div className="flex items-center space-x-2">
|
|
309
|
-
{/* <GetFileIcon
|
|
310
|
-
file={item.FileName}
|
|
311
|
-
showImagePreview={showImagePreview}
|
|
312
|
-
previewUrls={previewUrls}
|
|
313
|
-
/> */}
|
|
314
|
-
{isImageFile(item.FileName) && (
|
|
315
|
-
<img
|
|
316
|
-
src={constructDownloadUrl(item.FileID)}
|
|
317
|
-
alt={item.FileName}
|
|
318
|
-
className="mt-2 w-8 h-8 object-cover rounded-lg"
|
|
319
|
-
/>
|
|
320
|
-
)}
|
|
321
|
-
<div>
|
|
322
|
-
<p className="text-sm font-medium text-gray-700">
|
|
323
|
-
{item.FileName}
|
|
324
|
-
</p>
|
|
325
|
-
<p className="text-xs text-gray-500">
|
|
326
|
-
{(item.FileSize / 1024 / 1024).toFixed(2)} MB
|
|
327
|
-
</p>
|
|
328
|
-
</div>
|
|
329
|
-
</div>
|
|
330
|
-
<button onClick={() => handleDownload(item.FileID, item.FileName)}>
|
|
331
|
-
<Icon
|
|
332
|
-
dimensions={{ width: "18", height: "18" }}
|
|
333
|
-
elements={cloudDownload}
|
|
334
|
-
svgClass={"stroke-red-500 fill-none dark:stroke-white"}
|
|
335
|
-
/>
|
|
336
|
-
</button>
|
|
337
|
-
</div>
|
|
338
|
-
))}
|
|
264
|
+
<UploadedFilePreview
|
|
265
|
+
UploadedFileData={fileData}
|
|
266
|
+
apiURL={apiURL}
|
|
267
|
+
files={files}
|
|
268
|
+
showImagePreview={showImagePreview}
|
|
269
|
+
previewUrls={previewUrls}
|
|
270
|
+
onFileRemove={(index: any) => {
|
|
271
|
+
removeFile(index);
|
|
272
|
+
}}
|
|
273
|
+
isRemovable={isRemovable}
|
|
274
|
+
removedId={(fileId: any) => {
|
|
275
|
+
if (removedIds) removedIds(fileId);
|
|
276
|
+
}}
|
|
277
|
+
/>
|
|
339
278
|
</div>
|
|
340
279
|
);
|
|
341
280
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type FileUploadProps = {
|
|
2
2
|
showImagePreview?: boolean;
|
|
3
3
|
multiple?: boolean;
|
|
4
|
-
onChange
|
|
4
|
+
onChange?: (files: FileList | null) => void;
|
|
5
5
|
selectedFiles?: File[];
|
|
6
6
|
accept?: string;
|
|
7
7
|
fileCount?: number;
|
|
@@ -12,4 +12,19 @@ export type FileUploadProps = {
|
|
|
12
12
|
chunk_size?: number;
|
|
13
13
|
uploadedFileIdArray?: (ids: string[]) => void;
|
|
14
14
|
fileData?: File[];
|
|
15
|
+
documentId?: string[];
|
|
16
|
+
isRemovable?: boolean;
|
|
17
|
+
removedIds?: (fileId: string | null) => void;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type UploadedFilePreview = {
|
|
21
|
+
files?: any[];
|
|
22
|
+
UploadedFileData: any[];
|
|
23
|
+
apiURL: string;
|
|
24
|
+
previewType?: boolean;
|
|
25
|
+
showImagePreview: boolean;
|
|
26
|
+
previewUrls: { [key: string]: string };
|
|
27
|
+
onFileRemove: any;
|
|
28
|
+
isRemovable: boolean;
|
|
29
|
+
removedId?: any;
|
|
15
30
|
};
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
filetext,
|
|
12
12
|
film,
|
|
13
13
|
music,
|
|
14
|
-
} from "
|
|
15
|
-
import Icon from "
|
|
14
|
+
} from "../icon/iconPaths";
|
|
15
|
+
import Icon from "../icon/Icon";
|
|
16
16
|
|
|
17
17
|
// returns an icon based on the selected file type
|
|
18
18
|
export const GetFileIcon = ({ file, showImagePreview, previewUrls }: any) => {
|
|
@@ -118,7 +118,17 @@ export async function getAllFiles(apiUrl: string) {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
// returns files by ID
|
|
121
|
-
export async function getFilesById(
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
export async function getFilesById(
|
|
122
|
+
apiUrl: string,
|
|
123
|
+
documentIds: string[]
|
|
124
|
+
): Promise<any[]> {
|
|
125
|
+
return Promise.all(
|
|
126
|
+
documentIds.map(async (id) => {
|
|
127
|
+
const response = await fetch(`${apiUrl}?id=${id}`);
|
|
128
|
+
if (!response.ok) {
|
|
129
|
+
throw new Error(`Failed to fetch document with ID: ${id}`);
|
|
130
|
+
}
|
|
131
|
+
return response.json();
|
|
132
|
+
})
|
|
133
|
+
);
|
|
124
134
|
}
|