From e910172558f0054a0435b22b17895c770e4013a1 Mon Sep 17 00:00:00 2001 From: Yee Jia Wei Date: Sun, 17 Dec 2023 16:22:08 +0800 Subject: [PATCH] update link action icons --- .../LinkViews/LinkComponents/LinkActions.tsx | 24 +-- components/ModalContent/DeleteLinkModal.tsx | 24 +-- components/ModalContent/EditLinkModal.tsx | 20 +-- .../ModalContent/PreservedFormatsModal.tsx | 155 ++---------------- components/PreserverdFormatRow.tsx | 137 ++++++++++++++++ 5 files changed, 164 insertions(+), 196 deletions(-) create mode 100644 components/PreserverdFormatRow.tsx diff --git a/components/LinkViews/LinkComponents/LinkActions.tsx b/components/LinkViews/LinkComponents/LinkActions.tsx index 9f53a05..5bd18c0 100644 --- a/components/LinkViews/LinkComponents/LinkActions.tsx +++ b/components/LinkViews/LinkComponents/LinkActions.tsx @@ -4,8 +4,6 @@ import { LinkIncludingShortenedCollectionAndTags, } from "@/types/global"; import usePermissions from "@/hooks/usePermissions"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faEllipsis } from "@fortawesome/free-solid-svg-icons"; import EditLinkModal from "@/components/ModalContent/EditLinkModal"; import DeleteLinkModal from "@/components/ModalContent/DeleteLinkModal"; import PreservedFormatsModal from "@/components/ModalContent/PreservedFormatsModal"; @@ -13,15 +11,13 @@ import useLinkStore from "@/store/links"; import { toast } from "react-hot-toast"; import useAccountStore from "@/store/account"; -export default function LinkActions({ - link, - collection, - position, -}: { +type Props = { link: LinkIncludingShortenedCollectionAndTags; collection: CollectionIncludingMembersAndLinkCount; position?: string; -}) { +} + +export default function LinkActions({ link, collection, position }: Props) { const permissions = usePermissions(link.collection.id as number); const [editLinkModal, setEditLinkModal] = useState(false); @@ -46,7 +42,7 @@ export default function LinkActions({ toast.dismiss(load); response.ok && - toast.success(`Link ${isAlreadyPinned ? "Unpinned!" : "Pinned!"}`); + toast.success(`Link ${isAlreadyPinned ? "Unpinned!" : "Pinned!"}`); }; const deleteLink = async () => { @@ -74,14 +70,10 @@ export default function LinkActions({ role="button" className="btn btn-ghost btn-sm btn-square text-neutral" > - + -
    +
      {permissions === true ? (
    • Are you sure you want to delete this Link?

      - - - + Warning: This action is irreversible! @@ -84,7 +64,7 @@ export default function DeleteLinkModal({ onClose, activeLink }: Props) { className={`ml-auto btn w-fit text-white flex items-center gap-2 duration-100 bg-red-500 hover:bg-red-400 hover:dark:bg-red-600 cursor-pointer`} onClick={deleteLink} > - + Delete
      diff --git a/components/ModalContent/EditLinkModal.tsx b/components/ModalContent/EditLinkModal.tsx index 94e2ce8..bb43efd 100644 --- a/components/ModalContent/EditLinkModal.tsx +++ b/components/ModalContent/EditLinkModal.tsx @@ -1,5 +1,4 @@ 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"; @@ -8,8 +7,6 @@ import useLinkStore from "@/store/links"; import { LinkIncludingShortenedCollectionAndTags } from "@/types/global"; import toast from "react-hot-toast"; import Link from "next/link"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faLink } from "@fortawesome/free-solid-svg-icons"; import Modal from "../Modal"; type Props = { @@ -89,10 +86,7 @@ export default function EditLinkModal({ onClose, activeLink }: Props) { title={link.url} target="_blank" > - +

      {shortendURL}

      ) : undefined} @@ -122,13 +116,13 @@ export default function EditLinkModal({ onClose, activeLink }: Props) { defaultValue={ link.collection.id ? { - value: link.collection.id, - label: link.collection.name, - } + value: link.collection.id, + label: link.collection.name, + } : { - value: null as unknown as number, - label: "Unorganized", - } + value: null as unknown as number, + label: "Unorganized", + } } /> ) : null} diff --git a/components/ModalContent/PreservedFormatsModal.tsx b/components/ModalContent/PreservedFormatsModal.tsx index 964dab5..73f6cc8 100644 --- a/components/ModalContent/PreservedFormatsModal.tsx +++ b/components/ModalContent/PreservedFormatsModal.tsx @@ -1,32 +1,13 @@ import React, { useEffect, useState } from "react"; import useLinkStore from "@/store/links"; -import { - ArchivedFormat, - LinkIncludingShortenedCollectionAndTags, -} from "@/types/global"; +import { ArchivedFormat, LinkIncludingShortenedCollectionAndTags, } from "@/types/global"; import toast from "react-hot-toast"; import Link from "next/link"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { - faArrowUpRightFromSquare, - faCloudArrowDown, - faLink, - faTrashCan, - faUpRightFromSquare, -} from "@fortawesome/free-solid-svg-icons"; import Modal from "../Modal"; -import { - faFileImage, - faFileLines, - faFilePdf, -} from "@fortawesome/free-regular-svg-icons"; import { useRouter } from "next/router"; import { useSession } from "next-auth/react"; -import { - pdfAvailable, - readabilityAvailable, - screenshotAvailable, -} from "@/lib/shared/getArchiveValidity"; +import { pdfAvailable, readabilityAvailable, screenshotAvailable, } from "@/lib/shared/getArchiveValidity"; +import PreservedFormatRow from "@/components/PreserverdFormatRow"; type Props = { onClose: Function; @@ -92,25 +73,6 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) { } else toast.error(data.response); }; - const handleDownload = (format: ArchivedFormat) => { - const path = `/api/v1/archives/${link?.id}?format=${format}`; - fetch(path) - .then((response) => { - if (response.ok) { - // Create a temporary link and click it to trigger the download - const link = document.createElement("a"); - link.href = path; - link.download = format === ArchivedFormat.png ? "Screenshot" : "PDF"; - link.click(); - } else { - console.error("Failed to download file"); - } - }) - .catch((error) => { - console.error("Error:", error); - }); - }; - return (

      Preserved Formats

      @@ -129,112 +91,18 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
      {readabilityAvailable(link) ? ( -
      -
      -
      - -
      - -

      Readable

      -
      - -
      - {/*
      handleDownload(ArchivedFormat.pdf)} - className="cursor-pointer hover:opacity-60 duration-100 p-2 rounded-md" - > - -
      */} - - - - -
      -
      + ) : undefined} {screenshotAvailable(link) ? ( -
      -
      -
      - -
      - -

      Screenshot

      -
      - -
      -
      handleDownload(ArchivedFormat.png)} - className="cursor-pointer hover:opacity-60 duration-100 p-2 rounded-md" - > - -
      - - - - -
      -
      + ) : undefined} {pdfAvailable(link) ? ( -
      -
      -
      - -
      - -

      PDF

      -
      - -
      -
      handleDownload(ArchivedFormat.pdf)} - className="cursor-pointer hover:opacity-60 duration-100 p-2 rounded-md" - > - -
      - - - - -
      -
      + ) : undefined}
      @@ -272,10 +140,7 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {

      View latest snapshot on archive.org

      - +
      diff --git a/components/PreserverdFormatRow.tsx b/components/PreserverdFormatRow.tsx new file mode 100644 index 0000000..499e448 --- /dev/null +++ b/components/PreserverdFormatRow.tsx @@ -0,0 +1,137 @@ +import React, { useEffect, useState } from "react"; +import useLinkStore from "@/store/links"; +import { + ArchivedFormat, + LinkIncludingShortenedCollectionAndTags, +} from "@/types/global"; +import toast from "react-hot-toast"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import { useSession } from "next-auth/react"; + +type Props = { + name: string, + icon: string, + format: ArchivedFormat, + activeLink: LinkIncludingShortenedCollectionAndTags, + downloadable?: boolean, +}; + +export default function PreservedFormatRow({ name, icon, format, activeLink, downloadable }: Props) { + const session = useSession(); + const { getLink } = useLinkStore(); + + const [link, setLink] = + useState(activeLink); + + const router = useRouter(); + + useEffect(() => { + let isPublicRoute = router.pathname.startsWith("/public") + ? true + : undefined; + + (async () => { + const data = await getLink(link.id as number, isPublicRoute); + setLink( + (data as any).response as LinkIncludingShortenedCollectionAndTags + ); + })(); + + let interval: any; + if (link?.screenshotPath === "pending" || link?.pdfPath === "pending") { + interval = setInterval(async () => { + const data = await getLink(link.id as number, isPublicRoute); + setLink( + (data as any).response as LinkIncludingShortenedCollectionAndTags + ); + }, 5000); + } else { + if (interval) { + clearInterval(interval); + } + } + + return () => { + if (interval) { + clearInterval(interval); + } + }; + }, [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 path = `/api/v1/archives/${link?.id}?format=${format}`; + fetch(path) + .then((response) => { + if (response.ok) { + // Create a temporary link and click it to trigger the download + const link = document.createElement("a"); + link.href = path; + link.download = format === ArchivedFormat.png ? "Screenshot" : "PDF"; + link.click(); + } else { + console.error("Failed to download file"); + } + }) + .catch((error) => { + console.error("Error:", error); + }); + }; + + return ( +
      +
      +
      + +
      +

      {name}

      +
      + +
      + {downloadable || false ? ( +
      handleDownload()} + className="cursor-pointer hover:opacity-60 duration-100 p-2 rounded-md" + > + +
      + ) : undefined} + + + + +
      +
      + ); +}