import React, { useEffect, useMemo, useState } from "react"; import Tree, { mutateTree, moveItemOnTree, RenderItemParams, TreeItem, TreeData, ItemId, TreeSourcePosition, TreeDestinationPosition, } from "@atlaskit/tree"; import useCollectionStore from "@/store/collections"; import { Collection } from "@prisma/client"; import Link from "next/link"; import { CollectionIncludingMembersAndLinkCount } from "@/types/global"; import { useRouter } from "next/router"; interface ExtendedTreeItem extends TreeItem { data: Collection; } const CollectionListing = () => { const { collections } = useCollectionStore(); const router = useRouter(); const currentPath = router.asPath; const initialTree = useMemo(() => { if (collections.length > 0) { return buildTreeFromCollections(collections, router); } return undefined; }, [collections, router]); const [tree, setTree] = useState(initialTree); useEffect(() => { setTree(initialTree); }, [initialTree]); const onExpand = (itemId: ItemId) => { setTree((currentTree) => mutateTree(currentTree!, itemId, { isExpanded: true }) ); }; const onCollapse = (itemId: ItemId) => { setTree((currentTree) => mutateTree(currentTree as TreeData, itemId, { isExpanded: false }) ); }; const onDragEnd = ( source: TreeSourcePosition, destination: TreeDestinationPosition | undefined ) => { if (!destination || !tree) { return; } setTree((currentTree) => moveItemOnTree(currentTree!, source, destination)); }; if (!tree) { return <>; } else return ( renderItem({ ...itemProps }, currentPath)} onExpand={onExpand} onCollapse={onCollapse} onDragEnd={onDragEnd} isDragEnabled isNestingEnabled /> ); }; export default CollectionListing; const renderItem = ( { item, onExpand, onCollapse, provided }: RenderItemParams, currentPath: string ) => { const collection = item.data; return (
{Icon(item as ExtendedTreeItem, onExpand, onCollapse)}

{collection.name}

{collection.isPublic ? ( ) : undefined}
{collection._count?.links}
); }; const Icon = ( item: ExtendedTreeItem, onExpand: (id: ItemId) => void, onCollapse: (id: ItemId) => void ) => { if (item.children && item.children.length > 0) { return item.isExpanded ? ( ) : ( ); } // return ; return
; }; const buildTreeFromCollections = ( collections: CollectionIncludingMembersAndLinkCount[], router: ReturnType ): TreeData => { const items: { [key: string]: ExtendedTreeItem } = collections.reduce( (acc: any, collection) => { acc[collection.id as number] = { id: collection.id, children: [], hasChildren: false, isExpanded: false, data: { id: collection.id, parentId: collection.parentId, name: collection.name, description: collection.description, color: collection.color, isPublic: collection.isPublic, ownerId: collection.ownerId, createdAt: collection.createdAt, updatedAt: collection.updatedAt, _count: { links: collection._count?.links, }, }, }; return acc; }, {} ); console.log("items:", items); const activeCollectionId = Number(router.asPath.split("/collections/")[1]); if (activeCollectionId) { for (const item in items) { const collection = items[item]; if (Number(item) === activeCollectionId && collection.data.parentId) { // get all the parents of the active collection recursively until root and set isExpanded to true let parentId = collection.data.parentId || null; while (parentId) { items[parentId].isExpanded = true; parentId = items[parentId].data.parentId; } } } } collections.forEach((collection) => { const parentId = collection.parentId; if (parentId && items[parentId] && collection.id) { items[parentId].children.push(collection.id); items[parentId].hasChildren = true; } }); const rootId = "root"; items[rootId] = { id: rootId, children: (collections .filter((c) => c.parentId === null) .map((c) => c.id) || "") as unknown as string[], hasChildren: true, isExpanded: true, data: { name: "Root" } as Collection, }; return { rootId, items }; };