plane/web/components/pages/dropdowns/quick-actions.tsx
Aaryan Khandelwal d2717a221c
[WEB-1110] dev: custom context menu for issues, cycles, modules, views, pages and projects (#4267)
* dev: context menu

* chore: handle menu position on close

* chore: project quick actions

* chore: add more options to the project context menu

* chore: cycle item context menu

* refactor: context menu folder structure

* chore: module custom context menu

* chore: view custom context menu

* chore: issues custom context menu

* chore: reorder options

* chore: issues custom context menu

* chore: render the context menu in a portal
2024-04-30 18:59:07 +05:30

117 lines
3.3 KiB
TypeScript

import { useState } from "react";
import { observer } from "mobx-react";
import { ArchiveRestoreIcon, ExternalLink, Link, Lock, Trash2, UsersRound } from "lucide-react";
import { ArchiveIcon, ContextMenu, CustomMenu, TContextMenuItem, TOAST_TYPE, setToast } from "@plane/ui";
// components
import { DeletePageModal } from "@/components/pages";
// helpers
import { copyUrlToClipboard } from "@/helpers/string.helper";
// hooks
import { usePage } from "@/hooks/store";
type Props = {
pageId: string;
parentRef: React.RefObject<HTMLElement>;
projectId: string;
workspaceSlug: string;
};
export const PageQuickActions: React.FC<Props> = observer((props) => {
const { pageId, parentRef, projectId, workspaceSlug } = props;
// states
const [deletePageModal, setDeletePageModal] = useState(false);
// store hooks
const {
access,
archive,
archived_at,
makePublic,
makePrivate,
restore,
canCurrentUserArchivePage,
canCurrentUserChangeAccess,
canCurrentUserDeletePage,
} = usePage(pageId);
const pageLink = `${workspaceSlug}/projects/${projectId}/pages/${pageId}`;
const handleCopyText = () =>
copyUrlToClipboard(pageLink).then(() => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Link Copied!",
message: "Page link copied to clipboard.",
});
});
const handleOpenInNewTab = () => window.open(`/${pageLink}`, "_blank");
const MENU_ITEMS: TContextMenuItem[] = [
{
key: "make-public-private",
action: access === 0 ? makePrivate : makePublic,
title: access === 0 ? "Make private" : "Make public",
icon: access === 0 ? Lock : UsersRound,
shouldRender: canCurrentUserChangeAccess && !archived_at,
},
{
key: "open-new-tab",
action: handleOpenInNewTab,
title: "Open in new tab",
icon: ExternalLink,
shouldRender: true,
},
{
key: "copy-link",
action: handleCopyText,
title: "Copy link",
icon: Link,
shouldRender: true,
},
{
key: "archive-restore",
action: archived_at ? restore : archive,
title: archived_at ? "Restore" : "Archive",
icon: archived_at ? ArchiveRestoreIcon : ArchiveIcon,
shouldRender: canCurrentUserArchivePage,
},
{
key: "delete",
action: () => setDeletePageModal(true),
title: "Delete",
icon: Trash2,
shouldRender: canCurrentUserDeletePage && !!archived_at,
},
];
return (
<>
<DeletePageModal
isOpen={deletePageModal}
onClose={() => setDeletePageModal(false)}
pageId={pageId}
projectId={projectId}
/>
<ContextMenu parentRef={parentRef} items={MENU_ITEMS} />
<CustomMenu placement="bottom-end" ellipsis closeOnSelect>
{MENU_ITEMS.map((item) => {
if (!item.shouldRender) return null;
return (
<CustomMenu.MenuItem
key={item.key}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
item.action();
}}
className="flex items-center gap-2"
>
{item.icon && <item.icon className="h-3 w-3" />}
{item.title}
</CustomMenu.MenuItem>
);
})}
</CustomMenu>
</>
);
});