From 18e0b8b010655b8efd490b2e1bc4c8dea50f4535 Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Sat, 2 Dec 2023 13:33:07 -0500 Subject: [PATCH 01/12] removed extra fields --- pages/settings/appearance.tsx | 38 +------------------ .../migration.sql | 10 +++++ prisma/schema.prisma | 2 - 3 files changed, 12 insertions(+), 38 deletions(-) create mode 100644 prisma/migrations/20231202183159_remove_extra_fields/migration.sql diff --git a/pages/settings/appearance.tsx b/pages/settings/appearance.tsx index 26fb0b2..3ff1eb7 100644 --- a/pages/settings/appearance.tsx +++ b/pages/settings/appearance.tsx @@ -99,46 +99,12 @@ export default function Appearance() { -
-
-

Link Card

-
- -
- - - setUser({ ...user, displayLinkIcons: !user.displayLinkIcons }) - } - /> - {user.displayLinkIcons ? ( - - setUser({ ...user, blurredFavicons: !user.blurredFavicons }) - } - /> - ) : undefined} -

Preview:

- - -
- - + /> */} ); diff --git a/prisma/migrations/20231202183159_remove_extra_fields/migration.sql b/prisma/migrations/20231202183159_remove_extra_fields/migration.sql new file mode 100644 index 0000000..5380a30 --- /dev/null +++ b/prisma/migrations/20231202183159_remove_extra_fields/migration.sql @@ -0,0 +1,10 @@ +/* + Warnings: + + - You are about to drop the column `blurredFavicons` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `displayLinkIcons` on the `User` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "User" DROP COLUMN "blurredFavicons", +DROP COLUMN "displayLinkIcons"; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index dd91892..6ea1bda 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -45,8 +45,6 @@ model User { archiveAsPDF Boolean @default(true) archiveAsWaybackMachine Boolean @default(false) isPrivate Boolean @default(false) - displayLinkIcons Boolean @default(true) - blurredFavicons Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @default(now()) } From c447b365404352814c25ebd1a42bbbc234b73649 Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Sat, 2 Dec 2023 13:34:28 -0500 Subject: [PATCH 02/12] minor fix --- components/LinkCard.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/LinkCard.tsx b/components/LinkCard.tsx index 2f734f9..555358a 100644 --- a/components/LinkCard.tsx +++ b/components/LinkCard.tsx @@ -212,15 +212,13 @@ export default function LinkCard({ link, count, className }: Props) { onClick={() => router.push("/links/" + link.id)} className="flex items-start cursor-pointer gap-5 sm:gap-10 h-full w-full p-4" > - {url && account.displayLinkIcons && ( + {url && ( { const target = e.target as HTMLElement; From 33be9e5d83a80637f6f41c2ebae87845e4eeb189 Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Sat, 2 Dec 2023 15:23:26 -0500 Subject: [PATCH 03/12] minor patch --- components/ModalContent/NewLinkModal.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/ModalContent/NewLinkModal.tsx b/components/ModalContent/NewLinkModal.tsx index cd7cd53..1c73e40 100644 --- a/components/ModalContent/NewLinkModal.tsx +++ b/components/ModalContent/NewLinkModal.tsx @@ -23,6 +23,7 @@ export default function NewLinkModal({ onClose }: Props) { name: "", url: "", description: "", + type: "url", tags: [], screenshotPath: "", pdfPath: "", @@ -32,7 +33,7 @@ export default function NewLinkModal({ onClose }: Props) { name: "", ownerId: data?.user.id as number, }, - }; + } as LinkIncludingShortenedCollectionAndTags; const [link, setLink] = useState(initial); @@ -127,7 +128,7 @@ export default function NewLinkModal({ onClose }: Props) {

Link

setLink({ ...link, url: e.target.value })} placeholder="e.g. http://example.com/" className="bg-base-200" From 9c65e3e215e54cd183de9b515b7374f82b14bdce Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Sun, 3 Dec 2023 23:52:32 -0500 Subject: [PATCH 04/12] implemented basic support for pdf, png and jpg --- .env.sample | 1 + .../InputSelect/CollectionSelection.tsx | 8 +- .../ModalContent/DeleteCollectionModal.tsx | 4 +- components/ModalContent/DeleteLinkModal.tsx | 13 +- .../ModalContent/EditCollectionModal.tsx | 4 +- .../EditCollectionSharingModal.tsx | 12 +- components/ModalContent/EditLinkModal.tsx | 32 +-- .../ModalContent/NewCollectionModal.tsx | 4 +- components/ModalContent/NewLinkModal.tsx | 11 +- components/ModalContent/UploadFileModal.tsx | 237 ++++++++++++++++++ components/Navbar.tsx | 17 ++ package.json | 2 + pages/api/v1/archives/[linkId].ts | 128 ++++++++-- styles/globals.css | 4 + types/enviornment.d.ts | 1 + yarn.lock | 34 +++ 16 files changed, 443 insertions(+), 69 deletions(-) create mode 100644 components/ModalContent/UploadFileModal.tsx diff --git a/.env.sample b/.env.sample index 74e9192..10ed7ee 100644 --- a/.env.sample +++ b/.env.sample @@ -13,6 +13,7 @@ STORAGE_FOLDER= AUTOSCROLL_TIMEOUT= NEXT_PUBLIC_DISABLE_REGISTRATION= RE_ARCHIVE_LIMIT= +NEXT_PUBLIC_MAX_UPLOAD_SIZE= # AWS S3 Settings SPACES_KEY= diff --git a/components/InputSelect/CollectionSelection.tsx b/components/InputSelect/CollectionSelection.tsx index b514f79..71dc075 100644 --- a/components/InputSelect/CollectionSelection.tsx +++ b/components/InputSelect/CollectionSelection.tsx @@ -13,14 +13,9 @@ type Props = { value?: number; } | undefined; - id?: string; }; -export default function CollectionSelection({ - onChange, - defaultValue, - id, -}: Props) { +export default function CollectionSelection({ onChange, defaultValue }: Props) { const { collections } = useCollectionStore(); const router = useRouter(); @@ -49,7 +44,6 @@ export default function CollectionSelection({ return ( -

+

{permissions === true ? "Delete" : "Leave"} Collection

+
+
{permissions === true ? ( <> diff --git a/components/ModalContent/DeleteLinkModal.tsx b/components/ModalContent/DeleteLinkModal.tsx index 3a2654e..21ccc94 100644 --- a/components/ModalContent/DeleteLinkModal.tsx +++ b/components/ModalContent/DeleteLinkModal.tsx @@ -21,14 +21,6 @@ export default function DeleteLinkModal({ onClose, activeLink }: Props) { const [link, setLink] = useState(activeLink); - let shortendURL; - - try { - shortendURL = new URL(link.url).host.toLowerCase(); - } catch (error) { - console.log(error); - } - const { removeLink } = useLinkStore(); const [submitLoader, setSubmitLoader] = useState(false); @@ -50,7 +42,10 @@ export default function DeleteLinkModal({ onClose, activeLink }: Props) { return ( -

Delete Link

+

Delete Link

+ +
+

Are you sure you want to delete this Link?

diff --git a/components/ModalContent/EditCollectionModal.tsx b/components/ModalContent/EditCollectionModal.tsx index 5d15687..da22a87 100644 --- a/components/ModalContent/EditCollectionModal.tsx +++ b/components/ModalContent/EditCollectionModal.tsx @@ -49,7 +49,9 @@ export default function EditCollectionModal({ return ( -

Edit Collection Info

+

Edit Collection Info

+ +
diff --git a/components/ModalContent/EditCollectionSharingModal.tsx b/components/ModalContent/EditCollectionSharingModal.tsx index 7523e34..e6771ce 100644 --- a/components/ModalContent/EditCollectionSharingModal.tsx +++ b/components/ModalContent/EditCollectionSharingModal.tsx @@ -95,10 +95,12 @@ export default function EditCollectionSharingModal({ return ( -

+

{permissions === true ? "Share and Collaborate" : "Team"}

+
+
{permissions === true && (
@@ -178,7 +180,7 @@ export default function EditCollectionSharingModal({ setMemberState ) } - className="btn btn-primary text-white btn-square" + className="btn btn-primary btn-square btn-sm h-10 w-10" >
@@ -323,7 +325,7 @@ export default function EditCollectionSharingModal({ }} /> -

Edit Link

+

Edit Link

- - -

{shortendURL}

- +
+ + {link.url ? ( + + +

{shortendURL}

+ + ) : undefined}

Name

diff --git a/components/ModalContent/NewCollectionModal.tsx b/components/ModalContent/NewCollectionModal.tsx index 27936e4..2c3a806 100644 --- a/components/ModalContent/NewCollectionModal.tsx +++ b/components/ModalContent/NewCollectionModal.tsx @@ -54,7 +54,9 @@ export default function NewCollectionModal({ onClose }: Props) { return ( -

Create a New Collection

+

Create a New Collection

+ +
diff --git a/components/ModalContent/NewLinkModal.tsx b/components/ModalContent/NewLinkModal.tsx index 1c73e40..3eaa6aa 100644 --- a/components/ModalContent/NewLinkModal.tsx +++ b/components/ModalContent/NewLinkModal.tsx @@ -41,8 +41,6 @@ export default function NewLinkModal({ onClose }: Props) { const { addLink } = useLinkStore(); const [submitLoader, setSubmitLoader] = useState(false); - const [resetCollectionSelection, setResetCollectionSelection] = useState(""); - const [optionsExpanded, setOptionsExpanded] = useState(false); const router = useRouter(); @@ -66,9 +64,6 @@ export default function NewLinkModal({ onClose }: Props) { }; useEffect(() => { - setResetCollectionSelection(Date.now().toString()); - console.log(link); - setOptionsExpanded(false); if (router.query.id) { const currentCollection = collections.find( @@ -123,7 +118,10 @@ export default function NewLinkModal({ onClose }: Props) { return ( -

Create a New Link

+

Create a New Link

+ +
+

Link

@@ -143,7 +141,6 @@ export default function NewLinkModal({ onClose }: Props) { label: link.collection.name, value: link.collection.id, }} - id={resetCollectionSelection} /> ) : null}
diff --git a/components/ModalContent/UploadFileModal.tsx b/components/ModalContent/UploadFileModal.tsx new file mode 100644 index 0000000..1102533 --- /dev/null +++ b/components/ModalContent/UploadFileModal.tsx @@ -0,0 +1,237 @@ +import React, { useEffect, useState } from "react"; +import { Toaster } from "react-hot-toast"; +import CollectionSelection from "@/components/InputSelect/CollectionSelection"; +import TagSelection from "@/components/InputSelect/TagSelection"; +import TextInput from "@/components/TextInput"; +import unescapeString from "@/lib/client/unescapeString"; +import useCollectionStore from "@/store/collections"; +import useLinkStore from "@/store/links"; +import { + ArchivedFormat, + LinkIncludingShortenedCollectionAndTags, +} from "@/types/global"; +import { useSession } from "next-auth/react"; +import { useRouter } from "next/router"; +import toast from "react-hot-toast"; +import Modal from "../Modal"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faQuestion } from "@fortawesome/free-solid-svg-icons"; +import { faQuestionCircle } from "@fortawesome/free-regular-svg-icons"; + +type Props = { + onClose: Function; +}; + +export default function UploadFileModal({ onClose }: Props) { + const { data } = useSession(); + + const initial = { + name: "", + url: "", + description: "", + type: "url", + tags: [], + screenshotPath: "", + pdfPath: "", + readabilityPath: "", + textContent: "", + collection: { + name: "", + ownerId: data?.user.id as number, + }, + } as LinkIncludingShortenedCollectionAndTags; + + const [link, setLink] = + useState(initial); + + const [file, setFile] = useState(); + + const { addLink } = useLinkStore(); + const [submitLoader, setSubmitLoader] = useState(false); + + const [optionsExpanded, setOptionsExpanded] = useState(false); + + const router = useRouter(); + const { collections } = useCollectionStore(); + + const setCollection = (e: any) => { + if (e?.__isNew__) e.value = null; + + setLink({ + ...link, + collection: { id: e?.value, name: e?.label, ownerId: e?.ownerId }, + }); + }; + + const setTags = (e: any) => { + const tagNames = e.map((e: any) => { + return { name: e.label }; + }); + + setLink({ ...link, tags: tagNames }); + }; + + useEffect(() => { + setOptionsExpanded(false); + if (router.query.id) { + const currentCollection = collections.find( + (e) => e.id == Number(router.query.id) + ); + + if ( + currentCollection && + currentCollection.ownerId && + router.asPath.startsWith("/collections/") + ) + setLink({ + ...initial, + collection: { + id: currentCollection.id, + name: currentCollection.name, + ownerId: currentCollection.ownerId, + }, + }); + } else + setLink({ + ...initial, + collection: { + name: "Unorganized", + ownerId: data?.user.id as number, + }, + }); + }, []); + + const submit = async () => { + if (!submitLoader && file) { + let fileType: ArchivedFormat | null = null; + + if (file?.type === "image/jpg" || file.type === "image/jpeg") + fileType = ArchivedFormat.jpeg; + else if (file.type === "image/png") fileType = ArchivedFormat.png; + else if (file.type === "application/pdf") fileType = ArchivedFormat.pdf; + + console.log(fileType); + if (fileType !== null) { + setSubmitLoader(true); + + let response; + + const load = toast.loading("Creating..."); + + response = await addLink(link); + + toast.dismiss(load); + + if (response.ok) { + const formBody = new FormData(); + file && formBody.append("file", file); + + console.log(formBody.get("file")); + await fetch( + `/api/v1/archives/${ + (response.data as LinkIncludingShortenedCollectionAndTags).id + }?format=${fileType}`, + { + body: formBody, + method: "POST", + } + ); + toast.success(`Created!`); + onClose(); + } else toast.error(response.data as string); + + setSubmitLoader(false); + + return response; + } + } + }; + + return ( + +
+

Upload File

+
+
+
+
+

File

+ +

+ PDF, PNG, JPG (Up to {process.env.NEXT_PUBLIC_MAX_UPLOAD_SIZE || 30} + MB) +

+
+
+

Collection

+ {link.collection.name ? ( + + ) : null} +
+
+ {optionsExpanded ? ( +
+ {/*
*/} +
+
+

Name

+ setLink({ ...link, name: e.target.value })} + placeholder="e.g. Example Link" + className="bg-base-200" + /> +
+ +
+

Tags

+ { + return { label: e.name, value: e.id }; + })} + /> +
+ +
+

Description

+