diff --git a/components/LinkCard.tsx b/components/LinkCard.tsx index 04903fa..e4dbbdc 100644 --- a/components/LinkCard.tsx +++ b/components/LinkCard.tsx @@ -28,12 +28,19 @@ type Props = { className?: string; }; +type DropdownTrigger = + | { + x: number; + y: number; + } + | false; + export default function LinkCard({ link, count, className }: Props) { const { setModal } = useModalStore(); const permissions = usePermissions(link.collection.id as number); - const [expandDropdown, setExpandDropdown] = useState(false); + const [expandDropdown, setExpandDropdown] = useState(false); const { collections } = useCollectionStore(); @@ -84,6 +91,23 @@ export default function LinkCard({ link, count, className }: Props) { toast.success(`Link ${isAlreadyPinned ? "Unpinned!" : "Pinned!"}`); }; + const updateArchive = async () => { + const load = toast.loading("Applying..."); + + setExpandDropdown(false); + + const response = await fetch(`/api/v1/links/${link.id}/archive`, { + method: "PUT", + }); + + const data = await response.json(); + + toast.dismiss(load); + + if (response.ok) toast.success(`Link is being archived.`); + else toast.error(data); + }; + const deleteLink = async () => { const load = toast.loading("Deleting..."); @@ -114,7 +138,10 @@ export default function LinkCard({ link, count, className }: Props) { permissions?.canUpdate || permissions?.canDelete) && (
setExpandDropdown(!expandDropdown)} + onClick={(e) => { + console.log(); + setExpandDropdown({ x: e.clientX, y: e.clientY }); + }} id={"expand-dropdown" + link.id} className="text-gray-500 dark:text-gray-300 inline-flex rounded-md cursor-pointer hover:bg-slate-200 dark:hover:bg-neutral-700 absolute right-5 top-5 z-10 duration-100 p-1" > @@ -228,6 +255,12 @@ export default function LinkCard({ link, count, className }: Props) { }, } : undefined, + permissions === true + ? { + name: "Update Archive", + onClick: updateArchive, + } + : undefined, permissions === true || permissions?.canDelete ? { name: "Delete", diff --git a/components/Modal/Link/LinkDetails.tsx b/components/Modal/Link/LinkDetails.tsx index e593e09..55328f6 100644 --- a/components/Modal/Link/LinkDetails.tsx +++ b/components/Modal/Link/LinkDetails.tsx @@ -228,72 +228,77 @@ export default function LinkDetails({ link, isOwnerOrMod }: Props) {

{formattedDate}

+
-
-
-
- + {link.screenshotPath && link.screenshotPath !== "pending" ? ( +
+
+
+ +
+ +

Screenshot

-

Screenshot

-
+
+
handleDownload("png")} + className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md" + > + +
-
-
handleDownload("png")} - className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md" - > - + + + +
+
+ ) : undefined} + + {link.pdfPath && link.pdfPath !== "pending" ? ( +
+
+
+ +
+ +

PDF

- - - -
-
+
+
handleDownload("pdf")} + className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md" + > + +
-
-
-
- + + +
- -

PDF

- -
-
handleDownload("pdf")} - className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md" - > - -
- - - - -
-
+ ) : undefined}
diff --git a/lib/api/archive.ts b/lib/api/archive.ts index fce0454..b257940 100644 --- a/lib/api/archive.ts +++ b/lib/api/archive.ts @@ -14,6 +14,16 @@ export default async function archive( }, }); + const link = await prisma.link.update({ + where: { + id: linkId, + }, + data: { + screenshotPath: "pending", + pdfPath: "pending", + }, + }); + if (user?.archiveAsWaybackMachine) sendToWayback(url); if (user?.archiveAsPDF || user?.archiveAsScreenshot) { @@ -41,7 +51,7 @@ export default async function archive( fullPage: true, }); - createFile({ + await createFile({ data: screenshot, filePath: `archives/${linkExists.collectionId}/${linkId}.png`, }); @@ -55,11 +65,25 @@ export default async function archive( margin: { top: "15px", bottom: "15px" }, }); - createFile({ + await createFile({ data: pdf, filePath: `archives/${linkExists.collectionId}/${linkId}.pdf`, }); } + + const updateLink = await prisma.link.update({ + where: { + id: linkId, + }, + data: { + screenshotPath: user.archiveAsScreenshot + ? `archives/${linkExists.collectionId}/${linkId}.png` + : null, + pdfPath: user.archiveAsPDF + ? `archives/${linkExists.collectionId}/${linkId}.pdf` + : null, + }, + }); } await browser.close(); diff --git a/pages/api/v1/links/[id]/archive/index.ts b/pages/api/v1/links/[id]/archive/index.ts new file mode 100644 index 0000000..29e5c66 --- /dev/null +++ b/pages/api/v1/links/[id]/archive/index.ts @@ -0,0 +1,45 @@ +import type { NextApiRequest, NextApiResponse } from "next"; +import { getServerSession } from "next-auth/next"; +import { authOptions } from "@/pages/api/v1/auth/[...nextauth]"; +import archive from "@/lib/api/archive"; +import { prisma } from "@/lib/api/db"; + +export default async function links(req: NextApiRequest, res: NextApiResponse) { + console.log("hi"); + const session = await getServerSession(req, res, authOptions); + + if (!session?.user?.id) { + return res.status(401).json({ response: "You must be logged in." }); + } else if (session?.user?.isSubscriber === false) + res.status(401).json({ + response: + "You are not a subscriber, feel free to reach out to us at support@linkwarden.app in case of any issues.", + }); + + const link = await prisma.link.findUnique({ + where: { + id: Number(req.query.id), + }, + include: { collection: true }, + }); + + if (!link) + return res.status(404).json({ + response: "Link not found.", + }); + + if (link.collection.ownerId !== session.user.id) + return res.status(401).json({ + response: "Permission denied.", + }); + + if (req.method === "PUT") { + archive(link.id, link.url, session.user.id); + return res.status(200).json({ + response: "Link is being archived.", + }); + } + + // Later? + // else if (req.method === "DELETE") {} +} diff --git a/pages/api/v1/links/[id].ts b/pages/api/v1/links/[id]/index.ts similarity index 100% rename from pages/api/v1/links/[id].ts rename to pages/api/v1/links/[id]/index.ts diff --git a/types/global.ts b/types/global.ts index cfc149b..4af954d 100644 --- a/types/global.ts +++ b/types/global.ts @@ -5,7 +5,7 @@ type OptionalExcluding = Partial & Pick; export interface LinkIncludingShortenedCollectionAndTags - extends Omit { + extends Omit { id?: number; createdAt?: string; collectionId?: number;