From 9c65e3e215e54cd183de9b515b7374f82b14bdce Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Sun, 3 Dec 2023 23:52:32 -0500 Subject: [PATCH] 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

+