import { MouseEvent } from "react"; import Link from "next/link"; import { observer } from "mobx-react-lite"; import useSWR from "swr"; // hooks import { useApplication, useCycle, useIssues, useProject } from "hooks/store"; import useToast from "hooks/use-toast"; // ui import { SingleProgressStats } from "components/core"; import { AvatarGroup, Loader, Tooltip, LinearProgressIndicator, LayersIcon, StateGroupIcon, PriorityIcon, Avatar, CycleGroupIcon, } from "@plane/ui"; // components import ProgressChart from "components/core/sidebar/progress-chart"; import { ActiveCycleProgressStats } from "components/cycles"; import { StateDropdown } from "components/dropdowns"; // icons import { ArrowRight, CalendarCheck, CalendarDays, Star, Target } from "lucide-react"; // helpers import { renderFormattedDate, findHowManyDaysLeft, renderFormattedDateWithoutYear } from "helpers/date-time.helper"; import { truncateText } from "helpers/string.helper"; // types import { ICycle, TCycleGroups } from "@plane/types"; // constants import { EIssuesStoreType } from "constants/issue"; import { CYCLE_ISSUES_WITH_PARAMS } from "constants/fetch-keys"; import { CYCLE_STATE_GROUPS_DETAILS } from "constants/cycle"; interface IActiveCycleDetails { workspaceSlug: string; projectId: string; } export const ActiveCycleDetails: React.FC = observer((props) => { // props const { workspaceSlug, projectId } = props; // store hooks const { issues: { fetchActiveCycleIssues }, } = useIssues(EIssuesStoreType.CYCLE); const { commandPalette: { toggleCreateCycleModal }, } = useApplication(); const { fetchActiveCycle, currentProjectActiveCycleId, getActiveCycleById, addCycleToFavorites, removeCycleFromFavorites, } = useCycle(); const { currentProjectDetails } = useProject(); // toast alert const { setToastAlert } = useToast(); const { isLoading } = useSWR( workspaceSlug && projectId ? `PROJECT_ACTIVE_CYCLE_${projectId}` : null, workspaceSlug && projectId ? () => fetchActiveCycle(workspaceSlug, projectId) : null ); const activeCycle = currentProjectActiveCycleId ? getActiveCycleById(currentProjectActiveCycleId) : null; const { data: activeCycleIssues } = useSWR( workspaceSlug && projectId && currentProjectActiveCycleId ? CYCLE_ISSUES_WITH_PARAMS(currentProjectActiveCycleId, { priority: "urgent,high" }) : null, workspaceSlug && projectId && currentProjectActiveCycleId ? () => fetchActiveCycleIssues(workspaceSlug, projectId, currentProjectActiveCycleId) : null ); if (!activeCycle && isLoading) return ( ); if (!activeCycle) return (

No active cycle

); const endDate = new Date(activeCycle.end_date ?? ""); const startDate = new Date(activeCycle.start_date ?? ""); const groupedIssues: any = { backlog: activeCycle.backlog_issues, unstarted: activeCycle.unstarted_issues, started: activeCycle.started_issues, completed: activeCycle.completed_issues, cancelled: activeCycle.cancelled_issues, }; const cycleStatus = activeCycle.status.toLowerCase() as TCycleGroups; const handleAddToFavorites = (e: MouseEvent) => { e.preventDefault(); if (!workspaceSlug || !projectId) return; addCycleToFavorites(workspaceSlug?.toString(), projectId.toString(), activeCycle.id).catch(() => { setToastAlert({ type: "error", title: "Error!", message: "Couldn't add the cycle to favorites. Please try again.", }); }); }; const handleRemoveFromFavorites = (e: MouseEvent) => { e.preventDefault(); if (!workspaceSlug || !projectId) return; removeCycleFromFavorites(workspaceSlug?.toString(), projectId.toString(), activeCycle.id).catch(() => { setToastAlert({ type: "error", title: "Error!", message: "Couldn't add the cycle to favorites. Please try again.", }); }); }; const progressIndicatorData = CYCLE_STATE_GROUPS_DETAILS.map((group, index) => ({ id: index, name: group.title, value: activeCycle.total_issues > 0 ? ((activeCycle[group.key as keyof ICycle] as number) / activeCycle.total_issues) * 100 : 0, color: group.color, })); const daysLeft = findHowManyDaysLeft(activeCycle.end_date ?? new Date()); return (

{truncateText(activeCycle.name, 70)}

{`${daysLeft} ${daysLeft > 1 ? "days" : "day"} left`} {activeCycle.is_favorite ? ( ) : ( )}
{renderFormattedDate(startDate)}
{renderFormattedDate(endDate)}
{activeCycle.owned_by.avatar && activeCycle.owned_by.avatar !== "" ? ( {activeCycle.owned_by.display_name} ) : ( {activeCycle.owned_by.display_name.charAt(0)} )} {activeCycle.owned_by.display_name}
{activeCycle.assignees.length > 0 && (
{activeCycle.assignees.map((assignee) => ( ))}
)}
{activeCycle.total_issues} issues
{activeCycle.completed_issues} issues
View Cycle
Progress
{Object.keys(groupedIssues).map((group, index) => ( {group}
} completed={groupedIssues[group]} total={activeCycle.total_issues} /> ))}
High Priority Issues
{activeCycleIssues ? ( activeCycleIssues.length > 0 ? ( activeCycleIssues.map((issue: any) => (
{currentProjectDetails?.identifier}-{issue.sequence_id} {truncateText(issue.name, 30)}
{}} projectId={projectId?.toString() ?? ""} disabled={true} buttonVariant="background-with-text" /> {issue.target_date && (
{renderFormattedDateWithoutYear(issue.target_date)}
)}
)) ) : (
There are no high priority issues present in this cycle.
) ) : ( )}
Ideal
Current
Pending Issues -{" "} {activeCycle.total_issues - (activeCycle.completed_issues + activeCycle.cancelled_issues)}
); });