import { useRef, useState } from "react"; import { DraggableProvided, DraggableStateSnapshot } from "@hello-pangea/dnd"; import { observer } from "mobx-react-lite"; import Link from "next/link"; import { useRouter } from "next/router"; import { Disclosure, Transition } from "@headlessui/react"; // icons import { MoreVertical, PenSquare, LinkIcon, Star, FileText, Settings, Share2, LogOut, ChevronDown, MoreHorizontal, Inbox, } from "lucide-react"; // ui import { CustomMenu, Tooltip, ArchiveIcon, PhotoFilterIcon, DiceIcon, ContrastIcon, LayersIcon, setPromiseToast, } from "@plane/ui"; import { LeaveProjectModal, ProjectLogo, PublishProjectModal } from "components/project"; import { EUserProjectRoles } from "constants/project"; import { cn } from "helpers/common.helper"; import { getNumberCount } from "helpers/string.helper"; // hooks import { useApplication, useEventTracker, useInbox, useProject } from "hooks/store"; import useOutsideClickDetector from "hooks/use-outside-click-detector"; import { usePlatformOS } from "hooks/use-platform-os"; // helpers // components type Props = { projectId: string; provided?: DraggableProvided; snapshot?: DraggableStateSnapshot; handleCopyText: () => void; shortContextMenu?: boolean; disableDrag?: boolean; }; const navigation = (workspaceSlug: string, projectId: string) => [ { name: "Issues", href: `/${workspaceSlug}/projects/${projectId}/issues`, Icon: LayersIcon, }, { name: "Cycles", href: `/${workspaceSlug}/projects/${projectId}/cycles`, Icon: ContrastIcon, }, { name: "Modules", href: `/${workspaceSlug}/projects/${projectId}/modules`, Icon: DiceIcon, }, { name: "Views", href: `/${workspaceSlug}/projects/${projectId}/views`, Icon: PhotoFilterIcon, }, { name: "Pages", href: `/${workspaceSlug}/projects/${projectId}/pages`, Icon: FileText, }, { name: "Inbox", href: `/${workspaceSlug}/projects/${projectId}/inbox`, Icon: Inbox, }, { name: "Settings", href: `/${workspaceSlug}/projects/${projectId}/settings`, Icon: Settings, }, ]; export const ProjectSidebarListItem: React.FC = observer((props) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { projectId, provided, snapshot, handleCopyText, shortContextMenu = false, disableDrag } = props; // store hooks const { theme: themeStore } = useApplication(); const { setTrackElement } = useEventTracker(); const { addProjectToFavorites, removeProjectFromFavorites, getProjectById } = useProject(); const { getInboxesByProjectId, getInboxById } = useInbox(); const { isMobile } = usePlatformOS(); // states const [leaveProjectModalOpen, setLeaveProjectModal] = useState(false); const [publishModalOpen, setPublishModal] = useState(false); const [isMenuActive, setIsMenuActive] = useState(false); // refs const actionSectionRef = useRef(null); // router const router = useRouter(); const { workspaceSlug, projectId: URLProjectId } = router.query; // derived values const project = getProjectById(projectId); const isCollapsed = themeStore.sidebarCollapsed; const inboxesMap = project?.inbox_view ? getInboxesByProjectId(projectId) : undefined; const inboxDetails = inboxesMap && inboxesMap.length > 0 ? getInboxById(inboxesMap[0]) : undefined; // auth const isAdmin = project?.member_role === EUserProjectRoles.ADMIN; const isViewerOrGuest = project?.member_role && [EUserProjectRoles.VIEWER, EUserProjectRoles.GUEST].includes(project.member_role); const handleAddToFavorites = () => { if (!workspaceSlug || !project) return; const addToFavoritePromise = addProjectToFavorites(workspaceSlug.toString(), project.id); setPromiseToast(addToFavoritePromise, { loading: "Adding project to favorites...", success: { title: "Success!", message: () => "Project added to favorites.", }, error: { title: "Error!", message: () => "Couldn't add the project to favorites. Please try again.", }, }); }; const handleRemoveFromFavorites = () => { if (!workspaceSlug || !project) return; const removeFromFavoritePromise = removeProjectFromFavorites(workspaceSlug.toString(), project.id); setPromiseToast(removeFromFavoritePromise, { loading: "Removing project from favorites...", success: { title: "Success!", message: () => "Project removed from favorites.", }, error: { title: "Error!", message: () => "Couldn't remove the project from favorites. Please try again.", }, }); }; const handleLeaveProject = () => { setTrackElement("APP_SIDEBAR_PROJECT_DROPDOWN"); setLeaveProjectModal(true); }; const handleLeaveProjectModalClose = () => { setLeaveProjectModal(false); }; const handleProjectClick = () => { if (window.innerWidth < 768) { themeStore.toggleSidebar(); } }; useOutsideClickDetector(actionSectionRef, () => setIsMenuActive(false)); if (!project) return null; return ( <> setPublishModal(false)} /> {({ open }) => ( <>
{provided && !disableDrag && ( )}
{!isCollapsed &&

{project.name}

}
{!isCollapsed && ( )}
{!isCollapsed && ( setIsMenuActive(!isMenuActive)} >
} className={cn("hidden flex-shrink-0 group-hover:block", { "!block": isMenuActive, })} buttonClassName="!text-custom-sidebar-text-400" ellipsis placement="bottom-start" > {!project.is_favorite && ( Add to favorites )} {project.is_favorite && ( Remove from favorites )} Copy project link {/* publish project settings */} {isAdmin && ( setPublishModal(true)}>
{project.is_deployed ? "Publish settings" : "Publish"}
)} {!isViewerOrGuest && (
Archived issues
)}
Draft issues
Settings
{/* leave project */} {isViewerOrGuest && (
Leave project
)} )} {navigation(workspaceSlug as string, project?.id).map((item) => { if ( (item.name === "Cycles" && !project.cycle_view) || (item.name === "Modules" && !project.module_view) || (item.name === "Views" && !project.issue_views_view) || (item.name === "Pages" && !project.page_view) || (item.name === "Inbox" && !project.inbox_view) ) return; return (
{item.name === "Inbox" && inboxDetails ? ( <>
{inboxDetails?.pending_issue_count > 0 && ( = 100, }, { "border-none bg-custom-primary-300 text-white": router.asPath.includes( item.href ), } )} > {getNumberCount(inboxDetails?.pending_issue_count)} )}
{!isCollapsed && item.name} ) : ( <> {!isCollapsed && item.name} )}
); })}
)}
); });