import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
ChevronIcon,
TrashIcon,
EditIcon,
FolderIcon,
ChevronsLeftIcon,
LogoutIcon,
ChevronDownIcon,
} from '../ui/icons';
import { getTagColorStyle } from '../utils/colors';
const FolderNode = ({
node,
depth,
isSelected,
onToggle,
onSelect,
onDrop,
onDragOver,
onDragLeave,
onDelete,
onRename,
renderChildren,
onFolderDragStart,
onFolderDragEnd,
draggingFolderId,
}) => {
const isRoot = node.id === 'root';
const hasChildren = Boolean(node.hasChildren);
const canToggle = hasChildren || !node.loaded;
const showChevron = canToggle;
const icon = showChevron ? : null;
const canDrag = !isRoot;
const isDragging = draggingFolderId === node.id;
const isExpanded = Boolean(node.expanded);
const rowClasses = ['folder-row'];
if (isSelected) {
rowClasses.push('active');
}
const handleToggleClick = (event) => {
event.stopPropagation();
if (canToggle) {
onToggle(node.id);
}
};
return (
onSelect(node.id)}
onDragOver={(event) => onDragOver(event, node.id)}
onDragLeave={onDragLeave}
onDrop={(event) => onDrop(event, node.id)}
onDragStart={(event) => {
if (!canDrag || !onFolderDragStart) return;
onFolderDragStart(event, node.id);
}}
onDragEnd={(event) => {
if (onFolderDragEnd) {
onFolderDragEnd(event);
}
}}
>
{icon}
{node.name}
{node.id !== 'root' && (
)}
{isExpanded && node.children.length > 0 && (
{renderChildren(node.children, depth + 1)}
)}
);
};
const Sidebar = ({
folderNodes,
onToggle,
onSelect,
onDrop,
onDragOver,
onDragLeave,
onDeleteFolder,
onRenameFolder,
selectedFolder,
onFolderDragStart,
onFolderDragEnd,
draggedFolderId,
tags = [],
activeTagIds = [],
onToggleTagFilter,
correspondents = [],
activeCorrespondentIds = [],
onToggleCorrespondentFilter,
onManageTags,
onManageCorrespondents,
searchQuery = '',
onSearchChange,
onSearchSubmit,
onSearchClear,
isFilterActive,
appStatus,
loading,
previewActive,
onLogout,
status,
onCollapse,
tenantSlug,
tenants = [],
activeTenantId = null,
onSelectTenant,
}) => {
const sortedCorrespondents = useMemo(
() =>
[...correspondents].sort((a, b) =>
(a?.name || '').localeCompare(b?.name || '', undefined, { sensitivity: 'base' }),
),
[correspondents],
);
const activeCorrespondentSet = useMemo(
() => new Set(activeCorrespondentIds || []),
[activeCorrespondentIds],
);
const handleToggleTag = onToggleTagFilter || (() => {});
const activeTagSet = new Set(activeTagIds);
const handleManageTags = onManageTags || (() => {});
const handleManageCorrespondents = onManageCorrespondents || (() => {});
const handleSearchInputChange = useCallback(
(event) => {
onSearchChange?.(event.target.value);
},
[onSearchChange],
);
const handleSearchFormSubmit = useCallback(
(event) => {
event.preventDefault();
onSearchSubmit?.();
},
[onSearchSubmit],
);
const handleSearchClear = useCallback(() => {
onSearchClear?.();
}, [onSearchClear]);
const tenantButtonRef = useRef(null);
const tenantMenuRef = useRef(null);
const [tenantMenuOpen, setTenantMenuOpen] = useState(false);
const toggleTenantMenu = useCallback(() => {
const next = !tenantMenuOpen;
setTenantMenuOpen(next);
if (next && tenants.length === 0 && onSelectTenant) {
onSelectTenant(null, { refreshOnly: true });
}
}, [tenantMenuOpen, tenants.length, onSelectTenant]);
useEffect(() => {
if (!tenantMenuOpen) {
return undefined;
}
const handlePointer = (event) => {
const menuNode = tenantMenuRef.current;
const buttonNode = tenantButtonRef.current;
if (!menuNode) return;
if (menuNode.contains(event.target)) return;
if (buttonNode && buttonNode.contains(event.target)) return;
setTenantMenuOpen(false);
};
const handleKeyDown = (event) => {
if (event.key === 'Escape') {
setTenantMenuOpen(false);
}
};
document.addEventListener('mousedown', handlePointer);
document.addEventListener('touchstart', handlePointer);
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('mousedown', handlePointer);
document.removeEventListener('touchstart', handlePointer);
document.removeEventListener('keydown', handleKeyDown);
};
}, [tenantMenuOpen]);
const handleTenantSelect = useCallback(
(tenant) => {
const targetId = tenant?.tenant_id || tenant?.tenantId || tenant?.id || null;
if (!targetId) {
return;
}
setTenantMenuOpen(false);
onSelectTenant?.(tenant);
},
[onSelectTenant],
);
const handleLogoutFromMenu = useCallback(() => {
setTenantMenuOpen(false);
onLogout?.();
}, [onLogout]);
const renderNodes = useCallback(
(ids, depth) =>
ids.map((id) => {
const node = folderNodes.get(id);
if (!node) return null;
return (
onToggle(id)}
onSelect={onSelect}
onDrop={onDrop}
onDragOver={onDragOver}
onDragLeave={onDragLeave}
onDelete={onDeleteFolder}
onRename={onRenameFolder}
renderChildren={renderNodes}
onFolderDragStart={onFolderDragStart}
onFolderDragEnd={onFolderDragEnd}
draggingFolderId={draggedFolderId}
/>
);
}),
[
folderNodes,
selectedFolder,
onToggle,
onSelect,
onDrop,
onDragOver,
onDragLeave,
onDeleteFolder,
onRenameFolder,
onFolderDragStart,
onFolderDragEnd,
draggedFolderId,
],
);
const rootNode = folderNodes.get('root');
return (
);
};
export default Sidebar;
export { FolderNode };