Twan07 commited on
Commit
a786b70
·
verified ·
1 Parent(s): 0195b42

Update frontend/hooks/useFileUpload.ts

Browse files
Files changed (1) hide show
  1. frontend/hooks/useFileUpload.ts +46 -34
frontend/hooks/useFileUpload.ts CHANGED
@@ -1,16 +1,5 @@
1
- import { useCallback, useMemo, useState } from "react";
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<FileItem>((file) => ({
24
  id: crypto.randomUUID(),
25
  file,
26
- path: file.name, // mặc định
27
  progress: 0,
28
- status: "idle",
29
  }));
30
 
31
  setFiles((prev) => [...prev, ...list]);
32
  }, []);
33
 
34
- /* ---------- REMOVE FILE ---------- */
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 SINGLE ---------- */
49
- const uploadOne = useCallback(async (item: FileItem) => {
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
- ? { ...f, progress: percent, status: "uploading" }
 
 
 
 
66
  : f
67
  )
68
  );
@@ -77,7 +70,7 @@ export function useFileUpload() {
77
  ? {
78
  ...f,
79
  progress: 100,
80
- status: "done",
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 = () => reject(new Error("Network error"));
 
 
 
 
 
 
 
 
 
 
93
  xhr.send(form);
94
  });
95
  }, []);
96
 
97
- /* ---------- START UPLOAD (App.tsx dùng) ---------- */
98
  const startUpload = useCallback(async () => {
99
  if (isUploading) return;
100
  setIsUploading(true);
101
 
102
  try {
103
  for (const f of files) {
104
- if (f.status === "idle") {
 
 
 
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, // ✅ App.tsx dùng
116
- isUploading, // ✅ App.tsx dùng
117
  addFiles,
118
- removeFile, // ✅ App.tsx dùng
119
- updateFilePath, // ✅ App.tsx dùng
120
- startUpload, // ✅ App.tsx dùng
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
  }