import { useState, useCallback, useEffect } from "react"; import { X, Save, RotateCcw, Folder } from "lucide-react"; import { useFileBrowser } from "../hooks/useFileBrowser"; import { useFileEditor } from "../hooks/useFileEditor"; import { useProjectFileBrowser } from "../hooks/useProjectFileBrowser"; import { useProjectFileEditor } from "../hooks/useProjectFileEditor"; import { FileBrowser } from "./FileBrowser"; import { FileEditor } from "./FileEditor"; type TaskModeProps = { taskId: string; worktreePath?: string; projectRoot?: never; }; type ProjectModeProps = { projectRoot: string; taskId?: never; worktreePath?: never; }; type FileBrowserModalProps = { isOpen?: boolean; onClose: () => void; } & (TaskModeProps | ProjectModeProps); export function FileBrowserModal(props: FileBrowserModalProps) { const { taskId, projectRoot, onClose } = props; const [selectedFile, setSelectedFile] = useState(null); // Determine mode based on which prop is provided const isTaskMode = taskId !== undefined; const isProjectMode = projectRoot !== undefined; // Use appropriate hooks based on mode const taskBrowser = useFileBrowser(taskId ?? "", isTaskMode); const projectBrowser = useProjectFileBrowser(projectRoot ?? "", isProjectMode); const taskEditor = useFileEditor(taskId ?? "", selectedFile, isTaskMode); const projectEditor = useProjectFileEditor(projectRoot ?? "", selectedFile, isProjectMode); // Select the active hooks based on mode const { entries, currentPath, setPath, loading: browserLoading, error: browserError, refresh, } = isTaskMode ? taskBrowser : projectBrowser; const { content, setContent, originalContent, loading: editorLoading, saving, error: editorError, save, hasChanges, mtime, } = isTaskMode ? taskEditor : projectEditor; // Keyboard shortcuts useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === "Escape") { onClose(); } if ((e.metaKey || e.ctrlKey) && e.key === "s") { e.preventDefault(); if (hasChanges && !saving) { save(); } } }; document.addEventListener("keydown", handleKeyDown); return () => document.removeEventListener("keydown", handleKeyDown); }, [onClose, hasChanges, saving, save]); const handleSelectFile = useCallback((path: string) => { setSelectedFile(path); }, []); const handleDiscard = useCallback(() => { setContent(originalContent); }, [originalContent, setContent]); const formatFileSize = (content: string): string => { const bytes = new Blob([content]).size; if (bytes < 1024) return `${bytes} B`; return `${(bytes / 1024).toFixed(1)} KB`; }; // Determine modal title based on mode const modalTitle = isTaskMode ? `Files — ${taskId}` : "Files — Project"; return (
e.stopPropagation()}>
{modalTitle} {selectedFile && ( {currentPath === "." ? "" : currentPath + "/"} {selectedFile} )}
{selectedFile ? ( <>
{selectedFile} {mtime && ( Modified: {new Date(mtime).toLocaleString()} )} {editorLoading && ( Loading... )}
{hasChanges && ( <> )}
{editorError && (
{editorError}
)}
{formatFileSize(content)} {hasChanges && Unsaved changes}
) : (

Select a file to edit

)}
); }