diff --git a/components/CollectionSelection.tsx b/components/CollectionListing.tsx
similarity index 100%
rename from components/CollectionSelection.tsx
rename to components/CollectionListing.tsx
diff --git a/components/InputSelect/CollectionSelection.tsx b/components/InputSelect/CollectionSelection.tsx
index ec586ea..99b999e 100644
--- a/components/InputSelect/CollectionSelection.tsx
+++ b/components/InputSelect/CollectionSelection.tsx
@@ -44,12 +44,56 @@ export default function CollectionSelection({
useEffect(() => {
const formatedCollections = collections.map((e) => {
- return { value: e.id, label: e.name, ownerId: e.ownerId };
+ return {
+ value: e.id,
+ label: e.name,
+ ownerId: e.ownerId,
+ count: e._count,
+ parentId: e.parentId,
+ };
});
setOptions(formatedCollections);
}, [collections]);
+ const getParentNames = (parentId: number): string[] => {
+ const parentNames = [];
+ const parent = collections.find((e) => e.id === parentId);
+
+ if (parent) {
+ parentNames.push(parent.name);
+ if (parent.parentId) {
+ parentNames.push(...getParentNames(parent.parentId));
+ }
+ }
+
+ // Have the top level parent at beginning
+ return parentNames.reverse();
+ };
+
+ const customOption = ({ data, innerProps }: any) => {
+ return (
+
+
+ {data.label}
+ {data.count?.links}
+
+
+ {getParentNames(data?.parentId).length > 0 ? (
+ <>
+ {getParentNames(data.parentId).join(" > ")} {">"} {data.label}
+ >
+ ) : (
+ data.label
+ )}
+
+
+ );
+ };
+
if (creatable) {
return (
);
@@ -73,6 +120,9 @@ export default function CollectionSelection({
options={options}
styles={styles}
defaultValue={showDefaultValue ? defaultValue : null}
+ components={{
+ Option: customOption,
+ }}
// menuPosition="fixed"
/>
);
diff --git a/components/Sidebar.tsx b/components/Sidebar.tsx
index 66a8d23..3f3e97f 100644
--- a/components/Sidebar.tsx
+++ b/components/Sidebar.tsx
@@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { Disclosure, Transition } from "@headlessui/react";
import SidebarHighlightLink from "@/components/SidebarHighlightLink";
-import CollectionSelection from "@/components/CollectionSelection";
+import CollectionListing from "@/components/CollectionListing";
export default function Sidebar({ className }: { className?: string }) {
const [tagDisclosure, setTagDisclosure] = useState(() => {
@@ -99,7 +99,7 @@ export default function Sidebar({ className }: { className?: string }) {
leaveTo="transform opacity-0 -translate-y-3"
>
-
+
diff --git a/lib/api/controllers/collections/getCollections.ts b/lib/api/controllers/collections/getCollections.ts
index 3742163..fa13798 100644
--- a/lib/api/controllers/collections/getCollections.ts
+++ b/lib/api/controllers/collections/getCollections.ts
@@ -12,6 +12,12 @@ export default async function getCollection(userId: number) {
_count: {
select: { links: true },
},
+ parent: {
+ select: {
+ id: true,
+ name: true,
+ },
+ },
members: {
include: {
user: {
diff --git a/lib/api/controllers/collections/postCollection.ts b/lib/api/controllers/collections/postCollection.ts
index 245f642..94f4763 100644
--- a/lib/api/controllers/collections/postCollection.ts
+++ b/lib/api/controllers/collections/postCollection.ts
@@ -32,27 +32,6 @@ export default async function postCollection(
};
}
- const findCollection = await prisma.user.findUnique({
- where: {
- id: userId,
- },
- select: {
- collections: {
- where: {
- name: collection.name,
- },
- },
- },
- });
-
- const checkIfCollectionExists = findCollection?.collections[0];
-
- if (checkIfCollectionExists)
- return {
- response: "Oops! There's already a Collection with that name.",
- status: 400,
- };
-
const newCollection = await prisma.collection.create({
data: {
owner: {
@@ -65,10 +44,10 @@ export default async function postCollection(
color: collection.color,
parent: collection.parentId
? {
- connect: {
- id: collection.parentId,
- },
- }
+ connect: {
+ id: collection.parentId,
+ },
+ }
: undefined,
},
include: {
diff --git a/lib/api/controllers/links/postLink.ts b/lib/api/controllers/links/postLink.ts
index 1c82fc2..eb82949 100644
--- a/lib/api/controllers/links/postLink.ts
+++ b/lib/api/controllers/links/postLink.ts
@@ -22,8 +22,69 @@ export default async function postLink(
};
}
- if (!link.collection.name) {
+ if (!link.collection.id && link.collection.name) {
+ link.collection.name = link.collection.name.trim();
+
+ // find the collection with the name and the user's id
+ const findCollection = await prisma.collection.findFirst({
+ where: {
+ name: link.collection.name,
+ ownerId: userId,
+ parentId: link.collection.parentId,
+ },
+ });
+
+ if (findCollection) {
+ const collectionIsAccessible = await getPermission({
+ userId,
+ collectionId: findCollection.id,
+ });
+
+ const memberHasAccess = collectionIsAccessible?.members.some(
+ (e: UsersAndCollections) => e.userId === userId && e.canCreate
+ );
+
+ if (!(collectionIsAccessible?.ownerId === userId || memberHasAccess))
+ return { response: "Collection is not accessible.", status: 401 };
+
+ link.collection.id = findCollection.id;
+ } else {
+ const collection = await prisma.collection.create({
+ data: {
+ name: link.collection.name,
+ ownerId: userId,
+ },
+ });
+
+ link.collection.id = collection.id;
+ }
+ } else if (link.collection.id) {
+ const collectionIsAccessible = await getPermission({
+ userId,
+ collectionId: link.collection.id,
+ });
+
+ const memberHasAccess = collectionIsAccessible?.members.some(
+ (e: UsersAndCollections) => e.userId === userId && e.canCreate
+ );
+
+ if (!(collectionIsAccessible?.ownerId === userId || memberHasAccess))
+ return { response: "Collection is not accessible.", status: 401 };
+ } else if (!link.collection.id) {
link.collection.name = "Unorganized";
+ link.collection.parentId = null;
+
+ // find the collection with the name "Unorganized" and the user's id
+ const unorganizedCollection = await prisma.collection.findFirst({
+ where: {
+ name: "Unorganized",
+ ownerId: userId,
+ },
+ });
+
+ link.collection.id = unorganizedCollection?.id;
+ } else {
+ return { response: "Uncaught error.", status: 500 };
}
const numberOfLinksTheUserHas = await prisma.link.count({
@@ -42,22 +103,6 @@ export default async function postLink(
link.collection.name = link.collection.name.trim();
- if (link.collection.id) {
- const collectionIsAccessible = await getPermission({
- userId,
- collectionId: link.collection.id,
- });
-
- const memberHasAccess = collectionIsAccessible?.members.some(
- (e: UsersAndCollections) => e.userId === userId && e.canCreate
- );
-
- if (!(collectionIsAccessible?.ownerId === userId || memberHasAccess))
- return { response: "Collection is not accessible.", status: 401 };
- } else {
- link.collection.ownerId = userId;
- }
-
const description =
link.description && link.description !== ""
? link.description
@@ -86,17 +131,8 @@ export default async function postLink(
description,
type: linkType,
collection: {
- connectOrCreate: {
- where: {
- name_ownerId: {
- ownerId: link.collection.ownerId,
- name: link.collection.name,
- },
- },
- create: {
- name: link.collection.name.trim(),
- ownerId: userId,
- },
+ connect: {
+ id: link.collection.id,
},
},
tags: {
diff --git a/prisma/migrations/20240218080348_allow_duplicate_collection_names/migration.sql b/prisma/migrations/20240218080348_allow_duplicate_collection_names/migration.sql
new file mode 100644
index 0000000..d73171b
--- /dev/null
+++ b/prisma/migrations/20240218080348_allow_duplicate_collection_names/migration.sql
@@ -0,0 +1,2 @@
+-- DropIndex
+DROP INDEX "Collection_name_ownerId_key";
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 036f658..4d9ccec 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -91,8 +91,6 @@ model Collection {
links Link[]
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt
-
- @@unique([name, ownerId])
}
model UsersAndCollections {