From 2d0e52f65b05cb4176d54927fbe5731905608091 Mon Sep 17 00:00:00 2001 From: daniel31x13 Date: Wed, 28 Aug 2024 20:22:11 -0400 Subject: [PATCH] better looking detail modal --- components/Drawer.tsx | 2 +- components/LinkDetails.tsx | 403 ++++++++++-------- .../LinkViews/LinkComponents/LinkActions.tsx | 1 + .../LinkViews/LinkComponents/LinkCard.tsx | 2 +- .../LinkViews/LinkComponents/LinkIcon.tsx | 2 +- .../LinkViews/LinkComponents/LinkMasonry.tsx | 2 +- components/ModalContent/LinkDetailModal.tsx | 203 ++++++++- pages/links/[id].tsx | 13 +- pages/public/links/[id].tsx | 11 +- 9 files changed, 427 insertions(+), 212 deletions(-) diff --git a/components/Drawer.tsx b/components/Drawer.tsx index 07673fb..49cd9eb 100644 --- a/components/Drawer.tsx +++ b/components/Drawer.tsx @@ -46,7 +46,7 @@ export default function Drawer({ data-testid="mobile-modal-container" >
{children} diff --git a/components/LinkDetails.tsx b/components/LinkDetails.tsx index c9b1e59..5c940de 100644 --- a/components/LinkDetails.tsx +++ b/components/LinkDetails.tsx @@ -10,6 +10,7 @@ import { readabilityAvailable, monolithAvailable, screenshotAvailable, + previewAvailable, } from "@/lib/shared/getArchiveValidity"; import PreservedFormatRow from "@/components/PreserverdFormatRow"; import getPublicUserData from "@/lib/client/getPublicUserData"; @@ -22,13 +23,22 @@ import CopyButton from "./CopyButton"; import { useRouter } from "next/router"; import Icon from "./Icon"; import { IconWeight } from "@phosphor-icons/react"; +import Image from "next/image"; +import clsx from "clsx"; type Props = { className?: string; link: LinkIncludingShortenedCollectionAndTags; + standalone?: boolean; + editMode?: boolean; }; -export default function LinkDetails({ className, link }: Props) { +export default function LinkDetails({ + className, + link, + standalone, + editMode, +}: Props) { const { t } = useTranslation(); const session = useSession(); const getLink = useGetLink(); @@ -126,192 +136,241 @@ export default function LinkDetails({ className, link }: Props) { const isPublicRoute = router.pathname.startsWith("/public") ? true : false; return ( -
-
- -
+
+
+
+ {previewAvailable(link) ? ( + { + const target = e.target as HTMLElement; + target.style.display = "none"; + }} + /> + ) : link.preview === "unavailable" ? ( +
+ ) : ( +
+ )} +
+ +
+
- {link.name &&

{link.name}

} +
+ {link.name &&

{link.name}

} + + {link.url && ( + <> +
+ +

{t("link")}

+ +
+
+ + {link.url} + +
+ +
+
+
+ + )} - {link.url && ( - <>
-

{t("link")}

+

{t("collection")}

-
- - {link.url} - + +

{link.collection.name}

- + {link.collection.icon ? ( + + ) : ( + + )}
-
-
- - )} - -
- -

{t("collection")}

- -
- -

{link.collection.name}

-
- {link.collection.icon ? ( - - ) : ( - - )} -
- -
- - {link.tags[0] && ( - <> -
- -
-

{t("tags")}

+
-
- {link.tags.map((tag) => - isPublicRoute ? ( -
- {tag.name} + {link.tags[0] && ( + <> +
+ +
+

{t("tags")}

+
+ +
+ {link.tags.map((tag) => + isPublicRoute ? ( +
+ {tag.name} +
+ ) : ( + + {tag.name} + + ) + )} +
+ + )} + + {link.description && ( + <> +
+ +
+

{t("notes")}

+ +
+

{link.description}

- ) : ( - - {tag.name} - - ) - )} -
- - )} +
+ + )} - {link.description && ( - <>
-
-

{t("notes")}

- -
-

{link.description}

-
-
- - )} - -
- -

- {link.url ? t("preserved_formats") : t("file")} -

- -
- {monolithAvailable(link) ? ( - - ) : undefined} - - {screenshotAvailable(link) ? ( - - ) : undefined} - - {pdfAvailable(link) ? ( - - ) : undefined} - - {readabilityAvailable(link) ? ( - - ) : undefined} - - {!isReady() && !atLeastOneFormatAvailable() ? ( -
- - -

{t("preservation_in_queue")}

-

{t("check_back_later")}

-
- ) : link.url && !isReady() && atLeastOneFormatAvailable() ? ( -
- -

{t("there_are_more_formats")}

-

{t("check_back_later")}

-
- ) : undefined} - - {link.url && ( - -

{t("view_latest_snapshot")}

- - - )} + {link.url ? t("preserved_formats") : t("file")} +

+ +
+ {monolithAvailable(link) ? ( + + ) : undefined} + + {screenshotAvailable(link) ? ( + + ) : undefined} + + {pdfAvailable(link) ? ( + + ) : undefined} + + {readabilityAvailable(link) ? ( + + ) : undefined} + + {!isReady() && !atLeastOneFormatAvailable() ? ( +
+ + +

+ {t("preservation_in_queue")} +

+

{t("check_back_later")}

+
+ ) : link.url && !isReady() && atLeastOneFormatAvailable() ? ( +
+ +

{t("there_are_more_formats")}

+

{t("check_back_later")}

+
+ ) : undefined} + + {link.url && ( + +

{t("view_latest_snapshot")}

+ + + )} +
+
); diff --git a/components/LinkViews/LinkComponents/LinkActions.tsx b/components/LinkViews/LinkComponents/LinkActions.tsx index 0e04491..3e20981 100644 --- a/components/LinkViews/LinkComponents/LinkActions.tsx +++ b/components/LinkViews/LinkComponents/LinkActions.tsx @@ -222,6 +222,7 @@ export default function LinkActions({ setLinkDetailModal(false)} onEdit={() => setEditLinkModal(true)} + onDelete={() => setDeleteLinkModal(true)} link={link} /> )} diff --git a/components/LinkViews/LinkComponents/LinkCard.tsx b/components/LinkViews/LinkComponents/LinkCard.tsx index 7d13b54..f24c2a6 100644 --- a/components/LinkViews/LinkComponents/LinkCard.tsx +++ b/components/LinkViews/LinkComponents/LinkCard.tsx @@ -172,7 +172,7 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) {
)} {show.icon && ( -
+
)} diff --git a/components/LinkViews/LinkComponents/LinkIcon.tsx b/components/LinkViews/LinkComponents/LinkIcon.tsx index c7c42dd..5bc9104 100644 --- a/components/LinkViews/LinkComponents/LinkIcon.tsx +++ b/components/LinkViews/LinkComponents/LinkIcon.tsx @@ -16,7 +16,7 @@ export default function LinkIcon({ hideBackground?: boolean; }) { let iconClasses: string = clsx( - "rounded flex item-center justify-center select-none z-10 w-12 h-12", + "rounded flex item-center justify-center shadow-md select-none z-10 w-12 h-12", !hideBackground && "rounded-md bg-white backdrop-blur-lg bg-opacity-50 p-1", className ); diff --git a/components/LinkViews/LinkComponents/LinkMasonry.tsx b/components/LinkViews/LinkComponents/LinkMasonry.tsx index b59233d..7d2163a 100644 --- a/components/LinkViews/LinkComponents/LinkMasonry.tsx +++ b/components/LinkViews/LinkComponents/LinkMasonry.tsx @@ -162,7 +162,7 @@ export default function LinkMasonry({ link, flipDropdown, editMode }: Props) {
)} {show.icon && ( -
+
)} diff --git a/components/ModalContent/LinkDetailModal.tsx b/components/ModalContent/LinkDetailModal.tsx index ad7d36c..5dac3b6 100644 --- a/components/ModalContent/LinkDetailModal.tsx +++ b/components/ModalContent/LinkDetailModal.tsx @@ -1,22 +1,38 @@ import React, { useEffect, useState } from "react"; -import { LinkIncludingShortenedCollectionAndTags } from "@/types/global"; +import { + ArchivedFormat, + LinkIncludingShortenedCollectionAndTags, +} from "@/types/global"; import getPublicUserData from "@/lib/client/getPublicUserData"; import { useTranslation } from "next-i18next"; import { useUser } from "@/hooks/store/user"; -import { useGetLink } from "@/hooks/store/links"; +import { useDeleteLink, useGetLink, useUpdateLink } from "@/hooks/store/links"; import Drawer from "../Drawer"; import LinkDetails from "../LinkDetails"; import Link from "next/link"; import usePermissions from "@/hooks/usePermissions"; import { useRouter } from "next/router"; +import { previewAvailable } from "@/lib/shared/getArchiveValidity"; +import Image from "next/image"; +import { dropdownTriggerer } from "@/lib/client/utils"; +import toast from "react-hot-toast"; +import EditLinkModal from "./EditLinkModal"; +import DeleteLinkModal from "./DeleteLinkModal"; +import PreservedFormatsModal from "./PreservedFormatsModal"; type Props = { onClose: Function; onEdit: Function; + onDelete: Function; link: LinkIncludingShortenedCollectionAndTags; }; -export default function LinkDetailModal({ onClose, onEdit, link }: Props) { +export default function LinkDetailModal({ + onClose, + onEdit, + onDelete, + link, +}: Props) { const { t } = useTranslation(); const getLink = useGetLink(); const { data: user = {} } = useUser(); @@ -105,39 +121,180 @@ export default function LinkDetailModal({ onClose, onEdit, link }: Props) { const isPublicRoute = router.pathname.startsWith("/public") ? true : false; + const updateLink = useUpdateLink(); + const deleteLink = useDeleteLink(); + + const pinLink = async () => { + const isAlreadyPinned = link?.pinnedBy && link.pinnedBy[0] ? true : false; + + const load = toast.loading(t("updating")); + + await updateLink.mutateAsync( + { + ...link, + pinnedBy: isAlreadyPinned ? undefined : [{ id: user.id }], + }, + { + onSettled: (data, error) => { + toast.dismiss(load); + + if (error) { + toast.error(error.message); + } else { + toast.success( + isAlreadyPinned ? t("link_unpinned") : t("link_pinned") + ); + } + }, + } + ); + }; + + const updateArchive = async () => { + const load = toast.loading(t("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) { + await getLink.mutateAsync({ id: link.id as number }); + + toast.success(t("link_being_archived")); + } else toast.error(data.response); + }; + + const [editLinkModal, setEditLinkModal] = useState(false); + const [deleteLinkModal, setDeleteLinkModal] = useState(false); + const [preservedFormatsModal, setPreservedFormatsModal] = useState(false); + return (
onClose()} >
- -
- - - {(permissions === true || permissions?.canUpdate) && ( - <> -
-
- -
+
+
+ +
+
    + {(permissions === true || permissions?.canUpdate) && ( +
  • { - onEdit(); - onClose(); + (document?.activeElement as HTMLElement)?.blur(); + pinLink(); }} + className="whitespace-nowrap" + > + {link?.pinnedBy && link.pinnedBy[0] + ? t("unpin") + : t("pin_to_dashboard")} +
    +
  • + )} + {(permissions === true || permissions?.canUpdate) && ( +
  • +
    { + (document?.activeElement as HTMLElement)?.blur(); + setEditLinkModal(true); + }} + className="whitespace-nowrap" > {t("edit_link")}
    +
  • + )} + {link.type === "url" && permissions === true && ( +
  • +
    { + (document?.activeElement as HTMLElement)?.blur(); + updateArchive(); + }} + className="whitespace-nowrap" + > + {t("refresh_preserved_formats")} +
    +
  • + )} + {(permissions === true || permissions?.canDelete) && ( +
  • +
    { + (document?.activeElement as HTMLElement)?.blur(); + console.log(e.shiftKey); + if (e.shiftKey) { + const load = toast.loading(t("deleting")); + + await deleteLink.mutateAsync(link.id as number, { + onSettled: (data, error) => { + toast.dismiss(load); + + if (error) { + toast.error(error.message); + } else { + toast.success(t("deleted")); + } + }, + }); + onClose(); + } else { + onDelete(); + onClose(); + } + }} + className="whitespace-nowrap" + > + {t("delete")} +
    +
  • + )} +
+
+ + +
+ + + {/* {(permissions === true || permissions?.canUpdate) && ( +
+
{ + onEdit(); + onClose(); + }} + > + {t("edit_link")}
- - )} +
+ )} */}
); diff --git a/pages/links/[id].tsx b/pages/links/[id].tsx index 55f5648..bacd5b3 100644 --- a/pages/links/[id].tsx +++ b/pages/links/[id].tsx @@ -17,14 +17,13 @@ const Index = () => { }, []); return ( -
+
{getLink.data ? ( -
- -
+ ) : (
diff --git a/pages/public/links/[id].tsx b/pages/public/links/[id].tsx index 98002d6..fe43a27 100644 --- a/pages/public/links/[id].tsx +++ b/pages/public/links/[id].tsx @@ -17,12 +17,11 @@ const Index = () => { return (
{getLink.data ? ( -
- -
+ ) : (