harryagasi commited on
Commit
e9814c9
·
1 Parent(s): 3baad7e

fix(upload file): drag and drop file

Browse files
src/app/App.tsx CHANGED
@@ -1,9 +1,23 @@
 
1
  import { ThemeProvider } from "next-themes";
2
  import { RouterProvider } from "react-router";
3
  import { router } from "./routes";
4
  import { Toaster } from "./components/ui/sonner";
5
 
6
  export default function App() {
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  return (
8
  <ThemeProvider attribute="class" defaultTheme="light" enableSystem disableTransitionOnChange>
9
  <RouterProvider router={router} />
 
1
+ import { useEffect } from "react";
2
  import { ThemeProvider } from "next-themes";
3
  import { RouterProvider } from "react-router";
4
  import { router } from "./routes";
5
  import { Toaster } from "./components/ui/sonner";
6
 
7
  export default function App() {
8
+ // Safety net: without this, a file dropped just outside a dropzone
9
+ // (whitespace, a child element) falls through to the browser's
10
+ // default behavior, which opens/downloads the file instead of no-op.
11
+ useEffect(() => {
12
+ const preventDefault = (e: DragEvent) => e.preventDefault();
13
+ window.addEventListener("dragover", preventDefault);
14
+ window.addEventListener("drop", preventDefault);
15
+ return () => {
16
+ window.removeEventListener("dragover", preventDefault);
17
+ window.removeEventListener("drop", preventDefault);
18
+ };
19
+ }, []);
20
+
21
  return (
22
  <ThemeProvider attribute="class" defaultTheme="light" enableSystem disableTransitionOnChange>
23
  <RouterProvider router={router} />
src/app/components/KnowledgeManagement.tsx CHANGED
@@ -103,6 +103,7 @@ export default function KnowledgeManagement({
103
  const [docsError, setDocsError] = useState<string | null>(null);
104
  const [uploading, setUploading] = useState(false);
105
  const [uploadError, setUploadError] = useState<string | null>(null);
 
106
  const [processing, setProcessing] = useState<string | null>(null);
107
  const [deleting, setDeleting] = useState<string | null>(null);
108
 
@@ -227,8 +228,7 @@ export default function KnowledgeManagement({
227
  }
228
  };
229
 
230
- const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
231
- const files = e.target.files;
232
  if (!files || files.length === 0) return;
233
  const userId = getUserId();
234
  if (!userId) return;
@@ -251,9 +251,25 @@ export default function KnowledgeManagement({
251
  }
252
 
253
  setUploading(false);
 
 
 
 
 
 
254
  e.target.value = "";
255
  };
256
 
 
 
 
 
 
 
 
 
 
 
257
  const processDocumentById = async (userId: string, docId: string) => {
258
  setProcessing(docId);
259
  setDocuments((prev) =>
@@ -584,7 +600,26 @@ export default function KnowledgeManagement({
584
  {/* Upload zone */}
585
  <label
586
  htmlFor="file-upload"
587
- className="group flex flex-col items-center gap-2.5 border-2 border-dashed border-slate-200 rounded-xl p-7 cursor-pointer hover:border-[#FF8F00] hover:bg-orange-50/30 transition-colors"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
588
  >
589
  <div className="w-10 h-10 rounded-xl bg-slate-100 group-hover:bg-orange-100 flex items-center justify-center transition-colors">
590
  {uploading ? (
@@ -597,6 +632,8 @@ export default function KnowledgeManagement({
597
  <p className="text-sm font-medium text-slate-700">
598
  {uploading
599
  ? "Uploading..."
 
 
600
  : <>Drop files, or <span className="text-[#FF8F00]">browse</span></>
601
  }
602
  </p>
 
103
  const [docsError, setDocsError] = useState<string | null>(null);
104
  const [uploading, setUploading] = useState(false);
105
  const [uploadError, setUploadError] = useState<string | null>(null);
106
+ const [isDragging, setIsDragging] = useState(false);
107
  const [processing, setProcessing] = useState<string | null>(null);
108
  const [deleting, setDeleting] = useState<string | null>(null);
109
 
 
228
  }
229
  };
230
 
231
+ const uploadFiles = async (files: FileList) => {
 
232
  if (!files || files.length === 0) return;
233
  const userId = getUserId();
234
  if (!userId) return;
 
251
  }
252
 
253
  setUploading(false);
254
+ };
255
+
256
+ const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
257
+ const files = e.target.files;
258
+ if (!files) return;
259
+ await uploadFiles(files);
260
  e.target.value = "";
261
  };
262
 
263
+ const handleFileDrop = async (e: React.DragEvent<HTMLLabelElement>) => {
264
+ e.preventDefault();
265
+ e.stopPropagation();
266
+ setIsDragging(false);
267
+ if (uploading) return;
268
+ const files = e.dataTransfer.files;
269
+ if (!files || files.length === 0) return;
270
+ await uploadFiles(files);
271
+ };
272
+
273
  const processDocumentById = async (userId: string, docId: string) => {
274
  setProcessing(docId);
275
  setDocuments((prev) =>
 
600
  {/* Upload zone */}
601
  <label
602
  htmlFor="file-upload"
603
+ onDragEnter={(e) => {
604
+ e.preventDefault();
605
+ e.stopPropagation();
606
+ if (!uploading) setIsDragging(true);
607
+ }}
608
+ onDragOver={(e) => {
609
+ e.preventDefault();
610
+ e.stopPropagation();
611
+ }}
612
+ onDragLeave={(e) => {
613
+ e.preventDefault();
614
+ e.stopPropagation();
615
+ setIsDragging(false);
616
+ }}
617
+ onDrop={handleFileDrop}
618
+ className={`group flex flex-col items-center gap-2.5 border-2 border-dashed rounded-xl p-7 cursor-pointer transition-colors ${
619
+ isDragging
620
+ ? "border-[#FF8F00] bg-orange-50/50"
621
+ : "border-slate-200 hover:border-[#FF8F00] hover:bg-orange-50/30"
622
+ }`}
623
  >
624
  <div className="w-10 h-10 rounded-xl bg-slate-100 group-hover:bg-orange-100 flex items-center justify-center transition-colors">
625
  {uploading ? (
 
632
  <p className="text-sm font-medium text-slate-700">
633
  {uploading
634
  ? "Uploading..."
635
+ : isDragging
636
+ ? "Drop to upload"
637
  : <>Drop files, or <span className="text-[#FF8F00]">browse</span></>
638
  }
639
  </p>