From 44272540aa6aa0fa7159d21e329aa27a1ec4da76 Mon Sep 17 00:00:00 2001 From: Isaac Wise Date: Thu, 22 Feb 2024 01:51:51 -0600 Subject: [PATCH 01/16] Make sidebar collections sortable --- components/CollectionListing.tsx | 119 ++++++++++----- components/Sidebar.tsx | 28 ++-- .../users/userId/updateUserById.ts | 23 +-- next.config.js | 2 +- package.json | 4 + pages/_app.tsx | 1 + .../migration.sql | 2 + prisma/schema.prisma | 1 + yarn.lock | 142 +++++++++++++++++- 9 files changed, 253 insertions(+), 69 deletions(-) create mode 100644 prisma/migrations/20240222050805_collection_order/migration.sql diff --git a/components/CollectionListing.tsx b/components/CollectionListing.tsx index a8d580b..7564165 100644 --- a/components/CollectionListing.tsx +++ b/components/CollectionListing.tsx @@ -1,8 +1,10 @@ +import useAccountStore from "@/store/account"; import useCollectionStore from "@/store/collections"; import { CollectionIncludingMembersAndLinkCount } from "@/types/global"; import Link from "next/link"; import { useRouter } from "next/router"; import React, { useEffect, useState } from "react"; +import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd"; type Props = { links: boolean; @@ -10,37 +12,76 @@ type Props = { const CollectionSelection = ({ links }: Props) => { const { collections } = useCollectionStore(); + const { account, updateAccount } = useAccountStore(); const [active, setActive] = useState(""); const router = useRouter(); useEffect(() => { setActive(router.asPath); + + if (account.collectionOrder?.length === 0) { + updateAccount({ + ...account, + collectionOrder: collections + .filter((e) => e.parentId === null) // Filter out collections with non-null parentId + .map((e) => e.id as number), // Use "as number" to assert that e.id is a number + }); + } }, [router, collections]); return ( -
- {collections[0] ? ( - collections - .sort((a, b) => a.name.localeCompare(b.name)) - .filter((e) => e.parentId === null) - .map((e, i) => ( - - )) - ) : ( -
-

- You Have No Collections... -

-
- )} -
+ { + if (!result.destination) { + return; // Dragged outside the droppable area, do nothing + } + + const updatedCollectionOrder = [...account.collectionOrder]; + const [movedCollectionId] = updatedCollectionOrder.splice(result.source.index, 1); + updatedCollectionOrder.splice(result.destination.index, 0, movedCollectionId); + + // Update account with the new collection order + updateAccount({ + ...account, + collectionOrder: updatedCollectionOrder, + }); + }} + > + + {(provided) => ( +
+ {account.collectionOrder?.map((collectionId, index) => { + const collection = collections.find((c) => c.id === collectionId); + + if (collection) { + return ( + + {(provided) => ( + + )} + + ); + } + + return null; // Collection not found + })} + {provided.placeholder} +
+ )} +
+
); }; @@ -50,15 +91,16 @@ const CollectionItem = ({ collection, active, collections, + innerRef, + ...props }: { collection: CollectionIncludingMembersAndLinkCount; active: string; collections: CollectionIncludingMembersAndLinkCount[]; + innerRef?: any; }) => { const hasChildren = collections.some((e) => e.parentId === collection.id); - const router = useRouter(); - // Check if the current collection or any of its subcollections is active const isActiveOrParentOfActive = React.useMemo(() => { const isActive = active === `/collections/${collection.id}`; @@ -86,20 +128,20 @@ const CollectionItem = ({ return hasChildren ? ( <>
@@ -140,13 +182,12 @@ const CollectionItem = ({ )} ) : ( - +
{ localStorage.setItem("tagDisclosure", tagDisclosure ? "true" : "false"); }, [tagDisclosure]); @@ -42,12 +41,12 @@ export default function Sidebar({ className }: { className?: string }) { setActive(router.asPath); }, [router, collections]); + return (