-
-
-
-
-
-
- {children}
-
+
+
+
- >
- );
- else if ((status === "unauthenticated" && !redirect) || !routeExists)
- return <>{children}>;
- else return <>>;
+
+
+
+ {children}
+
+
+ >
+ );
}
diff --git a/layouts/SettingsLayout.tsx b/layouts/SettingsLayout.tsx
new file mode 100644
index 0000000..ae5c08f
--- /dev/null
+++ b/layouts/SettingsLayout.tsx
@@ -0,0 +1,78 @@
+import SettingsSidebar from "@/components/SettingsSidebar";
+import { ReactNode, useEffect, useState } from "react";
+import ModalManagement from "@/components/ModalManagement";
+import useModalStore from "@/store/modals";
+import { useRouter } from "next/router";
+import ClickAwayHandler from "@/components/ClickAwayHandler";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faBars } from "@fortawesome/free-solid-svg-icons";
+
+interface Props {
+ children: ReactNode;
+}
+
+export default function SettingsLayout({ children }: Props) {
+ const { modal } = useModalStore();
+
+ const router = useRouter();
+
+ useEffect(() => {
+ modal
+ ? (document.body.style.overflow = "hidden")
+ : (document.body.style.overflow = "auto");
+ }, [modal]);
+
+ const [sidebar, setSidebar] = useState(false);
+
+ window.addEventListener("resize", () => setSidebar(false));
+
+ useEffect(() => {
+ setSidebar(false);
+ }, [router]);
+
+ const toggleSidebar = () => {
+ setSidebar(!sidebar);
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {router.asPath.split("/").pop()} Settings
+
+
+
+ {children}
+
+ {sidebar ? (
+
+ ) : null}
+
+
+ >
+ );
+}
diff --git a/lib/api/controllers/links/getLinks.ts b/lib/api/controllers/links/getLinks.ts
index be02293..ac0d057 100644
--- a/lib/api/controllers/links/getLinks.ts
+++ b/lib/api/controllers/links/getLinks.ts
@@ -3,138 +3,130 @@ import { LinkRequestQuery, Sort } from "@/types/global";
export default async function getLink(userId: number, body: string) {
const query: LinkRequestQuery = JSON.parse(decodeURIComponent(body));
- console.log(query);
const POSTGRES_IS_ENABLED = process.env.DATABASE_URL.startsWith("postgresql");
- // Sorting logic
+
let order: any;
- if (query.sort === Sort.DateNewestFirst)
- order = {
- createdAt: "desc",
- };
- else if (query.sort === Sort.DateOldestFirst)
- order = {
- createdAt: "asc",
- };
- else if (query.sort === Sort.NameAZ)
- order = {
- name: "asc",
- };
- else if (query.sort === Sort.NameZA)
- order = {
- name: "desc",
- };
- else if (query.sort === Sort.DescriptionAZ)
- order = {
- description: "asc",
- };
- else if (query.sort === Sort.DescriptionZA)
- order = {
- description: "desc",
- };
+ if (query.sort === Sort.DateNewestFirst) order = { createdAt: "desc" };
+ else if (query.sort === Sort.DateOldestFirst) order = { createdAt: "asc" };
+ else if (query.sort === Sort.NameAZ) order = { name: "asc" };
+ else if (query.sort === Sort.NameZA) order = { name: "desc" };
+ else if (query.sort === Sort.DescriptionAZ) order = { description: "asc" };
+ else if (query.sort === Sort.DescriptionZA) order = { description: "desc" };
+
+ const searchConditions = [];
+
+ if (query.searchQuery) {
+ if (query.searchFilter?.name) {
+ searchConditions.push({
+ name: {
+ contains: query.searchQuery,
+ mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
+ },
+ });
+ }
+
+ if (query.searchFilter?.url) {
+ searchConditions.push({
+ url: {
+ contains: query.searchQuery,
+ mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
+ },
+ });
+ }
+
+ if (query.searchFilter?.description) {
+ searchConditions.push({
+ description: {
+ contains: query.searchQuery,
+ mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
+ },
+ });
+ }
+
+ if (query.searchFilter?.tags) {
+ searchConditions.push({
+ tags: {
+ some: {
+ name: {
+ contains: query.searchQuery,
+ mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
+ },
+ OR: [
+ { ownerId: userId },
+ {
+ links: {
+ some: {
+ collection: {
+ members: {
+ some: { userId },
+ },
+ },
+ },
+ },
+ },
+ ],
+ },
+ },
+ });
+ }
+ }
+
+ const tagCondition = [];
+
+ if (query.tagId) {
+ tagCondition.push({
+ tags: {
+ some: {
+ id: query.tagId,
+ },
+ },
+ });
+ }
+
+ const collectionCondition = [];
+
+ if (query.collectionId) {
+ collectionCondition.push({
+ collection: {
+ id: query.collectionId,
+ },
+ });
+ }
const links = await prisma.link.findMany({
take: Number(process.env.PAGINATION_TAKE_COUNT) || 20,
skip: query.cursor ? 1 : undefined,
- cursor: query.cursor
- ? {
- id: query.cursor,
- }
- : undefined,
+ cursor: query.cursor ? { id: query.cursor } : undefined,
where: {
- collection: {
- id: query.collectionId ? query.collectionId : undefined, // If collectionId was defined, filter by collection
- OR: [
- {
- ownerId: userId,
- },
- {
- members: {
- some: {
- userId,
+ AND: [
+ {
+ collection: {
+ OR: [
+ { ownerId: userId },
+ {
+ members: {
+ some: { userId },
+ },
},
- },
- },
- ],
- },
- [query.searchQuery ? "OR" : "AND"]: [
- {
- pinnedBy: query.pinnedOnly ? { some: { id: userId } } : undefined,
- },
- {
- name: {
- contains:
- query.searchQuery && query.searchFilter?.name
- ? query.searchQuery
- : undefined,
- mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
+ ],
},
},
+ ...collectionCondition,
{
- url: {
- contains:
- query.searchQuery && query.searchFilter?.url
- ? query.searchQuery
- : undefined,
- mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
- },
- },
- {
- description: {
- contains:
- query.searchQuery && query.searchFilter?.description
- ? query.searchQuery
- : undefined,
- mode: POSTGRES_IS_ENABLED ? "insensitive" : undefined,
- },
- },
- {
- tags:
- query.searchQuery && !query.searchFilter?.tags
- ? undefined
- : {
- some: query.tagId
- ? {
- // If tagId was defined, filter by tag
- id: query.tagId,
- name:
- query.searchQuery && query.searchFilter?.tags
- ? {
- contains: query.searchQuery,
- mode: POSTGRES_IS_ENABLED
- ? "insensitive"
- : undefined,
- }
- : undefined,
- OR: [
- { ownerId: userId }, // Tags owned by the user
- {
- links: {
- some: {
- name: {
- contains:
- query.searchQuery &&
- query.searchFilter?.tags
- ? query.searchQuery
- : undefined,
- mode: POSTGRES_IS_ENABLED
- ? "insensitive"
- : undefined,
- },
- collection: {
- members: {
- some: {
- userId, // Tags from collections where the user is a member
- },
- },
- },
- },
- },
- },
- ],
- }
+ OR: [
+ ...tagCondition,
+ {
+ [query.searchQuery ? "OR" : "AND"]: [
+ {
+ pinnedBy: query.pinnedOnly
+ ? { some: { id: userId } }
: undefined,
},
+ ...searchConditions,
+ ],
+ },
+ ],
},
],
},
@@ -146,9 +138,7 @@ export default async function getLink(userId: number, body: string) {
select: { id: true },
},
},
- orderBy: order || {
- createdAt: "desc",
- },
+ orderBy: order || { createdAt: "desc" },
});
return { response: links, status: 200 };
diff --git a/lib/client/avatarExists.ts b/lib/client/avatarExists.ts
index 2e82fa6..f81f1e9 100644
--- a/lib/client/avatarExists.ts
+++ b/lib/client/avatarExists.ts
@@ -1,4 +1,13 @@
+const avatarCache = new Map();
+
export default async function avatarExists(fileUrl: string): Promise
{
+ if (avatarCache.has(fileUrl)) {
+ return avatarCache.get(fileUrl);
+ }
+
const response = await fetch(fileUrl, { method: "HEAD" });
- return !(response.headers.get("content-type") === "text/html");
+ const exists = !(response.headers.get("content-type") === "text/html");
+
+ avatarCache.set(fileUrl, exists);
+ return exists;
}
diff --git a/package.json b/package.json
index 22e782b..93867e6 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"@auth/prisma-adapter": "^1.0.1",
"@aws-sdk/client-s3": "^3.379.1",
"@fortawesome/fontawesome-svg-core": "^6.4.0",
+ "@fortawesome/free-brands-svg-icons": "^6.4.2",
"@fortawesome/free-regular-svg-icons": "^6.4.0",
"@fortawesome/free-solid-svg-icons": "^6.4.0",
"@fortawesome/react-fontawesome": "^0.2.0",
diff --git a/pages/collections/[id].tsx b/pages/collections/[id].tsx
index 34626f8..d3f6f56 100644
--- a/pages/collections/[id].tsx
+++ b/pages/collections/[id].tsx
@@ -229,11 +229,9 @@ export default function Index() {
{links.some((e) => e.collectionId === Number(router.query.id)) ? (
- {links
- .filter((e) => e.collectionId === Number(router.query.id))
- .map((e, i) => {
- return ;
- })}
+ {links.map((e, i) => {
+ return ;
+ })}
) : (
- {links
- .filter((e) => e.tags.some((e) => e.id === Number(router.query.id)))
- .map((e, i) => {
- return ;
- })}
+ {links.map((e, i) => {
+ return ;
+ })}
diff --git a/yarn.lock b/yarn.lock
index 83ac24e..bb2f10a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -779,6 +779,11 @@
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz#88da2b70d6ca18aaa6ed3687832e11f39e80624b"
integrity sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ==
+"@fortawesome/fontawesome-common-types@6.4.2":
+ version "6.4.2"
+ resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz#1766039cad33f8ad87f9467b98e0d18fbc8f01c5"
+ integrity sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==
+
"@fortawesome/fontawesome-svg-core@^6.4.0":
version "6.4.0"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz#3727552eff9179506e9203d72feb5b1063c11a21"
@@ -786,6 +791,13 @@
dependencies:
"@fortawesome/fontawesome-common-types" "6.4.0"
+"@fortawesome/free-brands-svg-icons@^6.4.2":
+ version "6.4.2"
+ resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.2.tgz#9b8e78066ea6dd563da5dfa686615791d0f7cc71"
+ integrity sha512-LKOwJX0I7+mR/cvvf6qIiqcERbdnY+24zgpUSouySml+5w8B4BJOx8EhDR/FTKAu06W12fmUIcv6lzPSwYKGGg==
+ dependencies:
+ "@fortawesome/fontawesome-common-types" "6.4.2"
+
"@fortawesome/free-regular-svg-icons@^6.4.0":
version "6.4.0"
resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.4.0.tgz#cacc53bd8d832d46feead412d9ea9ce80a55e13a"