many bug fixes and improvements

This commit is contained in:
daniel31x13 2023-12-19 17:20:09 -05:00
parent b65787358f
commit 55c43d6f9e
15 changed files with 313 additions and 141 deletions

View File

@ -16,6 +16,7 @@ NEXT_PUBLIC_CREDENTIALS_ENABLED=
DISABLE_NEW_SSO_USERS= DISABLE_NEW_SSO_USERS=
RE_ARCHIVE_LIMIT= RE_ARCHIVE_LIMIT=
NEXT_PUBLIC_MAX_FILE_SIZE= NEXT_PUBLIC_MAX_FILE_SIZE=
MAX_LINKS_PER_USER=
# AWS S3 Settings # AWS S3 Settings
SPACES_KEY= SPACES_KEY=

View File

@ -15,7 +15,7 @@ type Props = {
link: LinkIncludingShortenedCollectionAndTags; link: LinkIncludingShortenedCollectionAndTags;
collection: CollectionIncludingMembersAndLinkCount; collection: CollectionIncludingMembersAndLinkCount;
position?: string; position?: string;
} };
export default function LinkActions({ link, collection, position }: Props) { export default function LinkActions({ link, collection, position }: Props) {
const permissions = usePermissions(link.collection.id as number); const permissions = usePermissions(link.collection.id as number);
@ -23,7 +23,6 @@ export default function LinkActions({ link, collection, position }: Props) {
const [editLinkModal, setEditLinkModal] = useState(false); const [editLinkModal, setEditLinkModal] = useState(false);
const [deleteLinkModal, setDeleteLinkModal] = useState(false); const [deleteLinkModal, setDeleteLinkModal] = useState(false);
const [preservedFormatsModal, setPreservedFormatsModal] = useState(false); const [preservedFormatsModal, setPreservedFormatsModal] = useState(false);
const [expandedLink, setExpandedLink] = useState(false);
const { account } = useAccountStore(); const { account } = useAccountStore();
@ -42,7 +41,7 @@ export default function LinkActions({ link, collection, position }: Props) {
toast.dismiss(load); toast.dismiss(load);
response.ok && response.ok &&
toast.success(`Link ${isAlreadyPinned ? "Unpinned!" : "Pinned!"}`); toast.success(`Link ${isAlreadyPinned ? "Unpinned!" : "Pinned!"}`);
}; };
const deleteLink = async () => { const deleteLink = async () => {
@ -57,85 +56,82 @@ export default function LinkActions({ link, collection, position }: Props) {
return ( return (
<div> <div>
{permissions === true || <div
permissions?.canUpdate || className={`dropdown dropdown-left absolute ${
permissions?.canDelete ? ( position || "top-3 right-3"
} z-20`}
>
<div <div
className={`dropdown dropdown-left absolute ${ tabIndex={0}
position || "top-3 right-3" role="button"
} z-20`} className="btn btn-ghost btn-sm btn-square text-neutral"
> >
<div <i
tabIndex={0} id={"expand-dropdown" + collection.id}
role="button" title="More"
className="btn btn-ghost btn-sm btn-square text-neutral" className="bi-three-dots text-xl"
> />
<i id={"expand-dropdown" + collection.id} title="More" className="bi-three-dots text-xl"/>
</div>
<ul
className="dropdown-content z-[20] menu shadow bg-base-200 border border-neutral-content rounded-box w-44 mr-1">
{permissions === true ? (
<li>
<div
role="button"
tabIndex={0}
onClick={() => {
(document?.activeElement as HTMLElement)?.blur();
pinLink();
}}
>
{link?.pinnedBy && link.pinnedBy[0]
? "Unpin"
: "Pin to Dashboard"}
</div>
</li>
) : undefined}
{permissions === true || permissions?.canUpdate ? (
<li>
<div
role="button"
tabIndex={0}
onClick={() => {
(document?.activeElement as HTMLElement)?.blur();
setEditLinkModal(true);
}}
>
Edit
</div>
</li>
) : undefined}
{permissions === true ? (
<li>
<div
role="button"
tabIndex={0}
onClick={() => {
(document?.activeElement as HTMLElement)?.blur();
setPreservedFormatsModal(true);
// updateArchive();
}}
>
Preserved Formats
</div>
</li>
) : undefined}
{permissions === true || permissions?.canDelete ? (
<li>
<div
role="button"
tabIndex={0}
onClick={(e) => {
(document?.activeElement as HTMLElement)?.blur();
e.shiftKey ? deleteLink() : setDeleteLinkModal(true);
}}
>
Delete
</div>
</li>
) : undefined}
</ul>
</div> </div>
) : undefined} <ul className="dropdown-content z-[20] menu shadow bg-base-200 border border-neutral-content rounded-box w-44 mr-1">
{permissions === true ? (
<li>
<div
role="button"
tabIndex={0}
onClick={() => {
(document?.activeElement as HTMLElement)?.blur();
pinLink();
}}
>
{link?.pinnedBy && link.pinnedBy[0]
? "Unpin"
: "Pin to Dashboard"}
</div>
</li>
) : undefined}
{permissions === true || permissions?.canUpdate ? (
<li>
<div
role="button"
tabIndex={0}
onClick={() => {
(document?.activeElement as HTMLElement)?.blur();
setEditLinkModal(true);
}}
>
Edit
</div>
</li>
) : undefined}
<li>
<div
role="button"
tabIndex={0}
onClick={() => {
(document?.activeElement as HTMLElement)?.blur();
setPreservedFormatsModal(true);
// updateArchive();
}}
>
Preserved Formats
</div>
</li>
{permissions === true || permissions?.canDelete ? (
<li>
<div
role="button"
tabIndex={0}
onClick={(e) => {
(document?.activeElement as HTMLElement)?.blur();
e.shiftKey ? deleteLink() : setDeleteLinkModal(true);
}}
>
Delete
</div>
</li>
) : undefined}
</ul>
</div>
{editLinkModal ? ( {editLinkModal ? (
<EditLinkModal <EditLinkModal

View File

@ -34,6 +34,8 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
const router = useRouter(); const router = useRouter();
let isPublic = router.pathname.startsWith("/public") ? true : undefined;
const [collectionOwner, setCollectionOwner] = useState({ const [collectionOwner, setCollectionOwner] = useState({
id: null as unknown as number, id: null as unknown as number,
name: "", name: "",
@ -78,12 +80,8 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
}; };
useEffect(() => { useEffect(() => {
let isPublicRoute = router.pathname.startsWith("/public")
? true
: undefined;
(async () => { (async () => {
const data = await getLink(link.id as number, isPublicRoute); const data = await getLink(link.id as number, isPublic);
setLink( setLink(
(data as any).response as LinkIncludingShortenedCollectionAndTags (data as any).response as LinkIncludingShortenedCollectionAndTags
); );
@ -93,7 +91,7 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
if (!isReady()) { if (!isReady()) {
interval = setInterval(async () => { interval = setInterval(async () => {
const data = await getLink(link.id as number, isPublicRoute); const data = await getLink(link.id as number, isPublic);
setLink( setLink(
(data as any).response as LinkIncludingShortenedCollectionAndTags (data as any).response as LinkIncludingShortenedCollectionAndTags
); );
@ -123,8 +121,11 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
toast.dismiss(load); toast.dismiss(load);
if (response.ok) { if (response.ok) {
const newLink = await getLink(link?.id as number);
setLink(
(newLink as any).response as LinkIncludingShortenedCollectionAndTags
);
toast.success(`Link is being archived...`); toast.success(`Link is being archived...`);
await getLink(link?.id as number);
} else toast.error(data.response); } else toast.error(data.response);
}; };
@ -148,20 +149,15 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
<div className={`flex flex-col gap-3`}> <div className={`flex flex-col gap-3`}>
{isReady() ? ( {isReady() ? (
<> <>
{readabilityAvailable(link) ? (
<PreservedFormatRow
name={"Readable"}
icon={"bi-file-earmark-text"}
format={ArchivedFormat.readability}
activeLink={link}
/>
) : undefined}
{screenshotAvailable(link) ? ( {screenshotAvailable(link) ? (
<PreservedFormatRow <PreservedFormatRow
name={"Screenshot"} name={"Screenshot"}
icon={"bi-file-earmark-image"} icon={"bi-file-earmark-image"}
format={ArchivedFormat.png} format={
link?.screenshotPath?.endsWith("png")
? ArchivedFormat.png
: ArchivedFormat.jpeg
}
activeLink={link} activeLink={link}
downloadable={true} downloadable={true}
/> />
@ -176,6 +172,15 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
downloadable={true} downloadable={true}
/> />
) : undefined} ) : undefined}
{readabilityAvailable(link) ? (
<PreservedFormatRow
name={"Readable"}
icon={"bi-file-earmark-text"}
format={ArchivedFormat.readability}
activeLink={link}
/>
) : undefined}
</> </>
) : ( ) : (
<div <div
@ -183,7 +188,7 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
> >
<i className="bi-stack drop-shadow text-primary text-8xl mx-auto mb-5"></i> <i className="bi-stack drop-shadow text-primary text-8xl mx-auto mb-5"></i>
<p className="text-center text-2xl"> <p className="text-center text-2xl">
The Link preservation is in the queue Link preservation is in the queue
</p> </p>
<p className="text-center text-lg"> <p className="text-center text-lg">
Please check back later to see the result Please check back later to see the result

View File

@ -32,13 +32,11 @@ export default function PreservedFormatRow({
const router = useRouter(); const router = useRouter();
useEffect(() => { let isPublic = router.pathname.startsWith("/public") ? true : undefined;
let isPublicRoute = router.pathname.startsWith("/public")
? true
: undefined;
useEffect(() => {
(async () => { (async () => {
const data = await getLink(link.id as number, isPublicRoute); const data = await getLink(link.id as number, isPublic);
setLink( setLink(
(data as any).response as LinkIncludingShortenedCollectionAndTags (data as any).response as LinkIncludingShortenedCollectionAndTags
); );
@ -47,7 +45,7 @@ export default function PreservedFormatRow({
let interval: any; let interval: any;
if (link?.screenshotPath === "pending" || link?.pdfPath === "pending") { if (link?.screenshotPath === "pending" || link?.pdfPath === "pending") {
interval = setInterval(async () => { interval = setInterval(async () => {
const data = await getLink(link.id as number, isPublicRoute); const data = await getLink(link.id as number, isPublic);
setLink( setLink(
(data as any).response as LinkIncludingShortenedCollectionAndTags (data as any).response as LinkIncludingShortenedCollectionAndTags
); );
@ -65,23 +63,6 @@ export default function PreservedFormatRow({
}; };
}, [link?.screenshotPath, link?.pdfPath, link?.readabilityPath]); }, [link?.screenshotPath, link?.pdfPath, link?.readabilityPath]);
const updateArchive = async () => {
const load = toast.loading("Sending request...");
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...`);
getLink(link?.id as number);
} else toast.error(data.response);
};
const handleDownload = () => { const handleDownload = () => {
const path = `/api/v1/archives/${link?.id}?format=${format}`; const path = `/api/v1/archives/${link?.id}?format=${format}`;
fetch(path) fetch(path)
@ -121,7 +102,9 @@ export default function PreservedFormatRow({
) : undefined} ) : undefined}
<Link <Link
href={`/preserved/${link?.id}?format=${format}`} href={`${isPublic ? "/public" : ""}/preserved/${
link?.id
}?format=${format}`}
target="_blank" target="_blank"
className="btn btn-sm btn-square" className="btn btn-sm btn-square"
> >

View File

@ -4,6 +4,8 @@ import isValidUrl from "@/lib/shared/isValidUrl";
import unescapeString from "@/lib/client/unescapeString"; import unescapeString from "@/lib/client/unescapeString";
import { TagIncludingLinkCount } from "@/types/global"; import { TagIncludingLinkCount } from "@/types/global";
import Link from "next/link"; import Link from "next/link";
import { useState } from "react";
import PreservedFormatsModal from "../ModalContent/PreservedFormatsModal";
interface LinksIncludingTags extends LinkType { interface LinksIncludingTags extends LinkType {
tags: TagIncludingLinkCount[]; tags: TagIncludingLinkCount[];
@ -25,6 +27,8 @@ export default function LinkCard({ link, count }: Props) {
day: "numeric", day: "numeric",
}); });
const [preservedFormatsModal, setPreservedFormatsModal] = useState(false);
return ( return (
<div className="border border-solid border-neutral-content bg-base-200 shadow hover:shadow-none duration-100 rounded-lg p-3 flex items-start relative gap-3 group/item"> <div className="border border-solid border-neutral-content bg-base-200 shadow hover:shadow-none duration-100 rounded-lg p-3 flex items-start relative gap-3 group/item">
<div className="flex justify-between items-end gap-5 w-full h-full z-0"> <div className="flex justify-between items-end gap-5 w-full h-full z-0">
@ -77,15 +81,52 @@ export default function LinkCard({ link, count }: Props) {
<div className="w-full"> <div className="w-full">
{unescapeString(link.description)}{" "} {unescapeString(link.description)}{" "}
<Link <Link
href={`/public/links/${link.id}`} href={link.url || ""}
target="_blank"
className="flex gap-1 items-center flex-wrap text-sm text-neutral hover:opacity-50 duration-100 min-w-fit float-right mt-1 ml-2" className="flex gap-1 items-center flex-wrap text-sm text-neutral hover:opacity-50 duration-100 min-w-fit float-right mt-1 ml-2"
> >
<p>Read</p> <p>Visit</p>
<i className={"bi-chevron-right"}></i> <i className={"bi-chevron-right"}></i>
</Link> </Link>
</div> </div>
</div> </div>
</div> </div>
<div
className={`dropdown dropdown-left absolute ${"top-3 right-3"} z-20`}
>
<div
tabIndex={0}
role="button"
className="btn btn-ghost btn-sm btn-square text-neutral"
>
<i
id={"expand-dropdown" + link.id}
title="More"
className="bi-three-dots text-xl"
/>
</div>
<ul className="dropdown-content z-[20] menu shadow bg-base-200 border border-neutral-content rounded-box w-44 mr-1">
<li>
<div
role="button"
tabIndex={0}
onClick={() => {
(document?.activeElement as HTMLElement)?.blur();
setPreservedFormatsModal(true);
// updateArchive();
}}
>
Preserved Formats
</div>
</li>
</ul>
</div>
{preservedFormatsModal ? (
<PreservedFormatsModal
onClose={() => setPreservedFormatsModal(false)}
activeLink={link as any}
/>
) : undefined}
</div> </div>
); );
} }

View File

@ -7,6 +7,7 @@ import { JSDOM } from "jsdom";
import DOMPurify from "dompurify"; import DOMPurify from "dompurify";
import { Collection, Link, User } from "@prisma/client"; import { Collection, Link, User } from "@prisma/client";
import validateUrlSize from "./validateUrlSize"; import validateUrlSize from "./validateUrlSize";
import removeFile from "./storage/removeFile";
type LinksAndCollectionAndOwner = Link & { type LinksAndCollectionAndOwner = Link & {
collection: Collection & { collection: Collection & {
@ -74,7 +75,7 @@ export default async function archiveHandler(link: LinksAndCollectionAndOwner) {
const content = await page.content(); const content = await page.content();
// TODO Webarchive // TODO single file
// const session = await page.context().newCDPSession(page); // const session = await page.context().newCDPSession(page);
// const doc = await session.send("Page.captureSnapshot", { // const doc = await session.send("Page.captureSnapshot", {
// format: "mhtml", // format: "mhtml",
@ -189,6 +190,13 @@ export default async function archiveHandler(link: LinksAndCollectionAndOwner) {
: undefined, : undefined,
}, },
}); });
else {
removeFile({ filePath: `archives/${link.collectionId}/${link.id}.png` });
removeFile({ filePath: `archives/${link.collectionId}/${link.id}.pdf` });
removeFile({
filePath: `archives/${link.collectionId}/${link.id}_readability.json`,
});
}
await browser.close(); await browser.close();
} }

View File

@ -6,6 +6,8 @@ import getPermission from "@/lib/api/getPermission";
import createFolder from "@/lib/api/storage/createFolder"; import createFolder from "@/lib/api/storage/createFolder";
import validateUrlSize from "../../validateUrlSize"; import validateUrlSize from "../../validateUrlSize";
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
export default async function postLink( export default async function postLink(
link: LinkIncludingShortenedCollectionAndTags, link: LinkIncludingShortenedCollectionAndTags,
userId: number userId: number
@ -24,6 +26,20 @@ export default async function postLink(
link.collection.name = "Unorganized"; link.collection.name = "Unorganized";
} }
const numberOfLinksTheUserHas = await prisma.link.count({
where: {
collection: {
ownerId: userId,
},
},
});
if (numberOfLinksTheUserHas + 1 > MAX_LINKS_PER_USER)
return {
response: `Error: Each user can only have a maximum of ${MAX_LINKS_PER_USER} Links.`,
status: 400,
};
link.collection.name = link.collection.name.trim(); link.collection.name = link.collection.name.trim();
if (link.collection.id) { if (link.collection.id) {

View File

@ -1,8 +1,9 @@
import { prisma } from "@/lib/api/db"; import { prisma } from "@/lib/api/db";
import { Backup } from "@/types/global";
import createFolder from "@/lib/api/storage/createFolder"; import createFolder from "@/lib/api/storage/createFolder";
import { JSDOM } from "jsdom"; import { JSDOM } from "jsdom";
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
export default async function importFromHTMLFile( export default async function importFromHTMLFile(
userId: number, userId: number,
rawData: string rawData: string
@ -10,6 +11,23 @@ export default async function importFromHTMLFile(
const dom = new JSDOM(rawData); const dom = new JSDOM(rawData);
const document = dom.window.document; const document = dom.window.document;
const bookmarks = document.querySelectorAll("A");
const totalImports = bookmarks.length;
const numberOfLinksTheUserHas = await prisma.link.count({
where: {
collection: {
ownerId: userId,
},
},
});
if (totalImports + numberOfLinksTheUserHas > MAX_LINKS_PER_USER)
return {
response: `Error: Each user can only have a maximum of ${MAX_LINKS_PER_USER} Links.`,
status: 400,
};
const folders = document.querySelectorAll("H3"); const folders = document.querySelectorAll("H3");
await prisma await prisma

View File

@ -2,9 +2,34 @@ import { prisma } from "@/lib/api/db";
import { Backup } from "@/types/global"; import { Backup } from "@/types/global";
import createFolder from "@/lib/api/storage/createFolder"; import createFolder from "@/lib/api/storage/createFolder";
export default async function getData(userId: number, rawData: string) { const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
export default async function importFromLinkwarden(
userId: number,
rawData: string
) {
const data: Backup = JSON.parse(rawData); const data: Backup = JSON.parse(rawData);
let totalImports = 0;
data.collections.forEach((collection) => {
totalImports += collection.links.length;
});
const numberOfLinksTheUserHas = await prisma.link.count({
where: {
collection: {
ownerId: userId,
},
},
});
if (totalImports + numberOfLinksTheUserHas > MAX_LINKS_PER_USER)
return {
response: `Error: Each user can only have a maximum of ${MAX_LINKS_PER_USER} Links.`,
status: 400,
};
await prisma await prisma
.$transaction( .$transaction(
async () => { async () => {

View File

@ -75,7 +75,7 @@ export default async function getPublicUser(
username: lessSensitiveInfo.username, username: lessSensitiveInfo.username,
image: lessSensitiveInfo.image, image: lessSensitiveInfo.image,
archiveAsScreenshot: lessSensitiveInfo.archiveAsScreenshot, archiveAsScreenshot: lessSensitiveInfo.archiveAsScreenshot,
archiveAsPdf: lessSensitiveInfo.archiveAsPDF, archiveAsPDF: lessSensitiveInfo.archiveAsPDF,
}; };
return { response: data, status: 200 }; return { response: data, status: 200 };

View File

@ -46,7 +46,14 @@ export default function Index() {
<img <img
alt="" alt=""
src={`/api/v1/archives/${link.id}?format=${ArchivedFormat.png}`} src={`/api/v1/archives/${link.id}?format=${ArchivedFormat.png}`}
className="object-contain w-full h-screen" className="w-fit mx-auto"
/>
)}
{link && Number(router.query.format) === ArchivedFormat.jpeg && (
<img
alt=""
src={`/api/v1/archives/${link.id}?format=${ArchivedFormat.jpeg}`}
className="w-fit mx-auto"
/> />
)} )}
</div> </div>

View File

@ -96,11 +96,11 @@ export default function PublicCollections() {
return collection ? ( return collection ? (
<div <div
className="h-screen" className="h-96"
style={{ style={{
backgroundImage: `linear-gradient(${collection?.color}30 10%, ${ backgroundImage: `linear-gradient(${collection?.color}30 10%, ${
settings.theme === "dark" ? "#262626" : "#f3f4f6" settings.theme === "dark" ? "#262626" : "#f3f4f6"
} 18rem, ${settings.theme === "dark" ? "#171717" : "#ffffff"} 100%)`, } 13rem, ${settings.theme === "dark" ? "#171717" : "#ffffff"} 100%)`,
}} }}
> >
{collection ? ( {collection ? (
@ -208,6 +208,11 @@ export default function PublicCollections() {
{links {links
?.filter((e) => e.collectionId === Number(router.query.id)) ?.filter((e) => e.collectionId === Number(router.query.id))
.map((e, i) => { .map((e, i) => {
const linkWithCollectionData = {
...e,
collection: collection, // Append collection data
};
return ( return (
<motion.div <motion.div
key={i} key={i}
@ -216,7 +221,10 @@ export default function PublicCollections() {
viewport={{ once: true, amount: 0.8 }} viewport={{ once: true, amount: 0.8 }}
> >
<motion.div variants={cardVariants}> <motion.div variants={cardVariants}>
<PublicLinkCard link={e as any} count={i} /> <PublicLinkCard
link={linkWithCollectionData as any}
count={i}
/>
</motion.div> </motion.div>
</motion.div> </motion.div>
); );

View File

@ -0,0 +1,63 @@
import React, { useEffect, useState } from "react";
import useLinkStore from "@/store/links";
import { useRouter } from "next/router";
import {
ArchivedFormat,
LinkIncludingShortenedCollectionAndTags,
} from "@/types/global";
import ReadableView from "@/components/ReadableView";
export default function Index() {
const { links, getLink } = useLinkStore();
const [link, setLink] = useState<LinkIncludingShortenedCollectionAndTags>();
const router = useRouter();
let isPublic = router.pathname.startsWith("/public") ? true : false;
useEffect(() => {
const fetchLink = async () => {
if (router.query.id) {
await getLink(Number(router.query.id), isPublic);
}
};
fetchLink();
}, []);
useEffect(() => {
if (links[0]) setLink(links.find((e) => e.id === Number(router.query.id)));
}, [links]);
return (
<div className="relative">
{/* <div className="fixed left-1/2 transform -translate-x-1/2 w-fit py-1 px-3 bg-base-200 border border-neutral-content rounded-md">
Readable
</div> */}
{link && Number(router.query.format) === ArchivedFormat.readability && (
<ReadableView link={link} />
)}
{link && Number(router.query.format) === ArchivedFormat.pdf && (
<iframe
src={`/api/v1/archives/${link.id}?format=${ArchivedFormat.pdf}`}
className="w-full h-screen border-none"
></iframe>
)}
{link && Number(router.query.format) === ArchivedFormat.png && (
<img
alt=""
src={`/api/v1/archives/${link.id}?format=${ArchivedFormat.png}`}
className="w-fit mx-auto"
/>
)}
{link && Number(router.query.format) === ArchivedFormat.jpeg && (
<img
alt=""
src={`/api/v1/archives/${link.id}?format=${ArchivedFormat.jpeg}`}
className="w-fit mx-auto"
/>
)}
</div>
);
}

View File

@ -10,7 +10,6 @@ import SubmitButton from "@/components/SubmitButton";
import React from "react"; import React from "react";
import { MigrationFormat, MigrationRequest } from "@/types/global"; import { MigrationFormat, MigrationRequest } from "@/types/global";
import Link from "next/link"; import Link from "next/link";
import ClickAwayHandler from "@/components/ClickAwayHandler";
import Checkbox from "@/components/Checkbox"; import Checkbox from "@/components/Checkbox";
export default function Account() { export default function Account() {
@ -85,9 +84,9 @@ export default function Account() {
setSubmitLoader(false); setSubmitLoader(false);
}; };
const [importDropdown, setImportDropdown] = useState(false);
const importBookmarks = async (e: any, format: MigrationFormat) => { const importBookmarks = async (e: any, format: MigrationFormat) => {
setSubmitLoader(true);
const file: File = e.target.files[0]; const file: File = e.target.files[0];
if (file) { if (file) {
@ -112,18 +111,19 @@ export default function Account() {
toast.dismiss(load); toast.dismiss(load);
toast.success("Imported the Bookmarks! Reloading the page..."); if (response.ok) {
toast.success("Imported the Bookmarks! Reloading the page...");
setImportDropdown(false); setTimeout(() => {
location.reload();
setTimeout(() => { }, 2000);
location.reload(); } else toast.error(data.response as string);
}, 2000);
}; };
reader.onerror = function (e) { reader.onerror = function (e) {
console.log("Error:", e); console.log("Error:", e);
}; };
} }
setSubmitLoader(false);
}; };
const [whitelistedUsersTextbox, setWhiteListedUsersTextbox] = useState(""); const [whitelistedUsersTextbox, setWhiteListedUsersTextbox] = useState("");

View File

@ -10,6 +10,7 @@ declare global {
AUTOSCROLL_TIMEOUT?: string; AUTOSCROLL_TIMEOUT?: string;
RE_ARCHIVE_LIMIT?: string; RE_ARCHIVE_LIMIT?: string;
NEXT_PUBLIC_MAX_FILE_SIZE?: string; NEXT_PUBLIC_MAX_FILE_SIZE?: string;
MAX_LINKS_PER_USER?: string;
SPACES_KEY?: string; SPACES_KEY?: string;
SPACES_SECRET?: string; SPACES_SECRET?: string;