Skip to content

Commit bd89409

Browse files
committed
feat: add drag-and-drop support for file uploads
- Add drag event handlers (dragEnter, dragOver, dragLeave, drop) - Show visual feedback with emerald border when dragging files - Refactor file processing into shared processFile function - Disable drag-and-drop when text query is active - Scale and highlight drop zone during drag interaction
1 parent c434819 commit bd89409

File tree

1 file changed

+74
-26
lines changed

1 file changed

+74
-26
lines changed

junction-app/app/dashboard/page.tsx

Lines changed: 74 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export default function DashboardPage() {
1616
const [isSubmitting, setIsSubmitting] = useState(false);
1717
const [showStreamModal, setShowStreamModal] = useState(false);
1818
const [streamingEntityName, setStreamingEntityName] = useState("");
19+
const [isDragging, setIsDragging] = useState(false);
1920

2021
useEffect(() => {
2122
if (!user) {
@@ -35,6 +36,69 @@ export default function DashboardPage() {
3536
return hashHex;
3637
};
3738

39+
// Process file and calculate hash
40+
const processFile = async (file: File) => {
41+
setFileName(file.name);
42+
setIsCalculatingHash(true);
43+
44+
try {
45+
const hash = await calculateSHA256(file);
46+
setFileHash(hash);
47+
48+
// Send hash directly to the deep security agent
49+
// Skip the research API and open streaming modal immediately
50+
setStreamingEntityName(hash);
51+
setShowStreamModal(true);
52+
53+
// Clear the file selection
54+
setFileName(null);
55+
setFileHash(null);
56+
} catch (error) {
57+
console.error("Error calculating file hash:", error);
58+
alert("Failed to calculate file hash. Please try again.");
59+
setFileName(null);
60+
setFileHash(null);
61+
} finally {
62+
setIsCalculatingHash(false);
63+
}
64+
};
65+
66+
// Handle drag and drop events
67+
const handleDragEnter = (event: React.DragEvent<HTMLLabelElement>) => {
68+
event.preventDefault();
69+
event.stopPropagation();
70+
if (!query.trim()) {
71+
setIsDragging(true);
72+
}
73+
};
74+
75+
const handleDragOver = (event: React.DragEvent<HTMLLabelElement>) => {
76+
event.preventDefault();
77+
event.stopPropagation();
78+
};
79+
80+
const handleDragLeave = (event: React.DragEvent<HTMLLabelElement>) => {
81+
event.preventDefault();
82+
event.stopPropagation();
83+
setIsDragging(false);
84+
};
85+
86+
const handleDrop = async (event: React.DragEvent<HTMLLabelElement>) => {
87+
event.preventDefault();
88+
event.stopPropagation();
89+
setIsDragging(false);
90+
91+
if (query.trim()) {
92+
return; // Don't process if text input is active
93+
}
94+
95+
const files = event.dataTransfer.files;
96+
if (files && files.length > 0) {
97+
const file = files[0];
98+
await processFile(file);
99+
}
100+
};
101+
38102
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
39103
event.preventDefault();
40104

@@ -121,29 +185,7 @@ export default function DashboardPage() {
121185
return;
122186
}
123187

124-
setFileName(file.name);
125-
setIsCalculatingHash(true);
126-
127-
try {
128-
const hash = await calculateSHA256(file);
129-
setFileHash(hash);
130-
131-
// Send hash directly to the deep security agent
132-
// Skip the research API and open streaming modal immediately
133-
setStreamingEntityName(hash);
134-
setShowStreamModal(true);
135-
136-
// Clear the file selection
137-
setFileName(null);
138-
setFileHash(null);
139-
} catch (error) {
140-
console.error("Error calculating file hash:", error);
141-
alert("Failed to calculate file hash. Please try again.");
142-
setFileName(null);
143-
setFileHash(null);
144-
} finally {
145-
setIsCalculatingHash(false);
146-
}
188+
await processFile(file);
147189
};
148190

149191
return (
@@ -195,10 +237,16 @@ export default function DashboardPage() {
195237

196238
<label
197239
htmlFor="file-upload"
198-
className={`flex flex-col gap-4 rounded-2xl border border-dashed border-white/20 bg-white/5 p-6 transition ${
240+
onDragEnter={handleDragEnter}
241+
onDragOver={handleDragOver}
242+
onDragLeave={handleDragLeave}
243+
onDrop={handleDrop}
244+
className={`flex flex-col gap-4 rounded-2xl border-2 border-dashed p-6 transition-all ${
199245
query.trim()
200-
? "cursor-not-allowed opacity-50"
201-
: "cursor-pointer hover:border-white/40 hover:bg-white/10"
246+
? "cursor-not-allowed border-white/20 bg-white/5 opacity-50"
247+
: isDragging
248+
? "cursor-copy border-emerald-400 bg-emerald-500/20 scale-[1.02]"
249+
: "cursor-pointer border-white/20 bg-white/5 hover:border-white/40 hover:bg-white/10"
202250
}`}
203251
>
204252
<div className="flex items-center gap-4">

0 commit comments

Comments
 (0)