"use client"; import React, { useState, useEffect, useCallback } from 'react'; import { FileDocument, FolderDocument, FileType } from '@/types'; import { FileTree } from './file-tree'; // import { FileSearch } from './file-search'; // import { FileActions } from './file-actions'; import { CreateFileDialog } from './create-file-dialog'; import { CreateFolderDialog } from './create-folder-dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { ScrollArea } from '@/components/ui/scroll-area'; // import { Separator } from '@/components/ui/separator'; import { Badge } from '@/components/ui/badge'; import { FolderPlus, FilePlus, Search, Filter, RefreshCw, // Settings, ChevronDown, ChevronRight } from 'lucide-react'; import { api } from '@/lib/api'; import { toast } from 'sonner'; export interface FileExplorerProps { projectId: string; onFileSelect: (file: FileDocument) => void; onFileCreate: (file: FileDocument) => void; onFileUpdate: (file: FileDocument) => void; onFileDelete: (fileId: string) => void; onFolderCreate: (folder: FolderDocument) => void; selectedFileId?: string; className?: string; } export function FileExplorer({ projectId, onFileSelect, onFileCreate, // onFileUpdate, onFileDelete, onFolderCreate, selectedFileId, className = "" }: FileExplorerProps) { const [files, setFiles] = useState([]); const [folders, setFolders] = useState([]); const [loading, setLoading] = useState(true); const [searchQuery, setSearchQuery] = useState(''); const [selectedFolder, setSelectedFolder] = useState(null); const [filterType, setFilterType] = useState('all'); const [isCreateFileOpen, setIsCreateFileOpen] = useState(false); const [isCreateFolderOpen, setIsCreateFolderOpen] = useState(false); const [expandedFolders, setExpandedFolders] = useState>(new Set()); const [isCollapsed, setIsCollapsed] = useState(false); // Load project files and folders const loadProjectData = useCallback(async () => { try { setLoading(true); // Load folders const foldersResponse = await api.get(`/projects/${projectId}/folders?tree=true`); if (foldersResponse.data.ok) { setFolders(foldersResponse.data.tree || []); } // Load files const filesResponse = await api.get(`/projects/${projectId}/files`); if (filesResponse.data.ok) { setFiles(filesResponse.data.files || []); } } catch (error) { console.error('Error loading project data:', error); toast.error('Failed to load project files'); } finally { setLoading(false); } }, [projectId]); useEffect(() => { loadProjectData(); }, [loadProjectData]); // Filter files based on search and type const filteredFiles = files.filter(file => { const matchesSearch = !searchQuery || file.name.toLowerCase().includes(searchQuery.toLowerCase()) || file.content.toLowerCase().includes(searchQuery.toLowerCase()); const matchesType = filterType === 'all' || file.type === filterType; const matchesFolder = !selectedFolder || file.parentFolderId === selectedFolder; return matchesSearch && matchesType && matchesFolder; }); // Handle file creation const handleFileCreate = async (fileData: { name: string; content: string; type: FileType; parentFolderId?: string; }) => { try { const response = await api.post(`/projects/${projectId}/files`, { ...fileData, parentFolderId: selectedFolder || fileData.parentFolderId }); if (response.data.ok) { const newFile = response.data.file; setFiles(prev => [...prev, newFile]); onFileCreate(newFile); toast.success(`File "${newFile.name}" created successfully`); setIsCreateFileOpen(false); } } catch (error: unknown) { console.error('Error creating file:', error); const message = (error as { response?: { data?: { message?: string } } })?.response?.data?.message || 'Failed to create file'; toast.error(message); } }; // Handle folder creation const handleFolderCreate = async (folderData: { name: string; parentFolderId?: string; }) => { try { const response = await api.post(`/projects/${projectId}/folders`, { ...folderData, parentFolderId: selectedFolder || folderData.parentFolderId }); if (response.data.ok) { const newFolder = response.data.folder; setFolders(prev => [...prev, newFolder]); onFolderCreate(newFolder); toast.success(`Folder "${newFolder.name}" created successfully`); setIsCreateFolderOpen(false); // Expand parent folder if (newFolder.parentFolderId) { setExpandedFolders(prev => new Set([...prev, newFolder.parentFolderId!])); } } } catch (error: unknown) { console.error('Error creating folder:', error); const message = (error as { response?: { data?: { message?: string } } })?.response?.data?.message || 'Failed to create folder'; toast.error(message); } }; // Handle file deletion const handleFileDelete = async (fileId: string) => { try { const response = await api.delete(`/projects/${projectId}/files/${fileId}`); if (response.data.ok) { setFiles(prev => prev.filter(f => f._id !== fileId)); onFileDelete(fileId); toast.success('File deleted successfully'); } } catch (error: unknown) { console.error('Error deleting file:', error); const message = (error as { response?: { data?: { message?: string } } })?.response?.data?.message || 'Failed to delete file'; toast.error(message); } }; // Handle folder selection const handleFolderSelect = (folderId: string | null) => { setSelectedFolder(folderId); }; // Toggle folder expansion const toggleFolderExpansion = (folderId: string) => { setExpandedFolders(prev => { const newSet = new Set(prev); if (newSet.has(folderId)) { newSet.delete(folderId); } else { newSet.add(folderId); } return newSet; }); }; // Get file type options for filter const fileTypes = Array.from(new Set(files.map(f => f.type))); if (isCollapsed) { return (
); } return (
{/* Header */}

Files

{/* Search */}
setSearchQuery(e.target.value)} className="pl-10 bg-neutral-800 border-neutral-700 text-white" />
{/* Actions */}
{/* Filter */}
Filter by type
setFilterType('all')} > All ({files.length}) {fileTypes.map(type => { const count = files.filter(f => f.type === type).length; return ( setFilterType(type)} > {type} ({count}) ); })}
{/* File Tree */}
{loading ? (
Loading files...
) : ( { // Handle file rename console.log('Rename file:', fileId, newName); }} onFileDuplicate={(fileId) => { // Handle file duplicate console.log('Duplicate file:', fileId); }} /> )}
{/* Dialogs */}
); }