feat: Refactor sidebar props to simplify data flow
This commit is contained in:
@@ -3,7 +3,7 @@ import { PlusIcon, SettingsIcon } from '../../components/icons';
|
||||
import type { Identifier } from '../../types/identifiers';
|
||||
import { useDocumentsFilter } from '../../documents/context/DocumentsFilterContext';
|
||||
|
||||
export interface CorrespondentEntry {
|
||||
interface CorrespondentEntry {
|
||||
id: Identifier;
|
||||
name: string;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@ import React, { useCallback } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { Identifier } from '../../types/identifiers';
|
||||
import { FolderPlusIcon } from '../../components/icons';
|
||||
import FolderNode, { FolderIdentifier, FolderTreeNode } from './SidebarFolderNode';
|
||||
import FolderNode, { FolderIdentifier } from './SidebarFolderNode';
|
||||
import type { FolderTreeNode } from '../../lib/api/apiTypes';
|
||||
|
||||
interface SidebarFolderListProps {
|
||||
folderNodes: Map<FolderIdentifier, FolderTreeNode>;
|
||||
roots: FolderTreeNode[];
|
||||
selectedFolder: FolderIdentifier | null;
|
||||
onToggle: (folderId: FolderIdentifier) => void;
|
||||
onSelect: (folderId: FolderIdentifier) => void;
|
||||
@@ -22,7 +23,7 @@ interface SidebarFolderListProps {
|
||||
}
|
||||
|
||||
const SidebarFolderList: React.FC<SidebarFolderListProps> = ({
|
||||
folderNodes,
|
||||
roots,
|
||||
selectedFolder,
|
||||
onToggle,
|
||||
onSelect,
|
||||
@@ -37,20 +38,44 @@ const SidebarFolderList: React.FC<SidebarFolderListProps> = ({
|
||||
onCreateFolder,
|
||||
creatingFolder,
|
||||
}) => {
|
||||
const rootNode = folderNodes.get('root');
|
||||
// Local expansion state for the UI
|
||||
const [expandedIds, setExpandedIds] = React.useState<Set<string>>(new Set(['root']));
|
||||
|
||||
// Override validation or external toggle if needed
|
||||
React.useEffect(() => {
|
||||
if (selectedFolder) {
|
||||
// ensure parent paths are expanded?
|
||||
// Without a parent map, we can't easily auto-expand up.
|
||||
// Rely on user or initial state for now, or add parent pointers.
|
||||
}
|
||||
}, [selectedFolder]);
|
||||
|
||||
const handleToggle = useCallback((folderId: FolderIdentifier) => {
|
||||
setExpandedIds((prev) => {
|
||||
const next = new Set(prev);
|
||||
const id = String(folderId);
|
||||
if (next.has(id)) {
|
||||
next.delete(id);
|
||||
} else {
|
||||
next.add(id);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
onToggle(folderId); // propagate event just in case parent needs it
|
||||
}, [onToggle]);
|
||||
|
||||
const renderNodes = useCallback(
|
||||
(ids: FolderIdentifier[], depth: number): ReactNode =>
|
||||
ids.map((id) => {
|
||||
const node = folderNodes.get(id);
|
||||
if (!node) return null;
|
||||
(nodes: FolderTreeNode[], depth: number): ReactNode =>
|
||||
nodes.map((node) => {
|
||||
const isExpanded = expandedIds.has(String(node.id));
|
||||
return (
|
||||
<FolderNode
|
||||
key={id}
|
||||
key={node.id}
|
||||
node={node}
|
||||
depth={depth}
|
||||
isSelected={selectedFolder === id}
|
||||
onToggle={onToggle}
|
||||
isSelected={selectedFolder === node.id}
|
||||
onToggle={handleToggle}
|
||||
expanded={isExpanded}
|
||||
onSelect={onSelect}
|
||||
onDrop={onDrop}
|
||||
onDragOver={onDragOver}
|
||||
@@ -66,9 +91,9 @@ const SidebarFolderList: React.FC<SidebarFolderListProps> = ({
|
||||
);
|
||||
}),
|
||||
[
|
||||
folderNodes,
|
||||
expandedIds,
|
||||
selectedFolder,
|
||||
onToggle,
|
||||
handleToggle,
|
||||
onSelect,
|
||||
onDrop,
|
||||
onDragOver,
|
||||
@@ -101,7 +126,7 @@ const SidebarFolderList: React.FC<SidebarFolderListProps> = ({
|
||||
) : null}
|
||||
</div>
|
||||
<ul className="folder-tree">
|
||||
{rootNode && renderNodes([rootNode.id], 0)}
|
||||
{renderNodes(roots, 0)}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -9,16 +9,9 @@ import {
|
||||
} from '../../components/icons';
|
||||
import type { Identifier } from '../../types/identifiers';
|
||||
|
||||
export type FolderIdentifier = Identifier | 'root';
|
||||
import type { FolderTreeNode } from '../../lib/api/apiTypes';
|
||||
|
||||
export interface FolderTreeNode {
|
||||
id: FolderIdentifier;
|
||||
name?: string;
|
||||
children: FolderIdentifier[];
|
||||
hasChildren?: boolean;
|
||||
loaded?: boolean;
|
||||
expanded?: boolean;
|
||||
}
|
||||
export type FolderIdentifier = Identifier | 'root';
|
||||
|
||||
interface FolderNodeProps {
|
||||
node: FolderTreeNode;
|
||||
@@ -31,7 +24,8 @@ interface FolderNodeProps {
|
||||
onDragLeave: (event: React.DragEvent<HTMLDivElement>) => void;
|
||||
onDelete: (folderId: FolderIdentifier) => void;
|
||||
onRename?: (folderId: FolderIdentifier, name: string) => void;
|
||||
renderChildren: (ids: FolderIdentifier[], depth: number) => ReactNode;
|
||||
renderChildren: (nodes: FolderTreeNode[], depth: number) => ReactNode;
|
||||
expanded: boolean;
|
||||
onFolderDragStart?: (event: React.DragEvent<HTMLDivElement>, folderId: FolderIdentifier) => void;
|
||||
onFolderDragEnd?: (event: React.DragEvent<HTMLDivElement>) => void;
|
||||
draggingFolderId?: FolderIdentifier | null;
|
||||
@@ -50,20 +44,21 @@ const FolderNode: React.FC<FolderNodeProps> = ({
|
||||
onDelete,
|
||||
onRename,
|
||||
renderChildren,
|
||||
expanded,
|
||||
onFolderDragStart,
|
||||
onFolderDragEnd,
|
||||
draggingFolderId,
|
||||
onCreateFolder,
|
||||
}) => {
|
||||
const isRoot = node.id === 'root';
|
||||
const childIds = Array.isArray(node.children) ? node.children : [];
|
||||
const hasChildren = Boolean(node.hasChildren || childIds.length);
|
||||
const canToggle = hasChildren || !node.loaded;
|
||||
const childNodes = node.children || [];
|
||||
const hasChildren = childNodes.length > 0;
|
||||
const canToggle = hasChildren; // Simplified: only toggle if we have children to show
|
||||
const showChevron = canToggle;
|
||||
const icon = showChevron ? <ChevronIcon className="toggle-icon" /> : null;
|
||||
const canDrag = !isRoot;
|
||||
const isDragging = draggingFolderId === node.id;
|
||||
const isExpanded = Boolean(node.expanded);
|
||||
const isExpanded = expanded;
|
||||
const rowClasses = ['folder-row'];
|
||||
if (isSelected) {
|
||||
rowClasses.push('active');
|
||||
@@ -162,9 +157,9 @@ const FolderNode: React.FC<FolderNodeProps> = ({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{isExpanded && childIds.length > 0 && (
|
||||
{isExpanded && childNodes.length > 0 && (
|
||||
<ul className={`folder-children${depth === 0 ? ' folder-children--level1' : ''}`}>
|
||||
{renderChildren(childIds, depth + 1)}
|
||||
{renderChildren(childNodes, depth + 1)}
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { getTagColorStyle } from '../../utils/colors';
|
||||
import type { Identifier } from '../../types/identifiers';
|
||||
import { useDocumentsFilter } from '../../documents/context/DocumentsFilterContext';
|
||||
|
||||
export interface TagEntry {
|
||||
interface TagEntry {
|
||||
id: Identifier;
|
||||
label: string;
|
||||
color?: string | null;
|
||||
|
||||
Reference in New Issue
Block a user