import React, { useEffect, useState } from "react"; // next import { useRouter } from "next/router"; import type { NextPage } from "next"; // swr import useSWR, { mutate } from "swr"; // services import issuesServices from "lib/services/issues.services"; import sprintService from "lib/services/cycles.services"; // hooks import useUser from "lib/hooks/useUser"; // fetching keys import { CYCLE_ISSUES, CYCLE_LIST } from "constants/fetch-keys"; // layouts import ProjectLayout from "layouts/ProjectLayout"; // components import SprintView from "components/project/cycles/CycleView"; import ConfirmIssueDeletion from "components/project/issues/ConfirmIssueDeletion"; import ConfirmSprintDeletion from "components/project/cycles/ConfirmCycleDeletion"; import CreateUpdateIssuesModal from "components/project/issues/CreateUpdateIssueModal"; import CreateUpdateSprintsModal from "components/project/cycles/CreateUpdateCyclesModal"; // ui import { Spinner } from "ui"; // icons import { PlusIcon } from "@heroicons/react/20/solid"; // types import { IIssue, ICycle, SelectSprintType, SelectIssue } from "types"; import { EmptySpace, EmptySpaceItem } from "ui/EmptySpace"; import { ArrowPathIcon } from "@heroicons/react/24/outline"; import HeaderButton from "ui/HeaderButton"; import { BreadcrumbItem, Breadcrumbs } from "ui/Breadcrumbs"; const ProjectSprints: NextPage = () => { const [isOpen, setIsOpen] = useState(false); const [selectedSprint, setSelectedSprint] = useState<SelectSprintType>(); const [isIssueModalOpen, setIsIssueModalOpen] = useState(false); const [selectedIssues, setSelectedIssues] = useState<SelectIssue>(); const [deleteIssue, setDeleteIssue] = useState<string | undefined>(); const { activeWorkspace, activeProject } = useUser(); const router = useRouter(); const { projectId } = router.query; const { data: sprints } = useSWR<ICycle[]>( projectId && activeWorkspace ? CYCLE_LIST(projectId as string) : null, activeWorkspace && projectId ? () => sprintService.getCycles(activeWorkspace.slug, projectId as string) : null ); const openIssueModal = ( sprintId: string, issue?: IIssue, actionType: "create" | "edit" | "delete" = "create" ) => { const sprint = sprints?.find((sprint) => sprint.id === sprintId); if (sprint) { setSelectedSprint({ ...sprint, actionType: "create-issue", }); if (issue) setSelectedIssues({ ...issue, actionType }); setIsIssueModalOpen(true); } }; const addIssueToSprint = (sprintId: string, issueId: string) => { if (!activeWorkspace || !projectId) return; issuesServices .addIssueToSprint(activeWorkspace.slug, projectId as string, sprintId, { issue: issueId, }) .then((response) => { console.log(response); mutate(CYCLE_ISSUES(sprintId)); }) .catch((error) => { console.log(error); }); }; useEffect(() => { if (isOpen) return; const timer = setTimeout(() => { setSelectedSprint(undefined); clearTimeout(timer); }, 500); }, [isOpen]); useEffect(() => { if (selectedIssues?.actionType === "delete") { setDeleteIssue(selectedIssues.id); } }, [selectedIssues]); return ( <ProjectLayout meta={{ title: "Plane - Cycles", }} > <CreateUpdateSprintsModal isOpen={ isOpen && selectedSprint?.actionType !== "delete" && selectedSprint?.actionType !== "create-issue" } setIsOpen={setIsOpen} data={selectedSprint} projectId={projectId as string} /> <ConfirmSprintDeletion isOpen={isOpen && !!selectedSprint && selectedSprint.actionType === "delete"} setIsOpen={setIsOpen} data={selectedSprint} /> <ConfirmIssueDeletion handleClose={() => setDeleteIssue(undefined)} isOpen={!!deleteIssue} data={selectedIssues} /> <CreateUpdateIssuesModal isOpen={ isIssueModalOpen && selectedSprint?.actionType === "create-issue" && selectedIssues?.actionType !== "delete" } data={selectedIssues} prePopulateData={{ sprints: selectedSprint?.id }} setIsOpen={setIsOpen} projectId={projectId as string} /> <div className="w-full h-full flex flex-col space-y-5"> {sprints ? ( sprints.length > 0 ? ( <div className="flex flex-col items-center justify-center w-full h-full px-2"> <div className="w-full h-full flex flex-col space-y-5"> <Breadcrumbs> <BreadcrumbItem title="Projects" link="/projects" /> <BreadcrumbItem title={`${activeProject?.name} Cycles`} /> </Breadcrumbs> <div className="flex items-center justify-between cursor-pointer w-full"> <h2 className="text-2xl font-medium">Project Cycle</h2> <HeaderButton Icon={PlusIcon} label="Add Cycle" action={() => setIsOpen(true)} /> </div> <div className="w-full h-full pr-2 overflow-auto"> {sprints.map((sprint) => ( <SprintView sprint={sprint} selectSprint={setSelectedSprint} projectId={projectId as string} workspaceSlug={activeWorkspace?.slug as string} openIssueModal={openIssueModal} addIssueToSprint={addIssueToSprint} key={sprint.id} /> ))} </div> </div> </div> ) : ( <> <div className="w-full h-full flex flex-col justify-center items-center px-4"> <EmptySpace title="You don't have any cycle yet." description="A cycle is a fixed time period where a team commits to a set number of issues from their backlog. Cycles are usually one, two, or four weeks long." Icon={ArrowPathIcon} > <EmptySpaceItem title="Create a new cycle" description={ <span> Use{" "} <pre className="inline bg-gray-100 px-2 py-1 rounded">Ctrl/Command + Q</pre>{" "} shortcut to create a new cycle </span> } Icon={PlusIcon} action={() => setIsOpen(true)} /> </EmptySpace> </div> </> ) ) : ( <div className="w-full h-full flex justify-center items-center"> <Spinner /> </div> )} </div> </ProjectLayout> ); }; export default ProjectSprints;