"use client" import { useEffect, useState, useCallback } from "react" import { ChevronRight, ChevronDown, Folder, Loader2 } from "lucide-react" interface DirNode { name: string path: string has_children: boolean } interface DirectoryTreeProps { currentPath: string onNavigate: (path: string) => void } interface TreeNodeProps { node: DirNode depth: number isActive: boolean isExpanded: boolean isLoading: boolean subdirs: DirNode[] basePath: string onExpand: (path: string) => void onNavigate: (path: string) => void } const TreeNode = ({ node, depth, isActive, isExpanded, isLoading, subdirs, basePath, onExpand, onNavigate, }: TreeNodeProps) => { return (
{node.has_children ? ( ) : (
)}
{isExpanded && subdirs.length > 0 && (
{subdirs.map((child) => ( ))}
)}
) } const BookmarkButton = ({ label, path, onNavigate, }: { label: string path: string onNavigate: (path: string) => void }) => ( ) export function DirectoryTree({ currentPath, onNavigate, }: DirectoryTreeProps) { const [expanded, setExpanded] = useState>(new Set()) const [childrenMap, setChildrenMap] = useState>( new Map() ) const [loading, setLoading] = useState>(new Set()) const getAuthHeader = () => { const token = localStorage.getItem("access_token") return { Authorization: `Bearer ${token}`, "Content-Type": "application/json", } } const getApiUrl = (path: string) => { const baseUrl = process.env.NEXT_PUBLIC_API_URL || "" return baseUrl + path } const fetchChildren = useCallback( async (path: string) => { // If already loaded, just toggle expand if (childrenMap.has(path)) { setExpanded((prev) => { const newSet = new Set(prev) if (newSet.has(path)) { newSet.delete(path) } else { newSet.add(path) } return newSet }) return } // Fetch children setLoading((prev) => new Set(prev).add(path)) try { const qs = `path=${encodeURIComponent(path)}&admin=true` const res = await fetch(getApiUrl(`/api/navigator/dirs?${qs}`), { headers: getAuthHeader(), }) const data = await res.json() setChildrenMap((prev) => new Map(prev).set(path, data.dirs || [])) setExpanded((prev) => new Set(prev).add(path)) } catch (err) { console.error("Failed to fetch subdirectories:", err) } finally { setLoading((prev) => { const newSet = new Set(prev) newSet.delete(path) return newSet }) } }, [childrenMap] ) // Auto-expand ancestors when currentPath changes useEffect(() => { if (!currentPath || currentPath === "/") return const parts = currentPath.replace(/^\//, "").split("/").filter(Boolean) for (let i = 0; i < parts.length; i++) { const ancestorPath = parts.slice(0, i).join("/") if (!childrenMap.has(ancestorPath)) { fetchChildren(ancestorPath) } else { setExpanded((prev) => new Set(prev).add(ancestorPath)) } } }, [currentPath, childrenMap, fetchChildren]) // Load root on mount useEffect(() => { fetchChildren("") }, [fetchChildren]) const basePath = "/" const rootPath = "" const rootChildren = childrenMap.get(rootPath) || [] return (
{/* Bookmarks Section */}

Favoriten

{/* Directory Tree */}

Verzeichnisse

{rootChildren.length > 0 ? ( rootChildren.map((node) => { const fullPath = basePath === "/" ? "/" + node.path : basePath + "/" + node.path return ( ) }) ) : (

{loading.has(rootPath) ? "Laden..." : "Keine Verzeichnisse"}

)}
) }