[WEB-2380] chore: cycle sidebar refactor (#5759)

* chore: cycle sidebar refactor

* chore: code splitting

* chore: code refactor

* chore: code refactor
This commit is contained in:
Anmol Singh Bhatia 2024-10-08 16:54:44 +05:30 committed by GitHub
parent b27249486a
commit f73a603226
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 99 additions and 88 deletions

View file

@ -0,0 +1,69 @@
"use client";
import { FC, Fragment } from "react";
import { observer } from "mobx-react";
// plane ui
import { Loader } from "@plane/ui";
// components
import ProgressChart from "@/components/core/sidebar/progress-chart";
import { validateCycleSnapshot } from "@/components/cycles";
// helpers
import { getDate } from "@/helpers/date-time.helper";
// hooks
import { useCycle } from "@/hooks/store";
type ProgressChartProps = {
workspaceSlug: string;
projectId: string;
cycleId: string;
};
export const SidebarChart: FC<ProgressChartProps> = observer((props) => {
const { workspaceSlug, projectId, cycleId } = props;
// hooks
const { getEstimateTypeByCycleId, getCycleById } = useCycle();
// derived data
const cycleDetails = validateCycleSnapshot(getCycleById(cycleId));
const cycleStartDate = getDate(cycleDetails?.start_date);
const cycleEndDate = getDate(cycleDetails?.end_date);
const totalEstimatePoints = cycleDetails?.total_estimate_points || 0;
const totalIssues = cycleDetails?.total_issues || 0;
const estimateType = getEstimateTypeByCycleId(cycleId);
const chartDistributionData =
estimateType === "points" ? cycleDetails?.estimate_distribution : cycleDetails?.distribution || undefined;
const completionChartDistributionData = chartDistributionData?.completion_chart || undefined;
if (!workspaceSlug || !projectId || !cycleId) return null;
return (
<div>
<div className="relative flex items-center gap-2">
<div className="flex items-center justify-center gap-1 text-xs">
<span className="h-2.5 w-2.5 rounded-full bg-[#A9BBD0]" />
<span>Ideal</span>
</div>
<div className="flex items-center justify-center gap-1 text-xs">
<span className="h-2.5 w-2.5 rounded-full bg-[#4C8FFF]" />
<span>Current</span>
</div>
</div>
{cycleStartDate && cycleEndDate && completionChartDistributionData ? (
<Fragment>
<ProgressChart
distribution={completionChartDistributionData}
startDate={cycleStartDate}
endDate={cycleEndDate}
totalIssues={estimateType === "points" ? totalEstimatePoints : totalIssues}
plotTitle={estimateType === "points" ? "points" : "issues"}
/>
</Fragment>
) : (
<Loader className="w-full h-[160px] mt-4">
<Loader.Item width="100%" height="100%" />
</Loader>
)}
</div>
);
});

View file

@ -1 +1 @@
export * from "./sidebar-chart";
export * from "./root";

View file

@ -0,0 +1,12 @@
"use client";
import React, { FC } from "react";
// components
import { SidebarChart } from "./base";
type Props = {
workspaceSlug: string;
projectId: string;
cycleId: string;
};
export const SidebarChartRoot: FC<Props> = (props) => <SidebarChart {...props} />;

View file

@ -1,57 +0,0 @@
import { Fragment } from "react";
import { TCycleDistribution, TCycleEstimateDistribution } from "@plane/types";
import { Loader } from "@plane/ui";
import ProgressChart from "@/components/core/sidebar/progress-chart";
type ProgressChartProps = {
chartDistributionData: TCycleEstimateDistribution | TCycleDistribution | undefined;
cycleStartDate: Date | undefined;
cycleEndDate: Date | undefined;
totalEstimatePoints: number;
totalIssues: number;
plotType: string;
};
export const SidebarBaseChart = (props: ProgressChartProps) => {
const { chartDistributionData, cycleStartDate, cycleEndDate, totalEstimatePoints, totalIssues, plotType } = props;
const completionChartDistributionData = chartDistributionData?.completion_chart || undefined;
return (
<div>
<div className="relative flex items-center gap-2">
<div className="flex items-center justify-center gap-1 text-xs">
<span className="h-2.5 w-2.5 rounded-full bg-[#A9BBD0]" />
<span>Ideal</span>
</div>
<div className="flex items-center justify-center gap-1 text-xs">
<span className="h-2.5 w-2.5 rounded-full bg-[#4C8FFF]" />
<span>Current</span>
</div>
</div>
{cycleStartDate && cycleEndDate && completionChartDistributionData ? (
<Fragment>
{plotType === "points" ? (
<ProgressChart
distribution={completionChartDistributionData}
startDate={cycleStartDate}
endDate={cycleEndDate}
totalIssues={totalEstimatePoints}
plotTitle={"points"}
/>
) : (
<ProgressChart
distribution={completionChartDistributionData}
startDate={cycleStartDate}
endDate={cycleEndDate}
totalIssues={totalIssues}
plotTitle={"issues"}
/>
)}
</Fragment>
) : (
<Loader className="w-full h-[160px] mt-4">
<Loader.Item width="100%" height="100%" />
</Loader>
)}
</div>
);
};

View file

@ -1,6 +1,6 @@
"use client";
import { FC, Fragment, useCallback, useMemo, useState } from "react";
import { FC, Fragment, useCallback, useMemo } from "react";
import isEmpty from "lodash/isEmpty";
import isEqual from "lodash/isEqual";
import { observer } from "mobx-react";
@ -16,10 +16,9 @@ import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
// helpers
import { getDate } from "@/helpers/date-time.helper";
// hooks
import { useIssues, useCycle, useProjectEstimates } from "@/hooks/store";
// plane web constants
import { SidebarBaseChart } from "@/plane-web/components/cycles/analytics-sidebar";
import { EEstimateSystem } from "@/plane-web/constants/estimates";
import { useIssues, useCycle } from "@/hooks/store";
// plane web components
import { SidebarChartRoot } from "@/plane-web/components/cycles";
type TCycleAnalyticsProgress = {
workspaceSlug: string;
@ -27,7 +26,7 @@ type TCycleAnalyticsProgress = {
cycleId: string;
};
const validateCycleSnapshot = (cycleDetails: ICycle | null): ICycle | null => {
export const validateCycleSnapshot = (cycleDetails: ICycle | null): ICycle | null => {
if (!cycleDetails || cycleDetails === null) return cycleDetails;
const updatedCycleDetails: any = { ...cycleDetails };
@ -60,12 +59,9 @@ export const CycleAnalyticsProgress: FC<TCycleAnalyticsProgress> = observer((pro
// router
const searchParams = useSearchParams();
const peekCycle = searchParams.get("peekCycle") || undefined;
// hooks
const { areEstimateEnabledByProjectId, currentActiveEstimateId, estimateById } = useProjectEstimates();
const {
getPlotTypeByCycleId,
getEstimateTypeByCycleId,
setPlotType,
getCycleById,
fetchCycleDetails,
fetchArchivedCycleDetails,
@ -74,17 +70,11 @@ export const CycleAnalyticsProgress: FC<TCycleAnalyticsProgress> = observer((pro
const {
issuesFilter: { issueFilters, updateFilters },
} = useIssues(EIssuesStoreType.CYCLE);
// state
const [loader, setLoader] = useState(false);
// derived values
const cycleDetails = validateCycleSnapshot(getCycleById(cycleId));
const plotType: TCyclePlotType = getPlotTypeByCycleId(cycleId);
const estimateType = getEstimateTypeByCycleId(cycleId);
const isCurrentProjectEstimateEnabled = projectId && areEstimateEnabledByProjectId(projectId) ? true : false;
const estimateDetails =
isCurrentProjectEstimateEnabled && currentActiveEstimateId && estimateById(currentActiveEstimateId);
const isCurrentEstimateTypeIsPoints = estimateDetails && estimateDetails?.type === EEstimateSystem.POINTS;
const completedIssues = cycleDetails?.completed_issues || 0;
const totalIssues = cycleDetails?.total_issues || 0;
@ -132,15 +122,13 @@ export const CycleAnalyticsProgress: FC<TCycleAnalyticsProgress> = observer((pro
setEstimateType(cycleId, value);
if (!workspaceSlug || !projectId || !cycleId) return;
try {
setLoader(true);
if (isArchived) {
await fetchArchivedCycleDetails(workspaceSlug, projectId, cycleId);
} else {
await fetchCycleDetails(workspaceSlug, projectId, cycleId);
}
setLoader(false);
} catch (error) {
setLoader(false);
} catch (err) {
console.error(err);
setEstimateType(cycleId, estimateType);
}
};
@ -218,16 +206,15 @@ export const CycleAnalyticsProgress: FC<TCycleAnalyticsProgress> = observer((pro
</CustomSelect.Option>
))}
</CustomSelect>
<div className="flex items-center justify-center gap-2">
<div className="flex items-center gap-1 text-xs">
<span className="text-custom-text-300">Done</span>
<span className="font-semibold text-custom-text-400">{progressHeaderPercentage}%</span>
</div>
</div>
</div>
<div className="py-4">
<SidebarBaseChart
chartDistributionData={chartDistributionData}
cycleStartDate={cycleStartDate}
cycleEndDate={cycleEndDate}
totalEstimatePoints={totalEstimatePoints}
totalIssues={totalIssues}
plotType={plotType}
/>
<SidebarChartRoot workspaceSlug={workspaceSlug} projectId={projectId} cycleId={cycleId} />
</div>
{/* progress detailed view */}
{chartDistributionData && (

View file

@ -3,10 +3,10 @@ import React, { FC } from "react";
import isEmpty from "lodash/isEmpty";
import { observer } from "mobx-react";
import { LayersIcon, SquareUser, Users } from "lucide-react";
// ui
import { ICycle } from "@plane/types";
import { Avatar, AvatarGroup, TextArea } from "@plane/ui";
// types
import { ICycle } from "@plane/types";
// ui
import { Avatar, AvatarGroup, TextArea } from "@plane/ui";
// hooks
import { useMember, useProjectEstimates } from "@/hooks/store";
// plane web