Spaces:
Sleeping
Sleeping
Update frontend/hooks/useFileUpload.ts
Browse files- frontend/hooks/useFileUpload.ts +46 -34
frontend/hooks/useFileUpload.ts
CHANGED
|
@@ -1,16 +1,5 @@
|
|
| 1 |
-
import { useCallback,
|
| 2 |
-
|
| 3 |
-
/* ================= TYPES ================= */
|
| 4 |
-
|
| 5 |
-
export interface FileItem {
|
| 6 |
-
id: string;
|
| 7 |
-
file: File;
|
| 8 |
-
path: string;
|
| 9 |
-
progress: number;
|
| 10 |
-
status: "idle" | "uploading" | "done" | "error";
|
| 11 |
-
url?: string;
|
| 12 |
-
error?: string;
|
| 13 |
-
}
|
| 14 |
|
| 15 |
/* ================= HOOK ================= */
|
| 16 |
|
|
@@ -20,18 +9,18 @@ export function useFileUpload() {
|
|
| 20 |
|
| 21 |
/* ---------- ADD FILES ---------- */
|
| 22 |
const addFiles = useCallback((input: FileList | File[]) => {
|
| 23 |
-
const list = Array.from(input).map
|
| 24 |
id: crypto.randomUUID(),
|
| 25 |
file,
|
| 26 |
-
path: file.name,
|
| 27 |
progress: 0,
|
| 28 |
-
status:
|
| 29 |
}));
|
| 30 |
|
| 31 |
setFiles((prev) => [...prev, ...list]);
|
| 32 |
}, []);
|
| 33 |
|
| 34 |
-
/* ---------- REMOVE
|
| 35 |
const removeFile = useCallback((id: string) => {
|
| 36 |
setFiles((prev) => prev.filter((f) => f.id !== id));
|
| 37 |
}, []);
|
|
@@ -45,13 +34,13 @@ export function useFileUpload() {
|
|
| 45 |
);
|
| 46 |
}, []);
|
| 47 |
|
| 48 |
-
/* ---------- UPLOAD
|
| 49 |
-
const uploadOne = useCallback(
|
| 50 |
-
const form = new FormData();
|
| 51 |
-
form.append("file", item.file);
|
| 52 |
-
form.append("path", item.path);
|
| 53 |
-
|
| 54 |
return new Promise<void>((resolve, reject) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
const xhr = new XMLHttpRequest();
|
| 56 |
xhr.open("POST", "/api/upload");
|
| 57 |
|
|
@@ -62,7 +51,11 @@ export function useFileUpload() {
|
|
| 62 |
setFiles((prev) =>
|
| 63 |
prev.map((f) =>
|
| 64 |
f.id === item.id
|
| 65 |
-
? {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
: f
|
| 67 |
)
|
| 68 |
);
|
|
@@ -77,7 +70,7 @@ export function useFileUpload() {
|
|
| 77 |
? {
|
| 78 |
...f,
|
| 79 |
progress: 100,
|
| 80 |
-
status:
|
| 81 |
url: res.url,
|
| 82 |
}
|
| 83 |
: f
|
|
@@ -85,23 +78,43 @@ export function useFileUpload() {
|
|
| 85 |
);
|
| 86 |
resolve();
|
| 87 |
} else {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
reject(new Error("Upload failed"));
|
| 89 |
}
|
| 90 |
};
|
| 91 |
|
| 92 |
-
xhr.onerror = () =>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
xhr.send(form);
|
| 94 |
});
|
| 95 |
}, []);
|
| 96 |
|
| 97 |
-
/* ---------- START UPLOAD
|
| 98 |
const startUpload = useCallback(async () => {
|
| 99 |
if (isUploading) return;
|
| 100 |
setIsUploading(true);
|
| 101 |
|
| 102 |
try {
|
| 103 |
for (const f of files) {
|
| 104 |
-
if (
|
|
|
|
|
|
|
|
|
|
| 105 |
await uploadOne(f);
|
| 106 |
}
|
| 107 |
}
|
|
@@ -110,13 +123,12 @@ export function useFileUpload() {
|
|
| 110 |
}
|
| 111 |
}, [files, uploadOne, isUploading]);
|
| 112 |
|
| 113 |
-
/* ---------- RETURN (KHỚP App.tsx) ---------- */
|
| 114 |
return {
|
| 115 |
-
files,
|
| 116 |
-
isUploading,
|
| 117 |
addFiles,
|
| 118 |
-
removeFile,
|
| 119 |
-
updateFilePath,
|
| 120 |
-
startUpload,
|
| 121 |
};
|
| 122 |
}
|
|
|
|
| 1 |
+
import { useCallback, useState } from "react";
|
| 2 |
+
import { FileItem, UploadStatus } from "../types";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
/* ================= HOOK ================= */
|
| 5 |
|
|
|
|
| 9 |
|
| 10 |
/* ---------- ADD FILES ---------- */
|
| 11 |
const addFiles = useCallback((input: FileList | File[]) => {
|
| 12 |
+
const list: FileItem[] = Array.from(input).map((file) => ({
|
| 13 |
id: crypto.randomUUID(),
|
| 14 |
file,
|
| 15 |
+
path: file.name,
|
| 16 |
progress: 0,
|
| 17 |
+
status: UploadStatus.IDLE,
|
| 18 |
}));
|
| 19 |
|
| 20 |
setFiles((prev) => [...prev, ...list]);
|
| 21 |
}, []);
|
| 22 |
|
| 23 |
+
/* ---------- REMOVE ---------- */
|
| 24 |
const removeFile = useCallback((id: string) => {
|
| 25 |
setFiles((prev) => prev.filter((f) => f.id !== id));
|
| 26 |
}, []);
|
|
|
|
| 34 |
);
|
| 35 |
}, []);
|
| 36 |
|
| 37 |
+
/* ---------- UPLOAD ONE ---------- */
|
| 38 |
+
const uploadOne = useCallback((item: FileItem) => {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
return new Promise<void>((resolve, reject) => {
|
| 40 |
+
const form = new FormData();
|
| 41 |
+
form.append("file", item.file);
|
| 42 |
+
form.append("path", item.path);
|
| 43 |
+
|
| 44 |
const xhr = new XMLHttpRequest();
|
| 45 |
xhr.open("POST", "/api/upload");
|
| 46 |
|
|
|
|
| 51 |
setFiles((prev) =>
|
| 52 |
prev.map((f) =>
|
| 53 |
f.id === item.id
|
| 54 |
+
? {
|
| 55 |
+
...f,
|
| 56 |
+
progress: percent,
|
| 57 |
+
status: UploadStatus.UPLOADING,
|
| 58 |
+
}
|
| 59 |
: f
|
| 60 |
)
|
| 61 |
);
|
|
|
|
| 70 |
? {
|
| 71 |
...f,
|
| 72 |
progress: 100,
|
| 73 |
+
status: UploadStatus.DONE,
|
| 74 |
url: res.url,
|
| 75 |
}
|
| 76 |
: f
|
|
|
|
| 78 |
);
|
| 79 |
resolve();
|
| 80 |
} else {
|
| 81 |
+
setFiles((prev) =>
|
| 82 |
+
prev.map((f) =>
|
| 83 |
+
f.id === item.id
|
| 84 |
+
? { ...f, status: UploadStatus.ERROR }
|
| 85 |
+
: f
|
| 86 |
+
)
|
| 87 |
+
);
|
| 88 |
reject(new Error("Upload failed"));
|
| 89 |
}
|
| 90 |
};
|
| 91 |
|
| 92 |
+
xhr.onerror = () => {
|
| 93 |
+
setFiles((prev) =>
|
| 94 |
+
prev.map((f) =>
|
| 95 |
+
f.id === item.id
|
| 96 |
+
? { ...f, status: UploadStatus.ERROR }
|
| 97 |
+
: f
|
| 98 |
+
)
|
| 99 |
+
);
|
| 100 |
+
reject(new Error("Network error"));
|
| 101 |
+
};
|
| 102 |
+
|
| 103 |
xhr.send(form);
|
| 104 |
});
|
| 105 |
}, []);
|
| 106 |
|
| 107 |
+
/* ---------- START UPLOAD ---------- */
|
| 108 |
const startUpload = useCallback(async () => {
|
| 109 |
if (isUploading) return;
|
| 110 |
setIsUploading(true);
|
| 111 |
|
| 112 |
try {
|
| 113 |
for (const f of files) {
|
| 114 |
+
if (
|
| 115 |
+
f.status === UploadStatus.IDLE ||
|
| 116 |
+
f.status === UploadStatus.ERROR
|
| 117 |
+
) {
|
| 118 |
await uploadOne(f);
|
| 119 |
}
|
| 120 |
}
|
|
|
|
| 123 |
}
|
| 124 |
}, [files, uploadOne, isUploading]);
|
| 125 |
|
|
|
|
| 126 |
return {
|
| 127 |
+
files,
|
| 128 |
+
isUploading,
|
| 129 |
addFiles,
|
| 130 |
+
removeFile,
|
| 131 |
+
updateFilePath,
|
| 132 |
+
startUpload,
|
| 133 |
};
|
| 134 |
}
|