import React, { useEffect, useState } from "react"; import Link from "next/link"; import Image from "next/image"; import { useRouter } from "next/router"; import { mutate } from "swr"; // services import cyclesService from "services/cycles.service"; // hooks import useToast from "hooks/use-toast"; // ui import { CustomMenu, LinearProgressIndicator, Tooltip } from "components/ui"; // icons import { CalendarDaysIcon, ExclamationCircleIcon } from "@heroicons/react/20/solid"; import { TargetIcon, ContrastIcon, PersonRunningIcon, ArrowRightIcon, TriangleExclamationIcon, AlarmClockIcon, } from "components/icons"; import { LinkIcon, PencilIcon, StarIcon, TrashIcon } from "@heroicons/react/24/outline"; // helpers import { getDateRangeStatus, renderShortDateWithYearFormat, findHowManyDaysLeft, } from "helpers/date-time.helper"; import { copyTextToClipboard, truncateText } from "helpers/string.helper"; // types import { CompletedCyclesResponse, CurrentAndUpcomingCyclesResponse, DraftCyclesResponse, ICycle, } from "types"; // fetch-keys import { CYCLE_COMPLETE_LIST, CYCLE_CURRENT_AND_UPCOMING_LIST, CYCLE_DETAILS, CYCLE_DRAFT_LIST, } from "constants/fetch-keys"; import { type } from "os"; type TSingleStatProps = { cycle: ICycle; handleEditCycle: () => void; handleDeleteCycle: () => void; isCompleted?: boolean; }; const stateGroups = [ { key: "backlog_issues", title: "Backlog", color: "#dee2e6", }, { key: "unstarted_issues", title: "Unstarted", color: "#26b5ce", }, { key: "started_issues", title: "Started", color: "#f7ae59", }, { key: "cancelled_issues", title: "Cancelled", color: "#d687ff", }, { key: "completed_issues", title: "Completed", color: "#09a953", }, ]; type progress = { progress: number; }; function RadialProgressBar({ progress }: progress) { const [circumference, setCircumference] = useState(0); useEffect(() => { const radius = 40; const circumference = 2 * Math.PI * radius; setCircumference(circumference); }, []); const progressOffset = ((100 - progress) / 100) * circumference; return (
); } export const SingleCycleList: React.FC = ({ cycle, handleEditCycle, handleDeleteCycle, isCompleted = false, }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; const { setToastAlert } = useToast(); const cycleStatus = getDateRangeStatus(cycle.start_date, cycle.end_date); const endDate = new Date(cycle.end_date ?? ""); const startDate = new Date(cycle.start_date ?? ""); const handleAddToFavorites = () => { if (!workspaceSlug || !projectId || !cycle) return; switch (cycleStatus) { case "current": case "upcoming": mutate( CYCLE_CURRENT_AND_UPCOMING_LIST(projectId as string), (prevData) => ({ current_cycle: (prevData?.current_cycle ?? []).map((c) => ({ ...c, is_favorite: c.id === cycle.id ? true : c.is_favorite, })), upcoming_cycle: (prevData?.upcoming_cycle ?? []).map((c) => ({ ...c, is_favorite: c.id === cycle.id ? true : c.is_favorite, })), }), false ); break; case "completed": mutate( CYCLE_COMPLETE_LIST(projectId as string), (prevData) => ({ completed_cycles: (prevData?.completed_cycles ?? []).map((c) => ({ ...c, is_favorite: c.id === cycle.id ? true : c.is_favorite, })), }), false ); break; case "draft": mutate( CYCLE_DRAFT_LIST(projectId as string), (prevData) => ({ draft_cycles: (prevData?.draft_cycles ?? []).map((c) => ({ ...c, is_favorite: c.id === cycle.id ? true : c.is_favorite, })), }), false ); break; } mutate( CYCLE_DETAILS(projectId as string), (prevData: any) => (prevData ?? []).map((c: any) => ({ ...c, is_favorite: c.id === cycle.id ? true : c.is_favorite, })), false ); cyclesService .addCycleToFavorites(workspaceSlug as string, projectId as string, { cycle: cycle.id, }) .catch(() => { setToastAlert({ type: "error", title: "Error!", message: "Couldn't add the cycle to favorites. Please try again.", }); }); }; const handleRemoveFromFavorites = () => { if (!workspaceSlug || !projectId || !cycle) return; switch (cycleStatus) { case "current": case "upcoming": mutate( CYCLE_CURRENT_AND_UPCOMING_LIST(projectId as string), (prevData) => ({ current_cycle: (prevData?.current_cycle ?? []).map((c) => ({ ...c, is_favorite: c.id === cycle.id ? false : c.is_favorite, })), upcoming_cycle: (prevData?.upcoming_cycle ?? []).map((c) => ({ ...c, is_favorite: c.id === cycle.id ? false : c.is_favorite, })), }), false ); break; case "completed": mutate( CYCLE_COMPLETE_LIST(projectId as string), (prevData) => ({ completed_cycles: (prevData?.completed_cycles ?? []).map((c) => ({ ...c, is_favorite: c.id === cycle.id ? false : c.is_favorite, })), }), false ); break; case "draft": mutate( CYCLE_DRAFT_LIST(projectId as string), (prevData) => ({ draft_cycles: (prevData?.draft_cycles ?? []).map((c) => ({ ...c, is_favorite: c.id === cycle.id ? false : c.is_favorite, })), }), false ); break; } mutate( CYCLE_DETAILS(projectId as string), (prevData: any) => (prevData ?? []).map((c: any) => ({ ...c, is_favorite: c.id === cycle.id ? false : c.is_favorite, })), false ); cyclesService .removeCycleFromFavorites(workspaceSlug as string, projectId as string, cycle.id) .catch(() => { setToastAlert({ type: "error", title: "Error!", message: "Couldn't remove the cycle from favorites. Please try again.", }); }); }; const handleCopyText = () => { const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; copyTextToClipboard( `${originURL}/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}` ).then(() => { setToastAlert({ type: "success", title: "Link Copied!", message: "Cycle link copied to clipboard.", }); }); }; const progressIndicatorData = stateGroups.map((group, index) => ({ id: index, name: group.title, value: cycle.total_issues > 0 ? ((cycle[group.key as keyof ICycle] as number) / cycle.total_issues) * 100 : 0, color: group.color, })); return (

{truncateText(cycle.name, 70)}

{cycle.description}

{cycleStatus === "current" ? ( {findHowManyDaysLeft(cycle.end_date ?? new Date())} Days Left ) : cycleStatus === "upcoming" ? ( {findHowManyDaysLeft(cycle.start_date ?? new Date())} Days Left ) : cycleStatus === "completed" ? ( {cycle.total_issues - cycle.completed_issues > 0 && ( )}{" "} Completed ) : ( cycleStatus )} {cycleStatus !== "draft" && (
{renderShortDateWithYearFormat(startDate)}
{renderShortDateWithYearFormat(endDate)}
)}
{cycle.owned_by.avatar && cycle.owned_by.avatar !== "" ? ( {cycle.owned_by.first_name} ) : ( {cycle.owned_by.first_name.charAt(0)} )}
Progress
} > {cycleStatus === "current" ? ( {Math.floor((cycle.completed_issues / cycle.total_issues) * 100)} % ) : cycleStatus === "upcoming" ? ( Yet to start ) : cycleStatus === "completed" ? ( {100} % ) : ( {cycleStatus} )} {cycle.is_favorite ? ( ) : ( )}
{!isCompleted && ( { e.preventDefault(); handleEditCycle(); }} > Edit Cycle )} {!isCompleted && ( { e.preventDefault(); handleDeleteCycle(); }} > Delete cycle )} { e.preventDefault(); handleCopyText(); }} > Copy cycle link
); };