From 90fe3c8fb9668eeaf3d4f9275506b099a1831326 Mon Sep 17 00:00:00 2001 From: tigeren Date: Wed, 27 Aug 2025 16:16:28 +0000 Subject: [PATCH] feat: enhance folder viewer with library fetching and error handling - Added functionality to fetch libraries from the API and manage library paths within the folder viewer. - Implemented error handling for directory loading, displaying user-friendly messages when errors occur. - Updated breadcrumb navigation to reflect the current library context and improved path management. - Enhanced UI to show error states and provide a retry option for loading directory contents. --- src/app/folder-viewer/page.tsx | 100 ++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 13 deletions(-) diff --git a/src/app/folder-viewer/page.tsx b/src/app/folder-viewer/page.tsx index 5b6fce2..8e83bfc 100644 --- a/src/app/folder-viewer/page.tsx +++ b/src/app/folder-viewer/page.tsx @@ -40,21 +40,44 @@ const FolderViewerPage = () => { const [selectedPhoto, setSelectedPhoto] = useState(null); const [isPhotoViewerOpen, setIsPhotoViewerOpen] = useState(false); const [currentPhotoIndex, setCurrentPhotoIndex] = useState(0); + const [libraries, setLibraries] = useState<{id: number, path: string}[]>([]); + const [error, setError] = useState(''); useEffect(() => { + fetchLibraries(); if (path) { fetchItems(path); } }, [path]); + const fetchLibraries = async () => { + try { + const res = await fetch('/api/libraries'); + const data = await res.json(); + setLibraries(data); + } catch (error) { + console.error('Error fetching libraries:', error); + } + }; + const fetchItems = async (currentPath: string) => { setLoading(true); + setError(''); try { - const res = await fetch(`/api/files?path=${currentPath}`); + const res = await fetch(`/api/files?path=${encodeURIComponent(currentPath)}`); const data = await res.json(); - setItems(data); + + if (!Array.isArray(data)) { + console.error('Invalid response format:', data); + setItems([]); + setError('Invalid response from server'); + } else { + setItems(data); + } } catch (error) { console.error('Error fetching items:', error); + setItems([]); + setError('Failed to load directory contents'); } finally { setLoading(false); } @@ -101,19 +124,38 @@ const FolderViewerPage = () => { return `${truncatedDir}/${filename}`; }; + const getLibraryRoot = (currentPath: string): string | null => { + if (!currentPath || libraries.length === 0) return null; + + // Find the library root that matches the current path + for (const library of libraries) { + if (currentPath.startsWith(library.path)) { + return library.path; + } + } + return null; + }; + const getBreadcrumbs = (currentPath: string): BreadcrumbItem[] => { if (!currentPath) return []; - const pathParts = currentPath.split('/').filter(part => part.length > 0); + const libraryRoot = getLibraryRoot(currentPath); + if (!libraryRoot) return [{ name: 'Unknown', path: currentPath }]; + + // Get the relative path from library root + const relativePath = currentPath.substring(libraryRoot.length); + const pathParts = relativePath.split('/').filter(part => part.length > 0); + const breadcrumbs: BreadcrumbItem[] = []; - // Add root/home - breadcrumbs.push({ name: 'Home', path: '' }); + // Use library name as root + const libraryName = libraryRoot.split('/').pop() || libraryRoot; + breadcrumbs.push({ name: libraryName, path: libraryRoot }); - // Build breadcrumbs for each path level - let accumulatedPath = ''; + // Build breadcrumbs for each path level within the library + let accumulatedPath = libraryRoot; pathParts.forEach((part, index) => { - accumulatedPath += (accumulatedPath ? '/' : '') + part; + accumulatedPath += '/' + part; breadcrumbs.push({ name: part, path: accumulatedPath @@ -125,8 +167,18 @@ const FolderViewerPage = () => { const getParentPath = (currentPath: string): string => { if (!currentPath) return ''; + + const libraryRoot = getLibraryRoot(currentPath); + if (!libraryRoot) return ''; + + // Don't allow navigation above library root + if (currentPath === libraryRoot) return ''; + const pathParts = currentPath.split('/').filter(part => part.length > 0); - if (pathParts.length <= 1) return ''; + const libraryParts = libraryRoot.split('/').filter(part => part.length > 0); + + if (pathParts.length <= libraryParts.length) return ''; + return pathParts.slice(0, -1).join('/'); }; @@ -252,6 +304,7 @@ const FolderViewerPage = () => { onClick={handleBackClick} className="text-zinc-400 hover:text-white hover:bg-zinc-800/50 transition-colors" disabled={!getParentPath(path || '')} + title={getParentPath(path || '') ? 'Go to parent directory' : 'Already at library root'} > Back @@ -271,11 +324,12 @@ const FolderViewerPage = () => { : 'hover:underline cursor-pointer' }`} disabled={index === getBreadcrumbs(path || '').length - 1} + title={breadcrumb.path} > - {breadcrumb.name === 'Home' ? ( + {index === 0 ? (
- Home + {breadcrumb.name}
) : ( breadcrumb.name @@ -292,7 +346,27 @@ const FolderViewerPage = () => {
- {items.map((item) => ( + {error && ( +
+
+
+ +
+

Error Loading Directory

+

{error}

+ +
+
+ )} + + {!error && Array.isArray(items) && items.map((item) => (
{ ))}
- {items.length === 0 && !loading && ( + {items.length === 0 && !loading && !error && (