managed how LinkCards are viewed by members

This commit is contained in:
Daniel 2023-06-21 07:10:45 +03:30
parent fdbe2e0d9f
commit 51c5615fea
3 changed files with 99 additions and 52 deletions

View File

@ -12,7 +12,8 @@ type MenuItem =
name: string; name: string;
onClick?: MouseEventHandler; onClick?: MouseEventHandler;
href: string; href: string;
}; }
| undefined;
type Props = { type Props = {
onClickOutside: Function; onClickOutside: Function;
@ -27,7 +28,7 @@ export default function Dropdown({ onClickOutside, className, items }: Props) {
className={`${className} py-1 shadow-md border border-sky-100 bg-gray-50 rounded-md flex flex-col z-20`} className={`${className} py-1 shadow-md border border-sky-100 bg-gray-50 rounded-md flex flex-col z-20`}
> >
{items.map((e, i) => { {items.map((e, i) => {
const inner = ( const inner = e && (
<div className="cursor-pointer rounded-md"> <div className="cursor-pointer rounded-md">
<div className="flex items-center gap-2 py-1 px-2 hover:bg-slate-200 duration-100"> <div className="flex items-center gap-2 py-1 px-2 hover:bg-slate-200 duration-100">
<p className="text-sky-900 select-none">{e.name}</p> <p className="text-sky-900 select-none">{e.name}</p>
@ -35,14 +36,16 @@ export default function Dropdown({ onClickOutside, className, items }: Props) {
</div> </div>
); );
return e.href ? ( return e && e.href ? (
<Link key={i} href={e.href}> <Link key={i} href={e.href}>
{inner} {inner}
</Link> </Link>
) : ( ) : (
<div key={i} onClick={e.onClick}> e && (
{inner} <div key={i} onClick={e.onClick}>
</div> {inner}
</div>
)
); );
})} })}
</ClickAwayHandler> </ClickAwayHandler>

View File

@ -1,6 +1,7 @@
import { import {
CollectionIncludingMembersAndLinkCount, CollectionIncludingMembersAndLinkCount,
LinkIncludingShortenedCollectionAndTags, LinkIncludingShortenedCollectionAndTags,
Member,
} from "@/types/global"; } from "@/types/global";
import { faFolder, faEllipsis } from "@fortawesome/free-solid-svg-icons"; import { faFolder, faEllipsis } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@ -12,6 +13,7 @@ import useCollectionStore from "@/store/collections";
import useAccountStore from "@/store/account"; import useAccountStore from "@/store/account";
import useModalStore from "@/store/modals"; import useModalStore from "@/store/modals";
import { faCalendarDays } from "@fortawesome/free-regular-svg-icons"; import { faCalendarDays } from "@fortawesome/free-regular-svg-icons";
import usePermissions from "@/hooks/usePermissions";
type Props = { type Props = {
link: LinkIncludingShortenedCollectionAndTags; link: LinkIncludingShortenedCollectionAndTags;
@ -22,6 +24,8 @@ type Props = {
export default function LinkCard({ link, count, className }: Props) { export default function LinkCard({ link, count, className }: Props) {
const { setModal } = useModalStore(); const { setModal } = useModalStore();
const permissions = usePermissions(link.collection.id as number);
const [expandDropdown, setExpandDropdown] = useState(false); const [expandDropdown, setExpandDropdown] = useState(false);
const { collections } = useCollectionStore(); const { collections } = useCollectionStore();
@ -59,18 +63,20 @@ export default function LinkCard({ link, count, className }: Props) {
<div <div
className={`bg-gradient-to-tr from-slate-200 from-10% to-gray-50 via-20% shadow hover:shadow-none cursor-pointer duration-100 p-5 rounded-2xl relative group ${className}`} className={`bg-gradient-to-tr from-slate-200 from-10% to-gray-50 via-20% shadow hover:shadow-none cursor-pointer duration-100 p-5 rounded-2xl relative group ${className}`}
> >
<div {permissions && (
onClick={() => setExpandDropdown(!expandDropdown)} <div
id={"expand-dropdown" + link.id} onClick={() => setExpandDropdown(!expandDropdown)}
className="text-gray-500 inline-flex rounded-md cursor-pointer hover:bg-slate-200 absolute right-5 top-5 z-10 duration-100 p-1"
>
<FontAwesomeIcon
icon={faEllipsis}
title="More"
className="w-5 h-5"
id={"expand-dropdown" + link.id} id={"expand-dropdown" + link.id}
/> className="text-gray-500 inline-flex rounded-md cursor-pointer hover:bg-slate-200 absolute right-5 top-5 z-10 duration-100 p-1"
</div> >
<FontAwesomeIcon
icon={faEllipsis}
title="More"
className="w-5 h-5"
id={"expand-dropdown" + link.id}
/>
</div>
)}
<div <div
onClick={() => { onClick={() => {
@ -126,42 +132,48 @@ export default function LinkCard({ link, count, className }: Props) {
{expandDropdown ? ( {expandDropdown ? (
<Dropdown <Dropdown
items={[ items={[
{ permissions === true || permissions?.canUpdate
name: ? {
link?.pinnedBy && link.pinnedBy[0] name:
? "Unpin"
: "Pin to Dashboard",
onClick: () => {
updateLink({
...link,
pinnedBy:
link?.pinnedBy && link.pinnedBy[0] link?.pinnedBy && link.pinnedBy[0]
? undefined ? "Unpin"
: [{ id: account.id }], : "Pin to Dashboard",
}); onClick: () => {
setExpandDropdown(false); updateLink({
}, ...link,
}, pinnedBy:
{ link?.pinnedBy && link.pinnedBy[0]
name: "Edit", ? undefined
onClick: () => { : [{ id: account.id }],
setModal({ });
modal: "LINK", setExpandDropdown(false);
state: true, },
method: "UPDATE", }
active: link, : undefined,
defaultIndex: 1, permissions === true || permissions?.canUpdate
}); ? {
setExpandDropdown(false); name: "Edit",
}, onClick: () => {
}, setModal({
{ modal: "LINK",
name: "Delete", state: true,
onClick: () => { method: "UPDATE",
removeLink(link); active: link,
setExpandDropdown(false); defaultIndex: 1,
}, });
}, setExpandDropdown(false);
},
}
: undefined,
permissions === true || permissions?.canDelete
? {
name: "Delete",
onClick: () => {
removeLink(link);
setExpandDropdown(false);
},
}
: undefined,
]} ]}
onClickOutside={(e: Event) => { onClickOutside={(e: Event) => {
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;

32
hooks/usePermissions.tsx Normal file
View File

@ -0,0 +1,32 @@
import useAccountStore from "@/store/account";
import useCollectionStore from "@/store/collections";
import { CollectionIncludingMembersAndLinkCount, Member } from "@/types/global";
import React, { useEffect, useState } from "react";
export default function usePermissions(collectionId: number) {
const { collections } = useCollectionStore();
const { account } = useAccountStore();
const [permissions, setPermissions] = useState<Member | true>();
useEffect(() => {
const collection = collections.find((e) => e.id === collectionId);
if (collection) {
let getPermission: Member | undefined = collection.members.find(
(e) => e.userId === account.id
);
if (
getPermission?.canCreate === false &&
getPermission?.canUpdate === false &&
getPermission?.canDelete === false
)
getPermission = undefined;
setPermissions(account.id === collection.ownerId || getPermission);
}
}, [collections]);
return permissions;
}