From 582607e726895c270750d5cfa078610849697f5a Mon Sep 17 00:00:00 2001 From: Isaac Wise Date: Sat, 10 Feb 2024 15:53:46 -0600 Subject: [PATCH] Pass the entire link to the store & fix bulk update function --- components/LinkViews/LinkCard.tsx | 14 ++-- .../ModalContent/BulkDeleteLinksModal.tsx | 2 +- lib/api/controllers/links/bulk/updateLinks.ts | 27 ++++++++ .../controllers/links/bulk/updateLinksById.ts | 65 ------------------- .../links/linkId/updateLinkById.ts | 14 ++-- pages/api/v1/links/bulk/index.ts | 2 +- pages/api/v1/links/index.ts | 2 +- pages/collections/[id].tsx | 4 +- store/links.ts | 29 +-------- 9 files changed, 52 insertions(+), 107 deletions(-) create mode 100644 lib/api/controllers/links/bulk/updateLinks.ts delete mode 100644 lib/api/controllers/links/bulk/updateLinksById.ts diff --git a/components/LinkViews/LinkCard.tsx b/components/LinkViews/LinkCard.tsx index a85ffcc..d08b898 100644 --- a/components/LinkViews/LinkCard.tsx +++ b/components/LinkViews/LinkCard.tsx @@ -35,10 +35,16 @@ export default function LinkCard({ const { links, getLink, setSelectedLinks, selectedLinks } = useLinkStore(); - const handleCheckboxClick = (checkboxId: number) => { - setSelectedLinks((selectedLinks.includes(checkboxId) ? selectedLinks.filter((id) => id !== checkboxId) : [...selectedLinks, checkboxId])); + const handleCheckboxClick = (link: LinkIncludingShortenedCollectionAndTags) => { + if (selectedLinks.includes(link)) { + setSelectedLinks(selectedLinks.filter((e) => e !== link)); + } else { + setSelectedLinks([...selectedLinks, link]); + } }; + console.log(selectedLinks) + let shortendURL; try { @@ -96,8 +102,8 @@ export default function LinkCard({ handleCheckboxClick(link.id)} + checked={selectedLinks.includes(link)} + onChange={() => handleCheckboxClick(link)} /> } { const load = toast.loading(`Deleting ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : ""}...`); - const response = await deleteLinksById(selectedLinks); + const response = await deleteLinksById(selectedLinks.map(link => link.id)); toast.dismiss(load); diff --git a/lib/api/controllers/links/bulk/updateLinks.ts b/lib/api/controllers/links/bulk/updateLinks.ts new file mode 100644 index 0000000..7faaf38 --- /dev/null +++ b/lib/api/controllers/links/bulk/updateLinks.ts @@ -0,0 +1,27 @@ +import { LinkIncludingShortenedCollectionAndTags } from "@/types/global"; +import updateLinkById from "../linkId/updateLinkById"; + +// Need to fix this +export default async function updateLinks(userId: number, links: LinkIncludingShortenedCollectionAndTags[], newData: Pick) { + let allUpdatesSuccessful = true; + + for (const link of links) { + const updatedData: LinkIncludingShortenedCollectionAndTags = { + ...link, + tags: [...link.tags, ...(newData.tags ?? [])], + collectionId: newData.collectionId ?? link.collectionId, + } + + const updatedLink = await updateLinkById(userId, link.id, updatedData); + + if (updatedLink.status !== 200) { + allUpdatesSuccessful = false; + } + } + + if (allUpdatesSuccessful) { + return { response: "All links updated successfully", status: 200 }; + } else { + return { response: "Some links failed to update", status: 400 }; + } +} \ No newline at end of file diff --git a/lib/api/controllers/links/bulk/updateLinksById.ts b/lib/api/controllers/links/bulk/updateLinksById.ts deleted file mode 100644 index 76ca346..0000000 --- a/lib/api/controllers/links/bulk/updateLinksById.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { LinkIncludingShortenedCollectionAndTags } from "@/types/global"; -import { prisma } from "@/lib/api/db"; -import getPermission from "@/lib/api/getPermission"; -import { UsersAndCollections } from "@prisma/client"; - -// Need to fix this -export default async function updateLinksById(userId: number, linkIds: number[], data: LinkIncludingShortenedCollectionAndTags) { - if (!linkIds || linkIds.length === 0) { - return { response: "Please choose valid links.", status: 401 }; - } - - // Check if the user has access to the collection of each link - // if any of the links are not accessible, return an error - for (const linkId of linkIds) { - const linkIsAccessible = await getPermission({ userId, linkId }); - - const memberHasAccess = linkIsAccessible?.members.some( - (e: UsersAndCollections) => e.userId === userId && e.canUpdate - ); - - if (!(linkIsAccessible?.ownerId === userId || memberHasAccess)) { - return { response: "Link is not accessible.", status: 401 }; - } - } - - const updateData = { - collection: { - connect: { - id: data.collection.id, - }, - }, - tags: { - set: [], - connectOrCreate: data.tags.map((tag) => ({ - where: { - name_ownerId: { - name: tag.name, - ownerId: data.collection.ownerId, - }, - }, - create: { - name: tag.name, - owner: { - connect: { - id: data.collection.ownerId, - }, - }, - }, - })), - }, - include: { - tags: true, - collection: true, - } - }; - - const updatedLinks = await prisma.link.updateMany({ - where: { - id: { in: linkIds }, - }, - data: updateData, - }); - - return { response: updatedLinks, status: 200 }; -} \ No newline at end of file diff --git a/lib/api/controllers/links/linkId/updateLinkById.ts b/lib/api/controllers/links/linkId/updateLinkById.ts index ce6b920..ebfe2c0 100644 --- a/lib/api/controllers/links/linkId/updateLinkById.ts +++ b/lib/api/controllers/links/linkId/updateLinkById.ts @@ -1,6 +1,6 @@ import { prisma } from "@/lib/api/db"; import { LinkIncludingShortenedCollectionAndTags } from "@/types/global"; -import { Collection, Link, UsersAndCollections } from "@prisma/client"; +import { UsersAndCollections } from "@prisma/client"; import getPermission from "@/lib/api/getPermission"; import moveFile from "@/lib/api/storage/moveFile"; @@ -48,9 +48,9 @@ export default async function updateLinkById( collection: true, pinnedBy: isCollectionOwner ? { - where: { id: userId }, - select: { id: true }, - } + where: { id: userId }, + select: { id: true }, + } : undefined, }, }); @@ -111,9 +111,9 @@ export default async function updateLinkById( collection: true, pinnedBy: isCollectionOwner ? { - where: { id: userId }, - select: { id: true }, - } + where: { id: userId }, + select: { id: true }, + } : undefined, }, }); diff --git a/pages/api/v1/links/bulk/index.ts b/pages/api/v1/links/bulk/index.ts index 71779c0..35e3362 100644 --- a/pages/api/v1/links/bulk/index.ts +++ b/pages/api/v1/links/bulk/index.ts @@ -1,7 +1,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import verifyUser from "@/lib/api/verifyUser"; import deleteLinksById from "@/lib/api/controllers/links/bulk/deleteLinksById"; -import updateLinksById from "@/lib/api/controllers/links/bulk/updateLinksById"; +import updateLinksById from "@/lib/api/controllers/links/bulk/updateLinks"; export default async function links(req: NextApiRequest, res: NextApiResponse) { const user = await verifyUser({ req, res }); diff --git a/pages/api/v1/links/index.ts b/pages/api/v1/links/index.ts index 8e58bac..cca1e3e 100644 --- a/pages/api/v1/links/index.ts +++ b/pages/api/v1/links/index.ts @@ -4,7 +4,7 @@ import postLink from "@/lib/api/controllers/links/postLink"; import { LinkRequestQuery } from "@/types/global"; import verifyUser from "@/lib/api/verifyUser"; import deleteLinksById from "@/lib/api/controllers/links/bulk/deleteLinksById"; -import updateLinksById from "@/lib/api/controllers/links/bulk/updateLinksById"; +import updateLinksById from "@/lib/api/controllers/links/bulk/updateLinks"; export default async function links(req: NextApiRequest, res: NextApiResponse) { const user = await verifyUser({ req, res }); diff --git a/pages/collections/[id].tsx b/pages/collections/[id].tsx index c3b2964..a5d9948 100644 --- a/pages/collections/[id].tsx +++ b/pages/collections/[id].tsx @@ -111,14 +111,14 @@ export default function Index() { if (selectedLinks.length === links.length) { setSelectedLinks([]); } else { - setSelectedLinks(links.map((e) => e.id)); + setSelectedLinks(links.map((link) => link)); } }; const bulkDeleteLinks = async () => { const load = toast.loading(`Deleting ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : ""}...`); - const response = await deleteLinksById(selectedLinks); + const response = await deleteLinksById(selectedLinks.map((link) => link.id)); toast.dismiss(load); diff --git a/store/links.ts b/store/links.ts index 00fda9d..72f681f 100644 --- a/store/links.ts +++ b/store/links.ts @@ -10,12 +10,12 @@ type ResponseObject = { type LinkStore = { links: LinkIncludingShortenedCollectionAndTags[]; - selectedLinks: number[]; + selectedLinks: LinkIncludingShortenedCollectionAndTags[]; setLinks: ( data: LinkIncludingShortenedCollectionAndTags[], isInitialCall: boolean ) => void; - setSelectedLinks: (linkIds: number[]) => void; + setSelectedLinks: (links: LinkIncludingShortenedCollectionAndTags[]) => void; addLink: ( body: LinkIncludingShortenedCollectionAndTags ) => Promise; @@ -23,7 +23,6 @@ type LinkStore = { updateLink: ( link: LinkIncludingShortenedCollectionAndTags ) => Promise; - updateLinksById: (linkIds: number[], data: Partial) => Promise; removeLink: (linkId: number) => Promise; deleteLinksById: (linkIds: number[]) => Promise; resetLinks: () => void; @@ -50,7 +49,7 @@ const useLinkStore = create()((set) => ({ ), })); }, - setSelectedLinks: (linkIds) => set({ selectedLinks: linkIds }), + setSelectedLinks: (links) => set({ selectedLinks: links }), addLink: async (body) => { const response = await fetch("/api/v1/links", { body: JSON.stringify(body), @@ -128,29 +127,7 @@ const useLinkStore = create()((set) => ({ return { ok: response.ok, data: data.response }; }, - updateLinksById: async (linkIds, data) => { - const response = await fetch("/api/v1/links", { - body: JSON.stringify({ linkIds, data }), - headers: { - "Content-Type": "application/json", - }, - method: "PUT", - }); - const responseData = await response.json(); - - if (response.ok) { - set((state) => ({ - links: state.links.map((link) => - linkIds.includes(link.id) ? { ...link, ...data } : link - ), - })); - useTagStore.getState().setTags(); - useCollectionStore.getState().setCollections(); - } - - return { ok: response.ok, data: responseData.response }; - }, removeLink: async (linkId) => { const response = await fetch(`/api/v1/links/${linkId}`, { headers: {