import { useState, useMemo, useEffect } from 'react';
import {
Box,
Checkbox,
Typography,
TextField,
Popover,
InputAdornment,
} from '@mui/material';
import { ExpandMore, ChevronRight, ArrowDropDown } from '@mui/icons-material';
import { SimpleTreeView, TreeItem } from '@mui/x-tree-view';
import {
CheckBoxOutlineBlank,
CheckBox,
IndeterminateCheckBox,
} from '@mui/icons-material';
const CollapsibleTree = ({
columnTree,
placeholder = 'Скрыть столбцы',
placeholderSelect = 'Скрыто столбцов: ',
selectedIds = [],
onSelectNode,
}) => {
const [expandedItems, setExpandedItems] = useState([]);
const [anchorEl, setAnchorEl] = useState(null);
const [selectedNodes, setSelectedNodes] = useState([]);
useEffect(() => {
setSelectedNodes(selectedIds);
}, [selectedIds]);
const handleExpandedItemsChange = (event, itemIds) => {
setExpandedItems(itemIds);
};
const handleSelectAll = (isSelected) => {
for (const col of columnTree) {
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 columnTree ? renderTree(columnTree) : null;
}, [columnTree, selectedNodes]);
const handleOpen = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const selectedCount = selectedNodes.length - 1; //1 колонка всегда скрыта
const isAllSelected = () => {
if (!columnTree) return false;
let isSelect = true;
for (const col of columnTree) {
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 CollapsibleTree;