"use client"; import { AlertTriangle, ChevronDown, ChevronRight, FolderTree, Loader2, RefreshCw, Search, X, } from "lucide-react"; import { memo, useMemo, useState, useTransition } from "react"; import { refreshCatalogTree, useLiveCatalog, } from "@/features/catalog/client/use-live-catalog"; import { cn } from "@/lib/utils"; import type { TreeNode } from "@/types/catalog"; /** * A refresh that fails must be visible. Every number and category below is * presented as current, so silently keeping the previous tree after a failed * read would show pre-import data as if nothing had happened — and a staff * member has no other signal that the import they just ran is not on screen. */ function LiveCatalogNotice() { const { refreshError, refreshing } = useLiveCatalog(); const [retrying, startRetry] = useTransition(); if (!refreshError && !refreshing) return null; return (

{refreshError ? ( <> Catalog could not refresh. ) : ( <> Updating catalog… )}

); } export const CatalogRail = memo(function CatalogRail({ tree, selectedId, onSelect, onClose, }: { tree: TreeNode[]; selectedId: number | null; onSelect: (id: number | null) => void; onClose?: () => void; }) { const [collapsed, setCollapsed] = useState>(new Set()); const [search, setSearch] = useState(""); const visible = useMemo(() => { if (search.trim()) return tree.filter((node) => node.caption.toLowerCase().includes(search.trim().toLowerCase()), ); const hidden = new Set(); for (const node of tree) if (hidden.has(node.parentId) || collapsed.has(node.parentId)) hidden.add(node.id); return tree.filter((node) => !hidden.has(node.id)); }, [tree, collapsed, search]); function toggle(id: number) { setCollapsed((previous) => { const next = new Set(previous); if (next.has(id)) next.delete(id); else next.add(id); return next; }); } return ( ); });