import { ArrowDropDown, ChevronRight, ExpandMore } from '@mui/icons-material';
import { CheckBox, CheckBoxOutlineBlank, IndeterminateCheckBox } from '@mui/icons-material';
import { Box, Checkbox, InputAdornment, Popover, TextField, Typography } from '@mui/material';
import { SimpleTreeView, TreeItem } from '@mui/x-tree-view';
import { memo, useMemo, useState } from 'react';
import { filterColumnTree, getColumnTreeLeafKeys } from '../RealtimeTable/utils/columnUtils';
const EMPTY_IDS = [];
const CollapsibleTree = ({
columnTree,
excludeColumnKeys = EMPTY_IDS,
placeholder = 'Скрыть столбцы',
placeholderSelect = 'Скрыто столбцов: ',
selectedIds = EMPTY_IDS,
onSelectNode,
onSelectAllNodes,
forStage = false,
}) => {
const [expandedItems, setExpandedItems] = useState([]);
const [anchorEl, setAnchorEl] = useState(null);
const selectedNodes = selectedIds;
const visibleColumnTree = useMemo(() => filterColumnTree(columnTree, excludeColumnKeys), [columnTree, excludeColumnKeys]);
const visibleLeafKeys = useMemo(() => getColumnTreeLeafKeys(visibleColumnTree), [visibleColumnTree]);
const handleExpandedItemsChange = (_event, itemIds) => {
setExpandedItems(itemIds);
};
const handleSelectAll = (isSelected) => {
if (onSelectAllNodes) {
onSelectAllNodes(visibleLeafKeys, !isSelected);
return;
}
for (const col of visibleColumnTree) {
onSelectNode?.(col, !isSelected);
}
};
const getChildrenIds = (node) => {
const getLeafColumn = (col) => {
const hasColumns = col.columns && Array.isArray(col.columns);
if (!hasColumns || col.columns.length === 0) {
return [col];
}
const allChildrenAreLeaves = col.columns.every(
(child) => !child.columns || !Array.isArray(child.columns) || child.columns.length === 0,
);
if (allChildrenAreLeaves) {
return col.columns;
}
return col.columns.flatMap((childCol) => getLeafColumn(childCol));
};
const leafColumns = getLeafColumn(node);
return leafColumns.map((c) => c.id || c.accessorKey);
};
const isNodeChecked = (node) => {
const childrenIds = getChildrenIds(node);
const selectedChildren = childrenIds.filter((id) => selectedNodes.includes(id));
if (selectedChildren.length === 0) return false;
if (selectedChildren.length === childrenIds.length) return true;
return 'indeterminate';
};
const handleNodeCheck = (node, isSelected) => {
onSelectNode?.(node, !isSelected);
};
const getId = (column) => {
const getFullColumnPath = (column) => {
const ancestors = [];
let current = column;
while (current) {
ancestors.unshift(current.id || current.accessorKey);
current = current.parent;
}
return ancestors;
};
return getFullColumnPath(column).join('_');
};
const renderTree = (nodes) => {
if (!nodes || nodes.length === 0) return null;
return nodes.map((node) => {
const checkStatus = isNodeChecked(node);
return (
e.stopPropagation()}
checked={checkStatus === true}
indeterminate={checkStatus === 'indeterminate'}
onChange={() => handleNodeCheck(node, checkStatus === 'indeterminate' ? true : !checkStatus)}
icon={}
checkedIcon={}
indeterminateIcon={}
/>
{node.columnDef?.header || node.name || node.header || 'Без названия'}
}>
{node.columns && node.columns.length > 0 && renderTree(node.columns)}
);
});
};
const treeElements = useMemo(() => {
return visibleColumnTree.length > 0 ? renderTree(visibleColumnTree) : null;
}, [visibleColumnTree, selectedNodes]);
const handleOpen = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const visibleSelectedCount = selectedNodes.filter((id) => visibleLeafKeys.includes(id)).length;
const selectedCount = visibleSelectedCount;
const isAllSelected = () => {
if (!visibleColumnTree.length) return false;
let isSelect = true;
for (const col of visibleColumnTree) {
const isChecked = isNodeChecked(col);
isSelect = isChecked === 'indeterminate' ? false : isChecked && isSelect;
}
return isSelect;
};
const open = Boolean(anchorEl);
const id = open ? 'tree-popover' : undefined;
const getDisplayValue = () => {
if (selectedCount === 0) {
return '';
}
return `${placeholderSelect} ${selectedCount}`;
};
return (
<>
),
},
}}
sx={{
cursor: 'pointer',
height: '2.5rem',
padding: 0,
'& .MuiInputBase-root': {
cursor: 'pointer',
height: '2.5rem',
},
'& input': {
cursor: 'pointer',
},
}}
/>
0 && !isAllSelected()}
onChange={(e) => handleSelectAll(e.target.checked)}
icon={}
checkedIcon={}
indeterminateIcon={}
/>
Выбрать все
{treeElements}
>
);
};
export default memo(CollapsibleTree);