diff --git a/components/Modal/Collection/DeleteCollection.tsx b/components/Modal/Collection/DeleteCollection.tsx
index 58941d7..0af00b2 100644
--- a/components/Modal/Collection/DeleteCollection.tsx
+++ b/components/Modal/Collection/DeleteCollection.tsx
@@ -82,7 +82,7 @@ export default function DeleteCollection({
-
+
To confirm, type "
{collection.name}
" in the box below:
diff --git a/components/Modal/Link/AddOrEditLink.tsx b/components/Modal/Link/AddOrEditLink.tsx
index 7b72a20..942f92a 100644
--- a/components/Modal/Link/AddOrEditLink.tsx
+++ b/components/Modal/Link/AddOrEditLink.tsx
@@ -7,8 +7,8 @@ import useLinkStore from "@/store/links";
import { faPlus } from "@fortawesome/free-solid-svg-icons";
import RequiredBadge from "../../RequiredBadge";
import { useSession } from "next-auth/react";
-// import useCollectionStore from "@/store/collections";
-// import { useRouter } from "next/router";
+import useCollectionStore from "@/store/collections";
+import { useRouter } from "next/router";
import SubmitButton from "../../SubmitButton";
import { toast } from "react-hot-toast";
import Link from "next/link";
@@ -55,27 +55,40 @@ export default function AddOrEditLink({
const { updateLink, addLink } = useLinkStore();
- // const router = useRouter();
+ const router = useRouter();
+ const { collections } = useCollectionStore();
- // const { collections } = useCollectionStore();
+ useEffect(() => {
+ if (method === "CREATE") {
+ if (router.query.id) {
+ const currentCollection = collections.find(
+ (e) => e.id == Number(router.query.id)
+ );
- // useEffect(() => {
- // if (router.query.id) {
- // const currentCollection = collections.find(
- // (e) => e.id == Number(router.query.id)
- // );
-
- // if (currentCollection && currentCollection.ownerId)
- // setLink({
- // ...link,
- // collection: {
- // id: currentCollection.id,
- // name: currentCollection.name,
- // ownerId: currentCollection.ownerId,
- // },
- // });
- // }
- // }, []);
+ if (
+ currentCollection &&
+ currentCollection.ownerId &&
+ router.asPath.startsWith("/collections/")
+ )
+ setLink({
+ ...link,
+ collection: {
+ id: currentCollection.id,
+ name: currentCollection.name,
+ ownerId: currentCollection.ownerId,
+ },
+ });
+ } else
+ setLink({
+ ...link,
+ collection: {
+ // id: ,
+ name: "Unorganized",
+ ownerId: data?.user.id as number,
+ },
+ });
+ }
+ }, []);
const setTags = (e: any) => {
const tagNames = e.map((e: any) => {
@@ -147,27 +160,29 @@ export default function AddOrEditLink({
Collection
-
+ {link.collection.name ? (
+
+ ) : null}
- ) : null}
+ ) : undefined}
{optionsExpanded ? (
@@ -187,20 +202,22 @@ export default function AddOrEditLink({
Collection
-
+ {link.collection.name ? (
+
+ ) : undefined}
) : undefined}
diff --git a/components/Modal/User/PrivacySettings.tsx b/components/Modal/User/PrivacySettings.tsx
index 44188d3..b068363 100644
--- a/components/Modal/User/PrivacySettings.tsx
+++ b/components/Modal/User/PrivacySettings.tsx
@@ -50,7 +50,7 @@ export default function PrivacySettings({
return wordsArray;
};
- const postJSONFile = async (e: any) => {
+ const postBookmarkFile = async (e: any) => {
const file: File = e.target.files[0];
if (file) {
@@ -156,9 +156,7 @@ export default function PrivacySettings({
-
- Import/Export Data
-
+
Import Data
-
+ {/* Commented out for now. */}
+ {/*
Export Data
-
+ */}
diff --git a/hooks/useDetectPageBottom.tsx b/hooks/useDetectPageBottom.tsx
index 518620e..c383f08 100644
--- a/hooks/useDetectPageBottom.tsx
+++ b/hooks/useDetectPageBottom.tsx
@@ -5,21 +5,22 @@ const useDetectPageBottom = () => {
useEffect(() => {
const handleScroll = () => {
- const offsetHeight = document.documentElement.offsetHeight;
- const innerHeight = window.innerHeight;
- const scrollTop = document.documentElement.scrollTop;
+ const totalHeight = document.documentElement.scrollHeight;
+ const scrolledHeight = window.scrollY + window.innerHeight;
- const hasReachedBottom = offsetHeight - (innerHeight + scrollTop) <= 100;
-
- setReachedBottom(hasReachedBottom);
+ if (scrolledHeight >= totalHeight) {
+ setReachedBottom(true);
+ }
};
window.addEventListener("scroll", handleScroll);
- return () => window.removeEventListener("scroll", handleScroll);
+ return () => {
+ window.removeEventListener("scroll", handleScroll);
+ };
}, []);
- return reachedBottom;
+ return { reachedBottom, setReachedBottom };
};
export default useDetectPageBottom;
diff --git a/hooks/useLinks.tsx b/hooks/useLinks.tsx
index 1d4ebf6..25d65b2 100644
--- a/hooks/useLinks.tsx
+++ b/hooks/useLinks.tsx
@@ -17,7 +17,7 @@ export default function useLinks(
const { links, setLinks, resetLinks } = useLinkStore();
const router = useRouter();
- const hasReachedBottom = useDetectPageBottom();
+ const { reachedBottom, setReachedBottom } = useDetectPageBottom();
const getLinks = async (isInitialCall: boolean, cursor?: number) => {
const requestBody: LinkRequestQuery = {
@@ -48,6 +48,8 @@ export default function useLinks(
}, [router, sort, searchFilter]);
useEffect(() => {
- if (hasReachedBottom) getLinks(false, links?.at(-1)?.id);
- }, [hasReachedBottom]);
+ if (reachedBottom) getLinks(false, links?.at(-1)?.id);
+
+ setReachedBottom(false);
+ }, [reachedBottom]);
}
diff --git a/lib/api/controllers/links/updateLink.ts b/lib/api/controllers/links/updateLink.ts
index 87954e1..13a9c53 100644
--- a/lib/api/controllers/links/updateLink.ts
+++ b/lib/api/controllers/links/updateLink.ts
@@ -8,6 +8,7 @@ export default async function updateLink(
link: LinkIncludingShortenedCollectionAndTags,
userId: number
) {
+ console.log(link);
if (!link || !link.collection.id)
return {
response: "Please choose a valid link and collection.",
diff --git a/lib/api/controllers/migration/getData.ts b/lib/api/controllers/migration/exportData.ts
similarity index 88%
rename from lib/api/controllers/migration/getData.ts
rename to lib/api/controllers/migration/exportData.ts
index 6b9e2b0..4d711f7 100644
--- a/lib/api/controllers/migration/getData.ts
+++ b/lib/api/controllers/migration/exportData.ts
@@ -1,6 +1,6 @@
import { prisma } from "@/lib/api/db";
-export default async function getData(userId: number) {
+export default async function exportData(userId: number) {
const user = await prisma.user.findUnique({
where: { id: userId },
include: {
diff --git a/lib/api/controllers/migration/importData.ts b/lib/api/controllers/migration/importData.ts
new file mode 100644
index 0000000..c7bc33e
--- /dev/null
+++ b/lib/api/controllers/migration/importData.ts
@@ -0,0 +1,97 @@
+import { prisma } from "@/lib/api/db";
+import { Backup } from "@/types/global";
+import createFolder from "@/lib/api/storage/createFolder";
+import { JSDOM } from "jsdom";
+
+export default async function importData(userId: number, rawData: string) {
+ try {
+ const dom = new JSDOM(rawData);
+ const document = dom.window.document;
+
+ const folders = document.querySelectorAll("H3");
+
+ // @ts-ignore
+ for (const folder of folders) {
+ const findCollection = await prisma.user.findUnique({
+ where: {
+ id: userId,
+ },
+ select: {
+ collections: {
+ where: {
+ name: folder.textContent.trim(),
+ },
+ },
+ },
+ });
+
+ const checkIfCollectionExists = findCollection?.collections[0];
+
+ let collectionId = findCollection?.collections[0]?.id;
+
+ if (!checkIfCollectionExists || !collectionId) {
+ const newCollection = await prisma.collection.create({
+ data: {
+ name: folder.textContent.trim(),
+ description: "",
+ color: "#0ea5e9",
+ isPublic: false,
+ ownerId: userId,
+ },
+ });
+
+ createFolder({ filePath: `archives/${newCollection.id}` });
+
+ collectionId = newCollection.id;
+ }
+
+ createFolder({ filePath: `archives/${collectionId}` });
+
+ const bookmarks = folder.nextElementSibling.querySelectorAll("A");
+ for (const bookmark of bookmarks) {
+ await prisma.link.create({
+ data: {
+ name: bookmark.textContent.trim(),
+ url: bookmark.getAttribute("HREF"),
+ tags: bookmark.getAttribute("TAGS")
+ ? {
+ connectOrCreate: bookmark
+ .getAttribute("TAGS")
+ .split(",")
+ .map((tag: string) =>
+ tag
+ ? {
+ where: {
+ name_ownerId: {
+ name: tag.trim(),
+ ownerId: userId,
+ },
+ },
+ create: {
+ name: tag.trim(),
+ owner: {
+ connect: {
+ id: userId,
+ },
+ },
+ },
+ }
+ : undefined
+ ),
+ }
+ : undefined,
+ description: bookmark.getAttribute("DESCRIPTION")
+ ? bookmark.getAttribute("DESCRIPTION")
+ : "",
+ collectionId: collectionId,
+ createdAt: new Date(),
+ },
+ });
+ }
+ }
+ } catch (err) {
+ console.log(err);
+ }
+
+ return { response: "Success.", status: 200 };
+}
diff --git a/lib/api/controllers/migration/postData.ts b/lib/api/controllers/migration/postData.ts
deleted file mode 100644
index 2082e4c..0000000
--- a/lib/api/controllers/migration/postData.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import { prisma } from "@/lib/api/db";
-import { Backup } from "@/types/global";
-import createFolder from "@/lib/api/storage/createFolder";
-
-export default async function getData(userId: number, rawData: any) {
- const data: Backup = JSON.parse(rawData);
-
- // Import collections
- try {
- data.collections.forEach(async (e) => {
- e.name = e.name.trim();
-
- const findCollection = await prisma.user.findUnique({
- where: {
- id: userId,
- },
- select: {
- collections: {
- where: {
- name: e.name,
- },
- },
- },
- });
-
- const checkIfCollectionExists = findCollection?.collections[0];
-
- let collectionId = findCollection?.collections[0]?.id;
-
- if (!checkIfCollectionExists) {
- const newCollection = await prisma.collection.create({
- data: {
- owner: {
- connect: {
- id: userId,
- },
- },
- name: e.name,
- description: e.description,
- color: e.color,
- },
- });
-
- createFolder({ filePath: `archives/${newCollection.id}` });
-
- collectionId = newCollection.id;
- }
-
- // Import Links
- e.links.forEach(async (e) => {
- const newLink = await prisma.link.create({
- data: {
- url: e.url,
- name: e.name,
- description: e.description,
- collection: {
- connect: {
- id: collectionId,
- },
- },
- tags: {
- connectOrCreate: e.tags.map((tag) => ({
- where: {
- name_ownerId: {
- name: tag.name.trim(),
- ownerId: userId,
- },
- },
- create: {
- name: tag.name.trim(),
- owner: {
- connect: {
- id: userId,
- },
- },
- },
- })),
- },
- },
- });
- });
- });
- } catch (err) {
- console.log(err);
- }
-
- return { response: "Success.", status: 200 };
-}
diff --git a/package.json b/package.json
index 252a02b..9256da6 100644
--- a/package.json
+++ b/package.json
@@ -54,6 +54,7 @@
"devDependencies": {
"@playwright/test": "^1.35.1",
"@types/bcrypt": "^5.0.0",
+ "@types/jsdom": "^21.1.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.26",
"prisma": "^5.1.0",
diff --git a/pages/api/migration/index.ts b/pages/api/migration/index.ts
index 9c15b2b..c082c3d 100644
--- a/pages/api/migration/index.ts
+++ b/pages/api/migration/index.ts
@@ -1,8 +1,8 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "next-auth/next";
import { authOptions } from "@/pages/api/auth/[...nextauth]";
-import getData from "@/lib/api/controllers/migration/getData";
-import postData from "@/lib/api/controllers/migration/postData";
+import exportData from "@/lib/api/controllers/migration/exportData";
+import importData from "@/lib/api/controllers/migration/importData";
export default async function users(req: NextApiRequest, res: NextApiResponse) {
const session = await getServerSession(req, res, authOptions);
@@ -16,7 +16,7 @@ export default async function users(req: NextApiRequest, res: NextApiResponse) {
});
if (req.method === "GET") {
- const data = await getData(session.user.id);
+ const data = await exportData(session.user.id);
if (data.status === 200)
return res
@@ -25,7 +25,7 @@ export default async function users(req: NextApiRequest, res: NextApiResponse) {
.status(data.status)
.json(data.response);
} else if (req.method === "POST") {
- const data = await postData(session.user.id, req.body);
+ const data = await importData(session.user.id, req.body);
return res.status(data.status).json({ response: data.response });
}
}
diff --git a/pages/collections/[id].tsx b/pages/collections/[id].tsx
index cb8ac03..2dd31cb 100644
--- a/pages/collections/[id].tsx
+++ b/pages/collections/[id].tsx
@@ -222,7 +222,7 @@ export default function Index() {
- {links[0] ? (
+ {links.some((e) => e.collectionId === Number(router.query.id)) ? (
{links
.filter((e) => e.collectionId === Number(router.query.id))
diff --git a/yarn.lock b/yarn.lock
index 023809e..71a70f1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1466,6 +1466,15 @@
resolved "https://registry.yarnpkg.com/@types/crypto-js/-/crypto-js-4.1.1.tgz#602859584cecc91894eb23a4892f38cfa927890d"
integrity sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==
+"@types/jsdom@^21.1.3":
+ version "21.1.3"
+ resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-21.1.3.tgz#a88c5dc65703e1b10b2a7839c12db49662b43ff0"
+ integrity sha512-1zzqSP+iHJYV4lB3lZhNBa012pubABkj9yG/GuXuf6LZH1cSPIJBqFDrm5JX65HHt6VOnNYdTui/0ySerRbMgA==
+ dependencies:
+ "@types/node" "*"
+ "@types/tough-cookie" "*"
+ parse5 "^7.0.0"
+
"@types/json5@^0.0.29":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
@@ -1521,6 +1530,11 @@
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
+"@types/tough-cookie@*":
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.3.tgz#3d06b6769518450871fbc40770b7586334bdfd90"
+ integrity sha512-THo502dA5PzG/sfQH+42Lw3fvmYkceefOspdCwpHRul8ik2Jv1K8I5OZz1AT3/rs46kwgMCe9bSBmDLYkkOMGg==
+
"@typescript-eslint/parser@^5.42.0":
version "5.49.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.49.0.tgz#d699734b2f20e16351e117417d34a2bc9d7c4b90"
@@ -3946,7 +3960,7 @@ parse-json@^5.0.0:
json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"
-parse5@^7.1.2:
+parse5@^7.0.0, parse5@^7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32"
integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==