import React, { useRef } from "react"; import { observer } from "mobx-react-lite"; import { useRouter } from "next/router"; // icons import { Check, Info } from "lucide-react"; // ui import { CircularProgressIndicator } from "@plane/ui"; // components import { ListItem } from "@/components/core/list"; import { ModuleListItemAction } from "@/components/modules"; // constants import { EEstimateSystem } from "@/constants/estimates"; // hooks import { useAppRouter, useModule, useProjectEstimates } from "@/hooks/store"; import { usePlatformOS } from "@/hooks/use-platform-os"; type Props = { moduleId: string; }; export const ModuleListItem: React.FC = observer((props) => { const { moduleId } = props; // refs const parentRef = useRef(null); // router const router = useRouter(); const { workspaceSlug } = router.query; // store hooks const { getModuleById } = useModule(); const { isMobile } = usePlatformOS(); const { projectId } = useAppRouter(); const { currentActiveEstimateId, areEstimateEnabledByProjectId, estimateById } = useProjectEstimates(); // derived values const moduleDetails = getModuleById(moduleId); if (!moduleDetails) return null; /** * NOTE: This completion percentage calculation is based on the total issues count. * when estimates are available and estimate type is points, we should consider the estimate point count * when estimates are available and estimate type is not points, then by default we consider the issue count */ const isEstimateEnabled = projectId && currentActiveEstimateId && areEstimateEnabledByProjectId(projectId) && estimateById(currentActiveEstimateId)?.type === EEstimateSystem.POINTS; const completionPercentage = isEstimateEnabled ? ((moduleDetails?.completed_estimate_points || 0) / (moduleDetails?.total_estimate_points || 0)) * 100 : ((moduleDetails.completed_issues + moduleDetails.cancelled_issues) / moduleDetails.total_issues) * 100; const progress = isNaN(completionPercentage) ? 0 : Math.floor(completionPercentage); const completedModuleCheck = moduleDetails.status === "completed"; // handlers const openModuleOverview = (e: React.MouseEvent) => { e.stopPropagation(); e.preventDefault(); const { query } = router; if (query.peekModule) { delete query.peekModule; router.push({ pathname: router.pathname, query: { ...query }, }); } else { router.push({ pathname: router.pathname, query: { ...query, peekModule: moduleId }, }); } }; const handleArchivedModuleClick = (e: React.MouseEvent) => { openModuleOverview(e); }; const handleItemClick = moduleDetails.archived_at ? handleArchivedModuleClick : undefined; return ( {completedModuleCheck ? ( progress === 100 ? ( ) : ( {`!`} ) ) : progress === 100 ? ( ) : ( {`${progress}%`} )} } appendTitleElement={ } actionableItems={} isMobile={isMobile} parentRef={parentRef} /> ); });