import { CollectionIncludingMembersAndLinkCount, LinkIncludingShortenedCollectionAndTags, } from "@/types/global"; import { faFolder, faEllipsis, faLink, } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useEffect, useState } from "react"; import Image from "next/image"; import Dropdown from "./Dropdown"; import useLinkStore from "@/store/links"; import useCollectionStore from "@/store/collections"; import useAccountStore from "@/store/account"; import useModalStore from "@/store/modals"; import { faCalendarDays } from "@fortawesome/free-regular-svg-icons"; import usePermissions from "@/hooks/usePermissions"; import { toast } from "react-hot-toast"; import isValidUrl from "@/lib/client/isValidUrl"; import Link from "next/link"; import unescapeString from "@/lib/client/unescapeString"; import { useRouter } from "next/router"; type Props = { link: LinkIncludingShortenedCollectionAndTags; count: number; className?: string; }; type DropdownTrigger = | { x: number; y: number; } | false; export default function LinkCard({ link, count, className }: Props) { const { setModal } = useModalStore(); const router = useRouter(); const permissions = usePermissions(link.collection.id as number); const [expandDropdown, setExpandDropdown] = useState(false); const { collections } = useCollectionStore(); const { links } = useLinkStore(); const { account } = useAccountStore(); let shortendURL; try { shortendURL = new URL(link.url).host.toLowerCase(); } catch (error) { console.log(error); } const [collection, setCollection] = useState( collections.find( (e) => e.id === link.collection.id ) as CollectionIncludingMembersAndLinkCount ); useEffect(() => { setCollection( collections.find( (e) => e.id === link.collection.id ) as CollectionIncludingMembersAndLinkCount ); }, [collections, links]); const { removeLink, updateLink, getLink } = useLinkStore(); const pinLink = async () => { const isAlreadyPinned = link?.pinnedBy && link.pinnedBy[0]; const load = toast.loading("Applying..."); setExpandDropdown(false); const response = await updateLink({ ...link, pinnedBy: isAlreadyPinned ? undefined : [{ id: account.id }], }); toast.dismiss(load); response.ok && toast.success(`Link ${isAlreadyPinned ? "Unpinned!" : "Pinned!"}`); }; const updateArchive = async () => { const load = toast.loading("Sending request..."); setExpandDropdown(false); 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 deleteLink = async () => { const load = toast.loading("Deleting..."); const response = await removeLink(link.id as number); toast.dismiss(load); response.ok && toast.success(`Link Deleted.`); setExpandDropdown(false); }; const url = isValidUrl(link.url) ? new URL(link.url) : undefined; const formattedDate = new Date(link.createdAt as string).toLocaleString( "en-US", { year: "numeric", month: "short", day: "numeric", } ); return ( <>
{(permissions === true || permissions?.canUpdate || permissions?.canDelete) && (
{ setExpandDropdown({ x: e.clientX, y: e.clientY }); }} id={"expand-dropdown" + link.id} className="text-gray-500 dark:text-gray-300 inline-flex rounded-md cursor-pointer hover:bg-slate-200 dark:hover:bg-neutral-700 absolute right-4 top-4 z-10 duration-100 p-1" >
)}
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 && ( { const target = e.target as HTMLElement; target.style.display = "none"; }} /> )}

{count + 1}

{unescapeString(link.name || link.description)}

{ e.stopPropagation(); }} className="flex items-center gap-1 max-w-full w-fit my-1 hover:opacity-70 duration-100" >

{collection?.name}

{/* {link.tags[0] ? (
{link.tags.map((e, i) => ( { e.stopPropagation(); }} className="px-2 bg-sky-200 text-black dark:text-white dark:bg-sky-900 text-xs rounded-3xl cursor-pointer hover:opacity-60 duration-100 truncate max-w-[19rem]" > {e.name} ))}
) : undefined} */} { e.stopPropagation(); }} className="flex items-center gap-1 max-w-full w-fit text-gray-500 dark:text-gray-300 hover:opacity-70 duration-100" >

{shortendURL}

{formattedDate}

{expandDropdown ? ( { setModal({ modal: "LINK", state: true, method: "UPDATE", active: link, }); setExpandDropdown(false); }, } : undefined, permissions === true ? { name: "Refresh Link", onClick: updateArchive, } : undefined, permissions === true || permissions?.canDelete ? { name: "Delete", onClick: deleteLink, } : undefined, ]} onClickOutside={(e: Event) => { const target = e.target as HTMLInputElement; if (target.id !== "expand-dropdown" + link.id) setExpandDropdown(false); }} className="w-40" /> ) : null} ); }