Last active
September 22, 2024 05:40
-
-
Save pradhumgp/10ed9447415be5366123009ce925193d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState, useEffect } from "react"; | |
// Recursive Component to render the tree structure with collapsible and auto-expand functionality on search | |
const TreeNode = ({ node, isExpandedInitially, onItemClick }) => { | |
const [isExpanded, setIsExpanded] = useState(isExpandedInitially); | |
// Update the expand state when the initial expand prop changes (e.g., during search) | |
useEffect(() => { | |
setIsExpanded(isExpandedInitially); | |
}, [isExpandedInitially]); | |
// Determine the name of the current node (category, subcategory, etc.) | |
const nodeName = | |
node.name || | |
node.category_name || | |
node.sub_category_name || | |
node.sub_sub_category_name; | |
// Check if there are children to render | |
const hasChildren = | |
node.categories || | |
node.sub_categories || | |
node.sub_sub_categories || | |
node.sub_sub_sub_categories; | |
// Toggle the collapse/expand state | |
const handleExpandClick = (e) => { | |
e.stopPropagation(); // Prevent the click event from propagating to the node div | |
setIsExpanded(!isExpanded); | |
}; | |
// Handle click event for the node | |
const handleNodeClick = () => { | |
if (onItemClick) { | |
onItemClick(node); // Call the provided onClick handler | |
} | |
}; | |
return ( | |
<li> | |
<div | |
style={{ cursor: hasChildren ? "pointer" : "default" }} | |
onClick={handleNodeClick} | |
> | |
{hasChildren && ( | |
<span | |
style={{ marginRight: "8px", cursor: "pointer" }} | |
onClick={handleExpandClick} | |
> | |
{isExpanded ? "▼" : "▶"} {/* Arrow to indicate collapse/expand */} | |
</span> | |
)} | |
{nodeName} | |
</div> | |
{/* Recursively render child nodes if the current node is expanded */} | |
{isExpanded && hasChildren && ( | |
<ul style={{ marginLeft: "20px" }}> | |
{node.categories && node.categories.map((child, index) => ( | |
<TreeNode key={index} node={child} isExpandedInitially={isExpandedInitially} onItemClick={onItemClick} /> | |
))} | |
{node.sub_categories && node.sub_categories.map((child, index) => ( | |
<TreeNode key={index} node={child} isExpandedInitially={isExpandedInitially} onItemClick={onItemClick} /> | |
))} | |
{node.sub_sub_categories && node.sub_sub_categories.map((child, index) => ( | |
<TreeNode key={index} node={child} isExpandedInitially={isExpandedInitially} onItemClick={onItemClick} /> | |
))} | |
{node.sub_sub_sub_categories && node.sub_sub_sub_categories.map((child, index) => ( | |
<TreeNode key={index} node={child} isExpandedInitially={isExpandedInitially} onItemClick={onItemClick} /> | |
))} | |
</ul> | |
)} | |
</li> | |
); | |
}; | |
// Function to filter the tree based on the search query | |
const filterTree = (nodes, query) => { | |
if (!query) return nodes; | |
return nodes | |
.map(node => { | |
// Recursively filter through all levels | |
const filteredNode = { ...node }; | |
const childrenKeys = ["categories", "sub_categories", "sub_sub_categories", "sub_sub_sub_categories"]; | |
// If this node matches the query, we will include all its children | |
const nodeMatches = (node.name || node.category_name || node.sub_category_name || node.sub_sub_category_name || "").toLowerCase().includes(query.toLowerCase()); | |
if (nodeMatches) { | |
return filteredNode; // Return the entire node with all its children | |
} | |
// Otherwise, recursively filter the children | |
childrenKeys.forEach(key => { | |
if (filteredNode[key]) { | |
filteredNode[key] = filterTree(filteredNode[key], query); | |
} | |
}); | |
// If any of the children match, keep the node | |
const childrenMatch = childrenKeys.some(key => filteredNode[key] && filteredNode[key].length > 0); | |
if (childrenMatch) { | |
return filteredNode; | |
} | |
return null; // Remove the node if it and its children don't match | |
}) | |
.filter(node => node !== null); // Filter out null nodes | |
}; | |
const CatalogTree2 = ({catalogData}) => { | |
const [searchQuery, setSearchQuery] = useState(""); | |
const [filteredData, setFilteredData] = useState(catalogData); | |
const handleSearch = (e) => { | |
const query = e.target.value; | |
setSearchQuery(query); | |
setFilteredData(filterTree(catalogData, query)); | |
}; | |
// Define the action to perform on item click | |
const handleItemClick = (node) => { | |
console.log("Clicked item:", node); | |
// Perform any action you want with the clicked node here | |
}; | |
return ( | |
<div> | |
<input | |
type="text" | |
placeholder="Search catalog..." | |
value={searchQuery} | |
onChange={handleSearch} | |
style={{ padding: "10px", width: "300px", marginBottom: "20px" }} | |
/> | |
<ul> | |
{filteredData.map((node, index) => ( | |
<TreeNode key={index} node={node} isExpandedInitially={!!searchQuery} onItemClick={handleItemClick} /> | |
))} | |
</ul> | |
</div> | |
); | |
}; | |
export default CatalogTree2; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment