import React, { useEffect, useRef, useState } from "react"; import FolderSection from "@/components/cloud-storage/folder-section"; import FilesSection from "@/components/cloud-storage/files-section"; import { apiRequest } from "@/lib/queryClient"; import { Breadcrumbs, FolderMeta } from "./bread-crumb"; type Props = { folderId: number | null; onClose?: () => void; onViewChange?: (id: number | null) => void; }; export default function FolderPanel({ folderId, onClose, onViewChange, }: Props) { const [currentFolderId, setCurrentFolderId] = useState( folderId ?? null ); const [path, setPath] = useState([]); const [isLoadingPath, setIsLoadingPath] = useState(false); // When the panel opens to a different initial folder, sync and notify parent useEffect(() => { setCurrentFolderId(folderId ?? null); onViewChange?.(folderId ?? null); }, [folderId, onViewChange]); // notify parent when viewed folder changes useEffect(() => { onViewChange?.(currentFolderId); }, [currentFolderId, onViewChange]); // whenever currentFolderId changes we load the ancestor path useEffect(() => { let mounted = true; async function buildPath(fid: number | null) { setIsLoadingPath(true); try { // We'll build path from root -> ... -> current. Since we don't know // if backend provides a single endpoint for ancestry, we'll fetch // current folder and walk parents until null. If fid is null then path is empty. if (fid == null) { if (mounted) setPath([]); return; } const collected: FolderMeta[] = []; let cursor: number | null = fid; // keep a safety cap to avoid infinite loop in case of cycles const MAX_DEPTH = 50; let depth = 0; while (cursor != null && depth < MAX_DEPTH) { const res = await apiRequest( "GET", `/api/cloud-storage/folders/${cursor}` ); const json = await res.json(); if (!res.ok) throw new Error(json?.message || "Failed to fetch folder"); const folder = json?.data ?? json ?? null; // normalize const meta: FolderMeta = { id: folder?.id ?? null, name: folder?.name ?? null, parentId: folder?.parentId ?? null, }; // prepend (we are walking up) then continue with parent collected.push(meta); cursor = meta.parentId; depth += 1; } // collected currently top-down from current -> root. We need root->...->current const rootToCurrent = collected.slice().reverse(); // we don't include the root (null) as an explicit item; Breadcrumbs shows "My Cloud Storage" if (mounted) setPath(rootToCurrent); } catch (err) { console.error("buildPath error", err); if (mounted) setPath([]); } finally { if (mounted) setIsLoadingPath(false); } } buildPath(currentFolderId); return () => { mounted = false; }; }, [currentFolderId]); // handler when child folder is clicked inside FolderSection function handleChildSelect(childFolderId: number | null) { // if user re-clicks current folder id as toggle, we still want to navigate into it. setCurrentFolderId(childFolderId); onViewChange?.(childFolderId); // keep page in sync } // navigate via breadcrumb (id may be null for root) function handleNavigateTo(id: number | null) { setCurrentFolderId(id); onViewChange?.(id); } return (

{currentFolderId == null ? "My Cloud Storage" : `Folder : ${path[path.length - 1]?.name ?? currentFolderId}`}

{onClose && ( )}
{/* Breadcrumb / path strip */}
{/* show breadcrumbs even if loading; breadcrumbs show 'My Cloud Storage' + path */}
{/* stacked vertically: folders on top, files below */}
{/* pass onSelect so FolderSection can tell the panel to navigate into a child */}
); }