added rearchive functionallity + dropdown fix [WIP]

This commit is contained in:
daniel31x13 2023-10-28 05:57:53 -04:00
parent 9b6038201c
commit ac795cdbdc
6 changed files with 169 additions and 62 deletions

View File

@ -28,12 +28,19 @@ type Props = {
className?: string; className?: string;
}; };
type DropdownTrigger =
| {
x: number;
y: number;
}
| false;
export default function LinkCard({ link, count, className }: Props) { export default function LinkCard({ link, count, className }: Props) {
const { setModal } = useModalStore(); const { setModal } = useModalStore();
const permissions = usePermissions(link.collection.id as number); const permissions = usePermissions(link.collection.id as number);
const [expandDropdown, setExpandDropdown] = useState(false); const [expandDropdown, setExpandDropdown] = useState<DropdownTrigger>(false);
const { collections } = useCollectionStore(); const { collections } = useCollectionStore();
@ -84,6 +91,23 @@ export default function LinkCard({ link, count, className }: Props) {
toast.success(`Link ${isAlreadyPinned ? "Unpinned!" : "Pinned!"}`); 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 deleteLink = async () => {
const load = toast.loading("Deleting..."); const load = toast.loading("Deleting...");
@ -114,7 +138,10 @@ export default function LinkCard({ link, count, className }: Props) {
permissions?.canUpdate || permissions?.canUpdate ||
permissions?.canDelete) && ( permissions?.canDelete) && (
<div <div
onClick={() => setExpandDropdown(!expandDropdown)} onClick={(e) => {
console.log();
setExpandDropdown({ x: e.clientX, y: e.clientY });
}}
id={"expand-dropdown" + link.id} 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" 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, : undefined,
permissions === true
? {
name: "Update Archive",
onClick: updateArchive,
}
: undefined,
permissions === true || permissions?.canDelete permissions === true || permissions?.canDelete
? { ? {
name: "Delete", name: "Delete",

View File

@ -228,72 +228,77 @@ export default function LinkDetails({ link, isOwnerOrMod }: Props) {
<p>{formattedDate}</p> <p>{formattedDate}</p>
</div> </div>
</div> </div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div className="flex justify-between items-center pr-1 border border-sky-100 dark:border-neutral-700 rounded-md"> {link.screenshotPath && link.screenshotPath !== "pending" ? (
<div className="flex gap-2 items-center"> <div className="flex justify-between items-center pr-1 border border-sky-100 dark:border-neutral-700 rounded-md">
<div className="text-white bg-sky-300 dark:bg-sky-600 p-2 rounded-l-md"> <div className="flex gap-2 items-center">
<FontAwesomeIcon icon={faFileImage} className="w-6 h-6" /> <div className="text-white bg-sky-300 dark:bg-sky-600 p-2 rounded-l-md">
<FontAwesomeIcon icon={faFileImage} className="w-6 h-6" />
</div>
<p className="text-black dark:text-white">Screenshot</p>
</div> </div>
<p className="text-black dark:text-white">Screenshot</p> <div className="flex text-black dark:text-white gap-1">
</div> <div
onClick={() => handleDownload("png")}
className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md"
>
<FontAwesomeIcon
icon={faCloudArrowDown}
className="w-5 h-5 cursor-pointer text-sky-500 dark:text-sky-500"
/>
</div>
<div className="flex text-black dark:text-white gap-1"> <Link
<div href={`/api/v1/archives/${link.collectionId}/${link.id}.png`}
onClick={() => handleDownload("png")} target="_blank"
className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md" className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faCloudArrowDown} icon={faArrowUpRightFromSquare}
className="w-5 h-5 cursor-pointer text-sky-500 dark:text-sky-500" className="w-5 h-5 text-sky-500 dark:text-sky-500"
/> />
</Link>
</div>
</div>
) : undefined}
{link.pdfPath && link.pdfPath !== "pending" ? (
<div className="flex justify-between items-center pr-1 border border-sky-100 dark:border-neutral-700 rounded-md">
<div className="flex gap-2 items-center">
<div className="text-white bg-sky-300 dark:bg-sky-600 p-2 rounded-l-md">
<FontAwesomeIcon icon={faFilePdf} className="w-6 h-6" />
</div>
<p className="text-black dark:text-white">PDF</p>
</div> </div>
<Link <div className="flex text-black dark:text-white gap-1">
href={`/api/v1/archives/${link.collectionId}/${link.id}.png`} <div
target="_blank" onClick={() => handleDownload("pdf")}
className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md" className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faArrowUpRightFromSquare} icon={faCloudArrowDown}
className="w-5 h-5 text-sky-500 dark:text-sky-500" className="w-5 h-5 cursor-pointer text-sky-500 dark:text-sky-500"
/> />
</Link> </div>
</div>
</div>
<div className="flex justify-between items-center pr-1 border border-sky-100 dark:border-neutral-700 rounded-md"> <Link
<div className="flex gap-2 items-center"> href={`/api/v1/archives/${link.collectionId}/${link.id}.pdf`}
<div className="text-white bg-sky-300 dark:bg-sky-600 p-2 rounded-l-md"> target="_blank"
<FontAwesomeIcon icon={faFilePdf} className="w-6 h-6" /> className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md"
>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="w-5 h-5 text-sky-500 dark:text-sky-500"
/>
</Link>
</div> </div>
<p className="text-black dark:text-white">PDF</p>
</div> </div>
) : undefined}
<div className="flex text-black dark:text-white gap-1">
<div
onClick={() => handleDownload("pdf")}
className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md"
>
<FontAwesomeIcon
icon={faCloudArrowDown}
className="w-5 h-5 cursor-pointer text-sky-500 dark:text-sky-500"
/>
</div>
<Link
href={`/api/v1/archives/${link.collectionId}/${link.id}.pdf`}
target="_blank"
className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md"
>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="w-5 h-5 text-sky-500 dark:text-sky-500"
/>
</Link>
</div>
</div>
<div className="flex justify-between items-center pr-1 border border-sky-100 dark:border-neutral-700 rounded-md"> <div className="flex justify-between items-center pr-1 border border-sky-100 dark:border-neutral-700 rounded-md">
<div className="flex gap-2 items-center"> <div className="flex gap-2 items-center">

View File

@ -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?.archiveAsWaybackMachine) sendToWayback(url);
if (user?.archiveAsPDF || user?.archiveAsScreenshot) { if (user?.archiveAsPDF || user?.archiveAsScreenshot) {
@ -41,7 +51,7 @@ export default async function archive(
fullPage: true, fullPage: true,
}); });
createFile({ await createFile({
data: screenshot, data: screenshot,
filePath: `archives/${linkExists.collectionId}/${linkId}.png`, filePath: `archives/${linkExists.collectionId}/${linkId}.png`,
}); });
@ -55,11 +65,25 @@ export default async function archive(
margin: { top: "15px", bottom: "15px" }, margin: { top: "15px", bottom: "15px" },
}); });
createFile({ await createFile({
data: pdf, data: pdf,
filePath: `archives/${linkExists.collectionId}/${linkId}.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(); await browser.close();

View File

@ -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") {}
}

View File

@ -5,7 +5,7 @@ type OptionalExcluding<T, TRequired extends keyof T> = Partial<T> &
Pick<T, TRequired>; Pick<T, TRequired>;
export interface LinkIncludingShortenedCollectionAndTags export interface LinkIncludingShortenedCollectionAndTags
extends Omit<Link, "id" | "createdAt" | "collectionId"> { extends Omit<Link, "id" | "createdAt" | "collectionId" | "updatedAt"> {
id?: number; id?: number;
createdAt?: string; createdAt?: string;
collectionId?: number; collectionId?: number;