Pass the entire link to the store & fix bulk update function
This commit is contained in:
parent
da0533ac36
commit
582607e726
|
@ -35,10 +35,16 @@ export default function LinkCard({
|
||||||
|
|
||||||
const { links, getLink, setSelectedLinks, selectedLinks } = useLinkStore();
|
const { links, getLink, setSelectedLinks, selectedLinks } = useLinkStore();
|
||||||
|
|
||||||
const handleCheckboxClick = (checkboxId: number) => {
|
const handleCheckboxClick = (link: LinkIncludingShortenedCollectionAndTags) => {
|
||||||
setSelectedLinks((selectedLinks.includes(checkboxId) ? selectedLinks.filter((id) => id !== checkboxId) : [...selectedLinks, checkboxId]));
|
if (selectedLinks.includes(link)) {
|
||||||
|
setSelectedLinks(selectedLinks.filter((e) => e !== link));
|
||||||
|
} else {
|
||||||
|
setSelectedLinks([...selectedLinks, link]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(selectedLinks)
|
||||||
|
|
||||||
let shortendURL;
|
let shortendURL;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -96,8 +102,8 @@ export default function LinkCard({
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="checkbox checkbox-primary my-auto ml-3 mt-3 absolute z-20 bg-white dark:bg-base-200"
|
className="checkbox checkbox-primary my-auto ml-3 mt-3 absolute z-20 bg-white dark:bg-base-200"
|
||||||
checked={selectedLinks.includes(link.id)}
|
checked={selectedLinks.includes(link)}
|
||||||
onChange={() => handleCheckboxClick(link.id)}
|
onChange={() => handleCheckboxClick(link)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<Link
|
<Link
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default function BulkDeleteLinksModal({ onClose }: Props) {
|
||||||
const deleteLink = async () => {
|
const deleteLink = async () => {
|
||||||
const load = toast.loading(`Deleting ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : ""}...`);
|
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);
|
toast.dismiss(load);
|
||||||
|
|
||||||
|
|
|
@ -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 };
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 };
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { prisma } from "@/lib/api/db";
|
import { prisma } from "@/lib/api/db";
|
||||||
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
|
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
|
||||||
import { Collection, Link, UsersAndCollections } from "@prisma/client";
|
import { UsersAndCollections } from "@prisma/client";
|
||||||
import getPermission from "@/lib/api/getPermission";
|
import getPermission from "@/lib/api/getPermission";
|
||||||
import moveFile from "@/lib/api/storage/moveFile";
|
import moveFile from "@/lib/api/storage/moveFile";
|
||||||
|
|
||||||
|
@ -48,9 +48,9 @@ export default async function updateLinkById(
|
||||||
collection: true,
|
collection: true,
|
||||||
pinnedBy: isCollectionOwner
|
pinnedBy: isCollectionOwner
|
||||||
? {
|
? {
|
||||||
where: { id: userId },
|
where: { id: userId },
|
||||||
select: { id: true },
|
select: { id: true },
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -111,9 +111,9 @@ export default async function updateLinkById(
|
||||||
collection: true,
|
collection: true,
|
||||||
pinnedBy: isCollectionOwner
|
pinnedBy: isCollectionOwner
|
||||||
? {
|
? {
|
||||||
where: { id: userId },
|
where: { id: userId },
|
||||||
select: { id: true },
|
select: { id: true },
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
import verifyUser from "@/lib/api/verifyUser";
|
import verifyUser from "@/lib/api/verifyUser";
|
||||||
import deleteLinksById from "@/lib/api/controllers/links/bulk/deleteLinksById";
|
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) {
|
export default async function links(req: NextApiRequest, res: NextApiResponse) {
|
||||||
const user = await verifyUser({ req, res });
|
const user = await verifyUser({ req, res });
|
||||||
|
|
|
@ -4,7 +4,7 @@ import postLink from "@/lib/api/controllers/links/postLink";
|
||||||
import { LinkRequestQuery } from "@/types/global";
|
import { LinkRequestQuery } from "@/types/global";
|
||||||
import verifyUser from "@/lib/api/verifyUser";
|
import verifyUser from "@/lib/api/verifyUser";
|
||||||
import deleteLinksById from "@/lib/api/controllers/links/bulk/deleteLinksById";
|
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) {
|
export default async function links(req: NextApiRequest, res: NextApiResponse) {
|
||||||
const user = await verifyUser({ req, res });
|
const user = await verifyUser({ req, res });
|
||||||
|
|
|
@ -111,14 +111,14 @@ export default function Index() {
|
||||||
if (selectedLinks.length === links.length) {
|
if (selectedLinks.length === links.length) {
|
||||||
setSelectedLinks([]);
|
setSelectedLinks([]);
|
||||||
} else {
|
} else {
|
||||||
setSelectedLinks(links.map((e) => e.id));
|
setSelectedLinks(links.map((link) => link));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const bulkDeleteLinks = async () => {
|
const bulkDeleteLinks = async () => {
|
||||||
const load = toast.loading(`Deleting ${selectedLinks.length} Link${selectedLinks.length > 1 ? "s" : ""}...`);
|
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);
|
toast.dismiss(load);
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,12 @@ type ResponseObject = {
|
||||||
|
|
||||||
type LinkStore = {
|
type LinkStore = {
|
||||||
links: LinkIncludingShortenedCollectionAndTags[];
|
links: LinkIncludingShortenedCollectionAndTags[];
|
||||||
selectedLinks: number[];
|
selectedLinks: LinkIncludingShortenedCollectionAndTags[];
|
||||||
setLinks: (
|
setLinks: (
|
||||||
data: LinkIncludingShortenedCollectionAndTags[],
|
data: LinkIncludingShortenedCollectionAndTags[],
|
||||||
isInitialCall: boolean
|
isInitialCall: boolean
|
||||||
) => void;
|
) => void;
|
||||||
setSelectedLinks: (linkIds: number[]) => void;
|
setSelectedLinks: (links: LinkIncludingShortenedCollectionAndTags[]) => void;
|
||||||
addLink: (
|
addLink: (
|
||||||
body: LinkIncludingShortenedCollectionAndTags
|
body: LinkIncludingShortenedCollectionAndTags
|
||||||
) => Promise<ResponseObject>;
|
) => Promise<ResponseObject>;
|
||||||
|
@ -23,7 +23,6 @@ type LinkStore = {
|
||||||
updateLink: (
|
updateLink: (
|
||||||
link: LinkIncludingShortenedCollectionAndTags
|
link: LinkIncludingShortenedCollectionAndTags
|
||||||
) => Promise<ResponseObject>;
|
) => Promise<ResponseObject>;
|
||||||
updateLinksById: (linkIds: number[], data: Partial<LinkIncludingShortenedCollectionAndTags>) => Promise<ResponseObject>;
|
|
||||||
removeLink: (linkId: number) => Promise<ResponseObject>;
|
removeLink: (linkId: number) => Promise<ResponseObject>;
|
||||||
deleteLinksById: (linkIds: number[]) => Promise<ResponseObject>;
|
deleteLinksById: (linkIds: number[]) => Promise<ResponseObject>;
|
||||||
resetLinks: () => void;
|
resetLinks: () => void;
|
||||||
|
@ -50,7 +49,7 @@ const useLinkStore = create<LinkStore>()((set) => ({
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
setSelectedLinks: (linkIds) => set({ selectedLinks: linkIds }),
|
setSelectedLinks: (links) => set({ selectedLinks: links }),
|
||||||
addLink: async (body) => {
|
addLink: async (body) => {
|
||||||
const response = await fetch("/api/v1/links", {
|
const response = await fetch("/api/v1/links", {
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
|
@ -128,29 +127,7 @@ const useLinkStore = create<LinkStore>()((set) => ({
|
||||||
|
|
||||||
return { ok: response.ok, data: data.response };
|
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) => {
|
removeLink: async (linkId) => {
|
||||||
const response = await fetch(`/api/v1/links/${linkId}`, {
|
const response = await fetch(`/api/v1/links/${linkId}`, {
|
||||||
headers: {
|
headers: {
|
||||||
|
|
Ŝarĝante…
Reference in New Issue