finished the collection listing ui

This commit is contained in:
daniel31x13 2024-03-01 06:59:14 -05:00
parent ac70c9e29c
commit 84aeac96ce

View File

@ -1,4 +1,4 @@
import React, { Component, useCallback, useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import Tree, { import Tree, {
mutateTree, mutateTree,
moveItemOnTree, moveItemOnTree,
@ -9,159 +9,53 @@ import Tree, {
TreeSourcePosition, TreeSourcePosition,
TreeDestinationPosition, TreeDestinationPosition,
} from "@atlaskit/tree"; } from "@atlaskit/tree";
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
import useCollectionStore from "@/store/collections"; import useCollectionStore from "@/store/collections";
import { Collection } from "@prisma/client";
import Link from "next/link";
const collections = [ interface ExtendedTreeItem extends TreeItem {
{ data: Collection;
id: 262, }
name: "dasd",
description: "",
color: "#0ea5e9",
parentId: null,
isPublic: false,
ownerId: 1,
createdAt: "2024-02-18T23:40:44.043Z",
updatedAt: "2024-02-19T19:16:14.873Z",
parent: null,
members: [
{
userId: 17,
collectionId: 262,
canCreate: true,
canUpdate: false,
canDelete: false,
createdAt: "2024-02-19T19:16:14.873Z",
updatedAt: "2024-02-19T19:16:14.873Z",
user: { username: "test", name: "ben", image: "" },
},
],
_count: { links: 0 },
},
{
id: 268,
name: "ab",
description: "",
color: "#0ea5e9",
parentId: 267,
isPublic: false,
ownerId: 17,
createdAt: "2024-02-19T21:06:52.545Z",
updatedAt: "2024-02-19T21:06:52.545Z",
parent: { id: 267, name: "a" },
members: [],
_count: { links: 0 },
},
{
id: 269,
name: "abc",
description: "",
color: "#0ea5e9",
parentId: 268,
isPublic: false,
ownerId: 17,
createdAt: "2024-02-19T21:07:08.565Z",
updatedAt: "2024-02-19T21:07:08.565Z",
parent: { id: 268, name: "ab" },
members: [],
_count: { links: 0 },
},
{
id: 267,
name: "a",
description: "",
color: "#0ea5e9",
parentId: null,
isPublic: false,
ownerId: 17,
createdAt: "2024-02-19T21:06:45.402Z",
updatedAt: "2024-02-26T16:59:20.312Z",
parent: null,
members: [],
_count: { links: 0 },
},
{
id: 80,
name: "abc",
description: "s",
color: "#0ea5e9",
parentId: 79,
isPublic: false,
ownerId: 1,
createdAt: "2024-02-05T07:00:46.881Z",
updatedAt: "2024-02-27T06:11:46.358Z",
parent: { id: 79, name: "ab" },
members: [
{
userId: 17,
collectionId: 80,
canCreate: false,
canUpdate: false,
canDelete: false,
createdAt: "2024-02-27T06:11:46.358Z",
updatedAt: "2024-02-27T06:11:46.358Z",
user: { username: "test", name: "ben", image: "" },
},
{
userId: 2,
collectionId: 80,
canCreate: false,
canUpdate: false,
canDelete: false,
createdAt: "2024-02-27T06:11:46.358Z",
updatedAt: "2024-02-27T06:11:46.358Z",
user: {
username: "sarah_connor",
name: "Sarah Smith",
image: "uploads/avatar/2.jpg",
},
},
],
_count: { links: 0 },
},
];
const DragDropWithNestingTree = () => { const DragDropWithNestingTree = () => {
const buildTreeFromCollections = (collections) => { const buildTreeFromCollections = (collections: Collection[]): TreeData => {
// Step 1: Map Collections to TreeItems const items: { [key: string]: ExtendedTreeItem } = collections.reduce(
const items = collections.reduce((acc, collection) => { (acc: any, collection) => {
acc[collection.id] = { acc[collection.id] = {
id: collection.id.toString(), id: collection.id,
children: [], children: [],
hasChildren: false, // Initially assume no children, adjust in Step 2 hasChildren: false,
isExpanded: false, isExpanded: false,
data: { data: {
title: collection.name, name: collection.name,
description: collection.description, description: collection.description,
color: collection.color, color: collection.color,
isPublic: collection.isPublic, isPublic: collection.isPublic,
ownerId: collection.ownerId, ownerId: collection.ownerId,
createdAt: collection.createdAt, createdAt: collection.createdAt,
updatedAt: collection.updatedAt, updatedAt: collection.updatedAt,
}, },
}; };
return acc; return acc;
}, {}); },
{}
);
// Step 2: Build Hierarchy
collections.forEach((collection) => { collections.forEach((collection) => {
const parentId = collection.parentId; const parentId = collection.parentId;
if (parentId !== null && items[parentId]) { if (parentId && items[parentId]) {
items[parentId].children.push(collection.id.toString()); items[parentId].children.push(collection.id);
items[parentId].hasChildren = true; items[parentId].hasChildren = true;
} }
}); });
// Define a root item to act as the top-level node of your tree if needed
const rootId = "root"; const rootId = "root";
items[rootId] = { items[rootId] = {
id: rootId, id: rootId,
children: collections children: collections.filter((c) => c.parentId === null).map((c) => c.id),
.filter((c) => c.parentId === null)
.map((c) => c.id.toString()),
hasChildren: true, hasChildren: true,
isExpanded: true, isExpanded: true,
data: { title: "Root" }, data: { name: "Root" } as Collection,
}; };
return { rootId, items }; return { rootId, items };
@ -172,11 +66,17 @@ const DragDropWithNestingTree = () => {
const { collections } = useCollectionStore(); const { collections } = useCollectionStore();
useEffect(() => { useEffect(() => {
const initialTree = buildTreeFromCollections(collections); const initialTree = buildTreeFromCollections(
collections as unknown as Collection[]
);
collections[0] && setTree(initialTree); collections[0] && setTree(initialTree);
}, [collections]); }, [collections]);
const getIcon = useCallback((item, onExpand, onCollapse) => { const getIcon = (
item: ExtendedTreeItem,
onExpand: (id: ItemId) => void,
onCollapse: (id: ItemId) => void
) => {
if (item.children && item.children.length > 0) { if (item.children && item.children.length > 0) {
return item.isExpanded ? ( return item.isExpanded ? (
<button onClick={() => onCollapse(item.id)}> <button onClick={() => onCollapse(item.id)}>
@ -188,63 +88,82 @@ const DragDropWithNestingTree = () => {
</button> </button>
); );
} }
return <span>&bull;</span>; // return <span>&bull;</span>;
}, []); };
const renderItem = useCallback( const renderItem = ({
({ item, onExpand, onCollapse, provided }: RenderItemParams) => { item,
return ( onExpand,
<div ref={provided.innerRef} {...provided.draggableProps}> onCollapse,
provided,
}: RenderItemParams) => {
const collection = item.data;
return (
<div
ref={provided.innerRef}
{...provided.draggableProps}
className="flex gap-1 items-center ml-2"
>
{getIcon(item as ExtendedTreeItem, onExpand, onCollapse)}
<Link
href={`/collections/${collection.id}`}
className="w-full"
{...provided.dragHandleProps}
>
<div <div
className="flex gap-1 items-center" className={`duration-100 py-1 pr-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize mb-1`}
{...provided.dragHandleProps}
> >
{getIcon(item, onExpand, onCollapse)} <i
{item.data ? item.data.title : ""} className="bi-folder-fill text-2xl drop-shadow"
style={{ color: collection.color }}
></i>
<p className="truncate w-full">{collection.name}</p>
{collection.isPublic ? (
<i
className="bi-globe2 text-sm text-black/50 dark:text-white/50 drop-shadow"
title="This collection is being shared publicly."
></i>
) : undefined}
<div className="drop-shadow text-neutral text-xs">
{collection._count?.links}
</div>
</div> </div>
</div> </Link>
); </div>
}, );
[getIcon] };
);
const onExpand = useCallback(
(itemId: ItemId) => {
if (tree) {
setTree((currentTree) =>
mutateTree(currentTree, itemId, { isExpanded: true })
);
}
},
[tree]
);
const onCollapse = useCallback(
(itemId: ItemId) => {
if (tree) {
setTree((currentTree) =>
mutateTree(currentTree, itemId, { isExpanded: false })
);
}
},
[tree]
);
const onDragEnd = useCallback(
(source: TreeSourcePosition, destination?: TreeDestinationPosition) => {
if (!destination || !tree) {
return;
}
const onExpand = (itemId: ItemId) => {
if (tree) {
setTree((currentTree) => setTree((currentTree) =>
moveItemOnTree(currentTree, source, destination) mutateTree(currentTree!, itemId, { isExpanded: true })
); );
}, }
[tree] };
);
const onCollapse = (itemId: ItemId) => {
if (tree) {
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) { if (!tree) {
return <div>Loading...</div>; // or any other loading state representation return <div>Loading...</div>;
} }
return ( return (
@ -261,99 +180,3 @@ const DragDropWithNestingTree = () => {
}; };
export default DragDropWithNestingTree; export default DragDropWithNestingTree;
class TreeBuilder {
rootId: ItemId;
items: Record<ItemId, TreeItem>;
constructor(rootId: ItemId) {
const rootItem = this._createItem(`${rootId}`);
this.rootId = rootItem.id;
this.items = {
[rootItem.id]: rootItem,
};
}
withLeaf(id: number) {
const leafItem = this._createItem(`${this.rootId}-${id}`);
this._addItemToRoot(leafItem.id);
this.items[leafItem.id] = leafItem;
return this;
}
withSubTree(tree: TreeBuilder) {
const subTree = tree.build();
this._addItemToRoot(`${this.rootId}-${subTree.rootId}`);
Object.keys(subTree.items).forEach((itemId) => {
const finalId = `${this.rootId}-${itemId}`;
this.items[finalId] = {
...subTree.items[itemId],
id: finalId,
children: subTree.items[itemId].children.map(
(i) => `${this.rootId}-${i}`
),
};
});
return this;
}
build() {
return {
rootId: this.rootId,
items: this.items,
};
}
_addItemToRoot(id: string) {
const rootItem = this.items[this.rootId];
rootItem.children.push(id);
rootItem.isExpanded = true;
rootItem.hasChildren = true;
}
_createItem = (id: string) => {
return {
id: `${id}`,
children: [],
hasChildren: false,
isExpanded: false,
isChildrenLoading: false,
data: {
title: `Title ${id}`,
},
};
};
}
const complexTree: TreeData = new TreeBuilder(1)
.withLeaf(0) // 0
.withLeaf(1) // 1
.withSubTree(
new TreeBuilder(2) // 2
.withLeaf(0) // 3
.withLeaf(1) // 4
.withLeaf(2) // 5
.withLeaf(3) // 6
)
.withLeaf(3) // 7
.withLeaf(4) // 8
.withLeaf(5) // 9
.withSubTree(
new TreeBuilder(6) // 10
.withLeaf(0) // 11
.withLeaf(1) // 12
.withSubTree(
new TreeBuilder(2) // 13
.withLeaf(0) // 14
.withLeaf(1) // 15
.withLeaf(2) // 16
)
.withLeaf(3) // 17
.withLeaf(4) // 18
)
.withLeaf(7) // 19
.withLeaf(8) // 20
.build();