"use client";
import { useEffect, useRef, useState } from "react";
import styles from "./CategoryTreeView.module.css";
export type CategoryTreeNode = {
id: string;
name: string;
hint?: string;
children: CategoryTreeNode[];
};
export type CategoryTreeActions = {
onAddChild?: (id: string) => void;
onEdit?: (id: string) => void;
onRemove?: (id: string) => void;
};
export default function CategoryTreeView({
nodes,
emptyLabel = "No categories yet",
actions,
}: {
nodes: CategoryTreeNode[];
emptyLabel?: string;
actions?: CategoryTreeActions;
}) {
if (!nodes.length) {
return
{emptyLabel}
;
}
return (
{nodes.map((node) => (
))}
);
}
function TreeBranch({
node,
depth,
actions,
}: {
node: CategoryTreeNode;
depth: number;
actions?: CategoryTreeActions;
}) {
const [open, setOpen] = useState(false);
const childCount = node.children.length;
const previousChildCount = useRef(childCount);
const hasChildren = childCount > 0;
const hasActions = Boolean(
actions?.onAddChild || actions?.onEdit || actions?.onRemove,
);
useEffect(() => {
if (childCount > previousChildCount.current) {
setOpen(true);
}
previousChildCount.current = childCount;
}, [childCount]);
return (
{hasChildren ? (
) : (
)}
{node.name}
{node.hint ?
{node.hint} : null}
{hasActions ? (
{actions?.onAddChild ? (
) : null}
{actions?.onEdit ? (
) : null}
{actions?.onRemove ? (
) : null}
) : null}
{hasChildren && open ? (
{node.children.map((child) => (
))}
) : null}
);
}