gbs-add-block 0.0.23-beta → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/package.json +1 -1
- package/source/components/select/index.tsx +1 -1
- package/source/components/uploader/UploadedFilePreview.tsx +130 -0
- package/source/components/uploader/Uploader.tsx +85 -120
- package/source/components/uploader/types.ts +16 -1
- package/source/components/uploader/uploaderIcon.tsx +3 -3
- package/source/components/uploader/uploaderService.ts +13 -3
package/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# GBS Building Blocks 2.0 (v0.0.23)
|
|
2
|
+
|
|
3
|
+
Latest and upgraded version of GBS building blocks with headless UI and removed dependencies.
|
|
4
|
+
|
|
5
|
+
## Documentation
|
|
6
|
+
|
|
7
|
+
For detailed documentation on usage and props, Please visit: [Building Block Documentation v2.0](https://blackmax-designs.gitbook.io/building-block-v2.0)
|
|
8
|
+
|
|
9
|
+
## What's New 🎉 (Ver 0.0.23)
|
|
10
|
+
|
|
11
|
+
- Updated Uploader
|
|
12
|
+
- Global Style Customisation is Now available(beta)
|
|
13
|
+
|
|
14
|
+
## Authors
|
|
15
|
+
|
|
16
|
+
- [@anandhuremanan](https://www.github.com/anandhuremanan)
|
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,130 @@
|
|
|
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
|
+
<GetFileIcon file={{ type: item.FileName.split(".").pop() }} />
|
|
91
|
+
)}
|
|
92
|
+
<div>
|
|
93
|
+
<p className="text-sm font-medium text-gray-700">
|
|
94
|
+
{item.FileName}
|
|
95
|
+
</p>
|
|
96
|
+
<p className="text-xs text-gray-500">
|
|
97
|
+
{(item.FileSize / 1024 / 1024).toFixed(2)} MB
|
|
98
|
+
</p>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
<div className="flex gap-2">
|
|
102
|
+
<button
|
|
103
|
+
onClick={() => handleDownload(item.FileID, item.FileName)}
|
|
104
|
+
>
|
|
105
|
+
<Icon
|
|
106
|
+
dimensions={{ width: "18", height: "18" }}
|
|
107
|
+
elements={cloudDownload}
|
|
108
|
+
svgClass={"stroke-blue-800 fill-none dark:stroke-white"}
|
|
109
|
+
/>
|
|
110
|
+
</button>
|
|
111
|
+
{isRemovable && (
|
|
112
|
+
<button
|
|
113
|
+
aria-label="Remove"
|
|
114
|
+
onClick={() => {
|
|
115
|
+
if (removedId) removedId(item.FileID);
|
|
116
|
+
}}
|
|
117
|
+
>
|
|
118
|
+
<Icon
|
|
119
|
+
dimensions={{ width: "16", height: "16" }}
|
|
120
|
+
elements={x}
|
|
121
|
+
svgClass={"stroke-red-500 fill-none dark:stroke-white"}
|
|
122
|
+
/>
|
|
123
|
+
</button>
|
|
124
|
+
)}
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
))}
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
@@ -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,48 @@ 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
|
+
setFiles([]);
|
|
67
|
+
} else {
|
|
68
|
+
setFileUploadStatus("No files selected");
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Getting Files by ID
|
|
73
|
+
const getFiles = async () => {
|
|
74
|
+
const files = await getFilesById(apiURL, documentId);
|
|
75
|
+
setFileData(files);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Fetching by FileId
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (documentId.length) {
|
|
81
|
+
getFiles();
|
|
82
|
+
}
|
|
83
|
+
}, [documentId]);
|
|
84
|
+
|
|
48
85
|
// Starts uploads to server
|
|
49
86
|
useEffect(() => {
|
|
50
87
|
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
88
|
handleUpload();
|
|
72
89
|
}
|
|
73
90
|
}, [startUpload]);
|
|
@@ -81,9 +98,34 @@ export const FileUploader = ({
|
|
|
81
98
|
|
|
82
99
|
// Adds files to file array
|
|
83
100
|
const handleFileChange = (newFiles: File[]) => {
|
|
101
|
+
// First check for duplicates
|
|
102
|
+
const duplicateFiles: string[] = [];
|
|
103
|
+
const nonDuplicateFiles = newFiles.filter((newFile) => {
|
|
104
|
+
const isDuplicate = files.some(
|
|
105
|
+
(existingFile) => existingFile.name === newFile.name
|
|
106
|
+
);
|
|
107
|
+
if (isDuplicate) {
|
|
108
|
+
duplicateFiles.push(newFile.name);
|
|
109
|
+
}
|
|
110
|
+
return !isDuplicate;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// If there are duplicates, set error messages
|
|
114
|
+
if (duplicateFiles.length > 0) {
|
|
115
|
+
setFileSizeErrors((prev) => [
|
|
116
|
+
...prev,
|
|
117
|
+
...duplicateFiles.map(
|
|
118
|
+
(fileName) => `File "${fileName}" has already been uploaded`
|
|
119
|
+
),
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
// If all files are duplicates, exit early
|
|
123
|
+
if (nonDuplicateFiles.length === 0) return;
|
|
124
|
+
}
|
|
125
|
+
|
|
84
126
|
let updatedFiles: File[] = multiple
|
|
85
|
-
? [...files, ...
|
|
86
|
-
: [
|
|
127
|
+
? [...files, ...nonDuplicateFiles]
|
|
128
|
+
: [nonDuplicateFiles[0]];
|
|
87
129
|
|
|
88
130
|
// Ensure the total number of files doesn't exceed the fileCount limit
|
|
89
131
|
if (updatedFiles.length > fileCount) {
|
|
@@ -127,7 +169,7 @@ export const FileUploader = ({
|
|
|
127
169
|
if (onChange) onChange(validFiles);
|
|
128
170
|
}
|
|
129
171
|
|
|
130
|
-
// Set file size errors
|
|
172
|
+
// Set file size errors (now includes both size and duplicate errors)
|
|
131
173
|
setFileSizeErrors(newErrors);
|
|
132
174
|
};
|
|
133
175
|
|
|
@@ -170,22 +212,6 @@ export const FileUploader = ({
|
|
|
170
212
|
handleFileChange(multiple ? droppedFiles : [droppedFiles[0]]);
|
|
171
213
|
};
|
|
172
214
|
|
|
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
215
|
return (
|
|
190
216
|
<div className="w-full max-w-md mx-auto">
|
|
191
217
|
<div
|
|
@@ -261,81 +287,20 @@ export const FileUploader = ({
|
|
|
261
287
|
<AestheticProcessingAnimationWithStyles progressPercentage={progress} />
|
|
262
288
|
)}
|
|
263
289
|
|
|
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
|
-
))}
|
|
290
|
+
<UploadedFilePreview
|
|
291
|
+
UploadedFileData={fileData}
|
|
292
|
+
apiURL={apiURL}
|
|
293
|
+
files={files}
|
|
294
|
+
showImagePreview={showImagePreview}
|
|
295
|
+
previewUrls={previewUrls}
|
|
296
|
+
onFileRemove={(index: any) => {
|
|
297
|
+
removeFile(index);
|
|
298
|
+
}}
|
|
299
|
+
isRemovable={isRemovable}
|
|
300
|
+
removedId={(fileId: any) => {
|
|
301
|
+
if (removedIds) removedIds(fileId);
|
|
302
|
+
}}
|
|
303
|
+
/>
|
|
339
304
|
</div>
|
|
340
305
|
);
|
|
341
306
|
};
|
|
@@ -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) => {
|
|
@@ -30,7 +30,7 @@ export const GetFileIcon = ({ file, showImagePreview, previewUrls }: any) => {
|
|
|
30
30
|
svgClass={"stroke-blue-500 fill-none dark:stroke-white"}
|
|
31
31
|
/>
|
|
32
32
|
);
|
|
33
|
-
if (file.type === "application/pdf")
|
|
33
|
+
if (file.type === "application/pdf" || file.type.includes("pdf"))
|
|
34
34
|
return (
|
|
35
35
|
<Icon
|
|
36
36
|
dimensions={{ width: "26", height: "26" }}
|
|
@@ -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
|
}
|