plane/web/components/cycles/quick-actions.tsx
Aaryan Khandelwal 535731141f
[WEB-682] feat: cycles list filtering and searching (#3910)
* chore: implemented cycles list filters and ordering

* chore: active cycle tab updated

* refactor: cycles folder structure

* fix: name search inout auto-focus

* fix: cycles ordering

* refactor: move cycle filters logic to mobx store from local storage

* chore: show completed cycles in a disclosure

* chore: added completed cycles count

* refactor: cycles mapping logic

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
2024-03-11 21:00:05 +05:30

113 lines
3.6 KiB
TypeScript

import { useState } from "react";
import { observer } from "mobx-react";
import { LinkIcon, Pencil, Trash2 } from "lucide-react";
// hooks
import { useCycle, useEventTracker, useUser } from "hooks/store";
// components
import { CycleCreateUpdateModal, CycleDeleteModal } from "components/cycles";
// ui
import { CustomMenu, TOAST_TYPE, setToast } from "@plane/ui";
// helpers
import { copyUrlToClipboard } from "helpers/string.helper";
// constants
import { EUserProjectRoles } from "constants/project";
type Props = {
cycleId: string;
projectId: string;
workspaceSlug: string;
};
export const CycleQuickActions: React.FC<Props> = observer((props) => {
const { cycleId, projectId, workspaceSlug } = props;
// states
const [updateModal, setUpdateModal] = useState(false);
const [deleteModal, setDeleteModal] = useState(false);
// store hooks
const { setTrackElement } = useEventTracker();
const {
membership: { currentWorkspaceAllProjectsRole },
} = useUser();
const { getCycleById } = useCycle();
// derived values
const cycleDetails = getCycleById(cycleId);
const isCompleted = cycleDetails?.status.toLowerCase() === "completed";
// auth
const isEditingAllowed =
!!currentWorkspaceAllProjectsRole && currentWorkspaceAllProjectsRole[projectId] >= EUserProjectRoles.MEMBER;
const handleCopyText = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
e.stopPropagation();
copyUrlToClipboard(`${workspaceSlug}/projects/${projectId}/cycles/${cycleId}`).then(() => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Link Copied!",
message: "Cycle link copied to clipboard.",
});
});
};
const handleEditCycle = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
e.stopPropagation();
setTrackElement("Cycles page list layout");
setUpdateModal(true);
};
const handleDeleteCycle = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
e.stopPropagation();
setTrackElement("Cycles page list layout");
setDeleteModal(true);
};
return (
<>
{cycleDetails && (
<div className="fixed">
<CycleCreateUpdateModal
data={cycleDetails}
isOpen={updateModal}
handleClose={() => setUpdateModal(false)}
workspaceSlug={workspaceSlug}
projectId={projectId}
/>
<CycleDeleteModal
cycle={cycleDetails}
isOpen={deleteModal}
handleClose={() => setDeleteModal(false)}
workspaceSlug={workspaceSlug}
projectId={projectId}
/>
</div>
)}
<CustomMenu ellipsis placement="bottom-end">
{!isCompleted && isEditingAllowed && (
<>
<CustomMenu.MenuItem onClick={handleEditCycle}>
<span className="flex items-center justify-start gap-2">
<Pencil className="h-3 w-3" />
<span>Edit cycle</span>
</span>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem onClick={handleDeleteCycle}>
<span className="flex items-center justify-start gap-2">
<Trash2 className="h-3 w-3" />
<span>Delete cycle</span>
</span>
</CustomMenu.MenuItem>
</>
)}
<CustomMenu.MenuItem onClick={handleCopyText}>
<span className="flex items-center justify-start gap-2">
<LinkIcon className="h-3 w-3" />
<span>Copy cycle link</span>
</span>
</CustomMenu.MenuItem>
</CustomMenu>
</>
);
});