import { useState, FC, useRef, useEffect, useCallback } from "react"; import { useRouter } from "next/router"; import { DragDropContext, Draggable, DropResult, Droppable } from "@hello-pangea/dnd"; import { Disclosure, Transition } from "@headlessui/react"; import { observer } from "mobx-react-lite"; import { ChevronDown, ChevronRight, Plus } from "lucide-react"; // hooks import { useApplication, useEventTracker, useProject, useUser } from "hooks/store"; // ui import { TOAST_TYPE, setToast } from "@plane/ui"; // components import { CreateProjectModal, ProjectSidebarListItem } from "components/project"; // helpers import { copyUrlToClipboard } from "helpers/string.helper"; import { orderJoinedProjects } from "helpers/project.helper"; import { cn } from "helpers/common.helper"; // constants import { EUserWorkspaceRoles } from "constants/workspace"; import { IProject } from "@plane/types"; export const ProjectSidebarList: FC = observer(() => { // states const [isFavoriteProjectCreate, setIsFavoriteProjectCreate] = useState(false); const [isProjectModalOpen, setIsProjectModalOpen] = useState(false); const [isScrolled, setIsScrolled] = useState(false); // scroll animation state // refs const containerRef = useRef(null); const { theme: { sidebarCollapsed }, commandPalette: { toggleCreateProjectModal }, } = useApplication(); const { setTrackElement } = useEventTracker(); const { membership: { currentWorkspaceRole }, } = useUser(); const { getProjectById, joinedProjectIds: joinedProjects, favoriteProjectIds: favoriteProjects, updateProjectView, } = useProject(); // router const router = useRouter(); const { workspaceSlug } = router.query; const isAuthorizedUser = !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER; const handleCopyText = (projectId: string) => { copyUrlToClipboard(`${workspaceSlug}/projects/${projectId}/issues`).then(() => { setToast({ type: TOAST_TYPE.SUCCESS, title: "Link Copied!", message: "Project link copied to clipboard.", }); }); }; const onDragEnd = (result: DropResult) => { const { source, destination, draggableId } = result; if (!destination || !workspaceSlug) return; if (source.index === destination.index) return; const joinedProjectsList: IProject[] = []; joinedProjects.map((projectId) => { const _project = getProjectById(projectId); if (_project) joinedProjectsList.push(_project); }); if (joinedProjectsList.length <= 0) return; const updatedSortOrder = orderJoinedProjects(source.index, destination.index, draggableId, joinedProjectsList); if (updatedSortOrder != undefined) updateProjectView(workspaceSlug.toString(), draggableId, { sort_order: updatedSortOrder }).catch(() => { setToast({ type: TOAST_TYPE.ERROR, title: "Error!", message: "Something went wrong. Please try again.", }); }); }; const isCollapsed = sidebarCollapsed || false; /** * Implementing scroll animation styles based on the scroll length of the container */ useEffect(() => { const handleScroll = () => { if (containerRef.current) { const scrollTop = containerRef.current.scrollTop; setIsScrolled(scrollTop > 0); } }; const currentContainerRef = containerRef.current; if (currentContainerRef) { currentContainerRef.addEventListener("scroll", handleScroll); } return () => { if (currentContainerRef) { currentContainerRef.removeEventListener("scroll", handleScroll); } }; }, []); return ( <> {workspaceSlug && ( { setIsProjectModalOpen(false); }} setToFavorite={isFavoriteProjectCreate} workspaceSlug={workspaceSlug.toString()} /> )}
{(provided) => (
{favoriteProjects && favoriteProjects.length > 0 && ( {({ open }) => ( <> {!isCollapsed && (
Favorites {open ? ( ) : ( )} {isAuthorizedUser && ( )}
)} {favoriteProjects.map((projectId, index) => ( {(provided, snapshot) => (
handleCopyText(projectId)} shortContextMenu disableDrag />
)}
))}
{provided.placeholder} )}
)}
)}
{(provided) => (
{joinedProjects && joinedProjects.length > 0 && ( {({ open }) => ( <> {!isCollapsed && (
Your projects {open ? ( ) : ( )} {isAuthorizedUser && ( )}
)} {joinedProjects.map((projectId, index) => ( {(provided, snapshot) => (
handleCopyText(projectId)} />
)}
))}
{provided.placeholder} )}
)}
)}
{isAuthorizedUser && joinedProjects && joinedProjects.length === 0 && ( )}
); });