Pass the entire link to the store & fix bulk update function

This commit is contained in:
Isaac Wise 2024-02-10 15:53:46 -06:00
parent da0533ac36
commit 582607e726
9 changed files with 52 additions and 107 deletions

View File

@ -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({
<input
type="checkbox"
className="checkbox checkbox-primary my-auto ml-3 mt-3 absolute z-20 bg-white dark:bg-base-200"
checked={selectedLinks.includes(link.id)}
onChange={() => handleCheckboxClick(link.id)}
checked={selectedLinks.includes(link)}
onChange={() => handleCheckboxClick(link)}
/>
}
<Link

View File

@ -13,7 +13,7 @@ export default function BulkDeleteLinksModal({ onClose }: Props) {
const deleteLink = 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);

View File

@ -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<LinkIncludingShortenedCollectionAndTags, "tags" | "collectionId">) {
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 };
}
}

View File

@ -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 };
}

View File

@ -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,
},
});

View File

@ -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 });

View File

@ -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 });

View File

@ -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);

View File

@ -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<ResponseObject>;
@ -23,7 +23,6 @@ type LinkStore = {
updateLink: (
link: LinkIncludingShortenedCollectionAndTags
) => Promise<ResponseObject>;
updateLinksById: (linkIds: number[], data: Partial<LinkIncludingShortenedCollectionAndTags>) => Promise<ResponseObject>;
removeLink: (linkId: number) => Promise<ResponseObject>;
deleteLinksById: (linkIds: number[]) => Promise<ResponseObject>;
resetLinks: () => void;
@ -50,7 +49,7 @@ const useLinkStore = create<LinkStore>()((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<LinkStore>()((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: {