From 26f7ba724eb5f3fd98a72bbbc95771205dc59a5a Mon Sep 17 00:00:00 2001 From: Nidhi Kumari Date: Mon, 18 May 2026 03:21:44 +0530 Subject: [PATCH 1/5] feat: add delete confirmation modal with 5-second undo option --- src/components/DeleteConfirmModal.css | 30 +++++++++++++++++++ src/components/DeleteConfirmModal.js | 38 +++++++++++++++++++++++ src/components/FileExplorer.js | 43 ++++++++++++++++++++++++++- 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 src/components/DeleteConfirmModal.css create mode 100644 src/components/DeleteConfirmModal.js diff --git a/src/components/DeleteConfirmModal.css b/src/components/DeleteConfirmModal.css new file mode 100644 index 0000000..117785d --- /dev/null +++ b/src/components/DeleteConfirmModal.css @@ -0,0 +1,30 @@ +.dcm-backdrop { + position: fixed; inset: 0; + background: rgba(0, 0, 0, 0.55); + display: flex; align-items: center; justify-content: center; + z-index: 9999; +} +.dcm-box { + background: #1e2327; border: 1px solid #333; + border-radius: 10px; padding: 28px; width: 360px; max-width: 90vw; +} +.dcm-title { + color: #e0e0e0; font-size: 16px; font-weight: 600; + text-align: center; margin: 0 0 12px; +} +.dcm-body { + color: #aaa; font-size: 13.5px; text-align: center; + line-height: 1.6; margin: 0 0 22px; +} +.dcm-body strong { color: #e0e0e0; } +.dcm-note { display: block; margin-top: 8px; color: #e5a820; font-size: 12px; } +.dcm-actions { display: flex; gap: 10px; } +.dcm-cancel { + flex: 1; padding: 8px 0; background: #2e3338; + color: #ccc; border: none; border-radius: 6px; cursor: pointer; +} +.dcm-confirm { + flex: 1; padding: 8px 0; background: #c0392b; + color: #fff; border: none; border-radius: 6px; + font-weight: 500; cursor: pointer; +} \ No newline at end of file diff --git a/src/components/DeleteConfirmModal.js b/src/components/DeleteConfirmModal.js new file mode 100644 index 0000000..d774ecb --- /dev/null +++ b/src/components/DeleteConfirmModal.js @@ -0,0 +1,38 @@ +import { useEffect, useRef } from "react"; +import "./DeleteConfirmModal.css"; + +export default function DeleteConfirmModal({ target, onCancel, onConfirm }) { + const confirmRef = useRef(null); + + useEffect(() => { + confirmRef.current?.focus(); + const handler = (e) => { + if (e.key === "Escape") onCancel(); + if (e.key === "Enter") onConfirm(); + }; + window.addEventListener("keydown", handler); + return () => window.removeEventListener("keydown", handler); + }, [onCancel, onConfirm]); + + const isFolder = target?.type === "folder"; + + return ( +
+
e.stopPropagation()}> +

Delete {isFolder ? "folder" : "file"}?

+

+ {target?.name} will be permanently deleted + {isFolder && target.childCount > 0 + ? ` along with all ${target.childCount} files inside` + : ""}. +
+ ⚠️ This affects everyone in the room. +

+
+ + +
+
+
+ ); +} \ No newline at end of file diff --git a/src/components/FileExplorer.js b/src/components/FileExplorer.js index bce35f8..6d760aa 100644 --- a/src/components/FileExplorer.js +++ b/src/components/FileExplorer.js @@ -12,6 +12,7 @@ import { ChevronRight, ChevronDown, } from 'lucide-react'; +import DeleteConfirmModal from "./DeleteConfirmModal"; // File icon by extension — returns a Lucide component function FileIcon({ name }) { @@ -28,6 +29,8 @@ function FileNode({ node, fileSystem, depth, activeFileId, onFileClick, onCreate const [renaming, setRenaming] = useState(false); const [renameVal, setRenameVal] = useState(node.name); const [showCreate, setShowCreate] = useState(null); // 'file' | 'folder' + const [deleteTarget, setDeleteTarget] = useState(null); + const [undoToast, setUndoToast] = useState(null); const [createName, setCreateName] = useState(''); const renameRef = useRef(null); const createRef = useRef(null); @@ -60,6 +63,27 @@ function FileNode({ node, fileSystem, depth, activeFileId, onFileClick, onCreate setExpanded(true); }; + const handleDeleteClick = (nodeId, name, type, childCount = 0) => { + setDeleteTarget({ nodeId, name, type, childCount }); + }; + + const handleDeleteConfirm = () => { + const { nodeId, name } = deleteTarget; + setDeleteTarget(null); + + const timer = setTimeout(() => { + onDeleteNode(nodeId); + setUndoToast(null); + }, 5000); + + setUndoToast({ label: name, timer }); + }; + + const handleUndo = () => { + clearTimeout(undoToast.timer); + setUndoToast(null); + }; + const children = (node.children || []).map(id => fileSystem[id]).filter(Boolean); return ( @@ -115,7 +139,7 @@ function FileNode({ node, fileSystem, depth, activeFileId, onFileClick, onCreate - @@ -161,6 +185,23 @@ function FileNode({ node, fileSystem, depth, activeFileId, onFileClick, onCreate canWrite={canWrite} /> ))} + + {/* Delete Confirmation Modal */} + {deleteTarget && ( + setDeleteTarget(null)} + onConfirm={handleDeleteConfirm} + /> + )} + + {/* Undo Toast */} + {undoToast && ( +
+ "{undoToast.label}" deleting in 5s… + +
+ )} ); } From 9de7ce67b2b3357d6d34b92ddabf45d68e520ed6 Mon Sep 17 00:00:00 2001 From: Nidhi <99027229+nidhii-dev@users.noreply.github.com> Date: Mon, 18 May 2026 11:26:30 +0530 Subject: [PATCH 2/5] Update src/components/DeleteConfirmModal.js fix: prevent Enter key from triggering deletion twice Co-authored-by: entelligence-ai-pr-reviews[bot] <174136889+entelligence-ai-pr-reviews[bot]@users.noreply.github.com> --- src/components/DeleteConfirmModal.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/DeleteConfirmModal.js b/src/components/DeleteConfirmModal.js index d774ecb..a351f59 100644 --- a/src/components/DeleteConfirmModal.js +++ b/src/components/DeleteConfirmModal.js @@ -8,11 +8,12 @@ export default function DeleteConfirmModal({ target, onCancel, onConfirm }) { confirmRef.current?.focus(); const handler = (e) => { if (e.key === "Escape") onCancel(); - if (e.key === "Enter") onConfirm(); + if (e.key === "Enter" && document.activeElement !== confirmRef.current) onConfirm(); }; window.addEventListener("keydown", handler); return () => window.removeEventListener("keydown", handler); }, [onCancel, onConfirm]); + }, [onCancel, onConfirm]); const isFolder = target?.type === "folder"; From 5232323124ff2a6d55e4b225be7047c6cff8c50a Mon Sep 17 00:00:00 2001 From: Nidhi <99027229+nidhii-dev@users.noreply.github.com> Date: Mon, 18 May 2026 11:40:56 +0530 Subject: [PATCH 3/5] Update src/components/DeleteConfirmModal.js Co-authored-by: entelligence-ai-pr-reviews[bot] <174136889+entelligence-ai-pr-reviews[bot]@users.noreply.github.com> --- src/components/DeleteConfirmModal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/DeleteConfirmModal.js b/src/components/DeleteConfirmModal.js index a351f59..bc34ef1 100644 --- a/src/components/DeleteConfirmModal.js +++ b/src/components/DeleteConfirmModal.js @@ -8,7 +8,7 @@ export default function DeleteConfirmModal({ target, onCancel, onConfirm }) { confirmRef.current?.focus(); const handler = (e) => { if (e.key === "Escape") onCancel(); - if (e.key === "Enter" && document.activeElement !== confirmRef.current) onConfirm(); + if (e.key === "Enter" && !confirmRef.current?.contains(document.activeElement)) onConfirm(); }; window.addEventListener("keydown", handler); return () => window.removeEventListener("keydown", handler); From c718247192590ddd559e34c349155b14e0621b14 Mon Sep 17 00:00:00 2001 From: Nidhi Kumari Date: Mon, 18 May 2026 11:43:05 +0530 Subject: [PATCH 4/5] feat: add delete confirmation modal with undo option --- src/components/FileExplorer.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/FileExplorer.js b/src/components/FileExplorer.js index 6d760aa..88aaeac 100644 --- a/src/components/FileExplorer.js +++ b/src/components/FileExplorer.js @@ -1,4 +1,4 @@ -import React, { useState, useRef } from 'react'; +import React, { useState, useRef, useEffect } from 'react'; import { v4 as uuid } from 'uuid'; import { File, @@ -83,6 +83,14 @@ function FileNode({ node, fileSystem, depth, activeFileId, onFileClick, onCreate clearTimeout(undoToast.timer); setUndoToast(null); }; + + useEffect(() => { + return () => { + if (undoToast?.timer) { + clearTimeout(undoToast.timer); + } + }; + }, [undoToast]); const children = (node.children || []).map(id => fileSystem[id]).filter(Boolean); From 4d9a34eaacb7779d803f99aff3ed69b360f18040 Mon Sep 17 00:00:00 2001 From: Nidhi Kumari Date: Tue, 26 May 2026 12:05:58 +0530 Subject: [PATCH 5/5] fix: add timer cleanup and folder count message --- src/components/DeleteConfirmModal.js | 2 +- src/components/FileExplorer.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/DeleteConfirmModal.js b/src/components/DeleteConfirmModal.js index bc34ef1..0048e18 100644 --- a/src/components/DeleteConfirmModal.js +++ b/src/components/DeleteConfirmModal.js @@ -24,7 +24,7 @@ export default function DeleteConfirmModal({ target, onCancel, onConfirm }) {

{target?.name} will be permanently deleted {isFolder && target.childCount > 0 - ? ` along with all ${target.childCount} files inside` + ? ` along with ${target.childCount} item${target.childCount === 1 ? '' : 's'} directly inside` : ""}.
⚠️ This affects everyone in the room. diff --git a/src/components/FileExplorer.js b/src/components/FileExplorer.js index 88aaeac..3f27a55 100644 --- a/src/components/FileExplorer.js +++ b/src/components/FileExplorer.js @@ -83,6 +83,14 @@ function FileNode({ node, fileSystem, depth, activeFileId, onFileClick, onCreate clearTimeout(undoToast.timer); setUndoToast(null); }; + + useEffect(() => { + return () => { + if (undoToast?.timer) { + clearTimeout(undoToast.timer); + } + }; +}, [undoToast]); useEffect(() => { return () => {