Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions apps/app/components/core/sidebar/progress-chart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from "react";

import {
XAxis,
YAxis,
Tooltip,
ResponsiveContainer,
AreaChart,
Area,
ReferenceLine,
} from "recharts";

//types
import { IIssue } from "types";
// helper
import { getDatesInRange, renderShortNumericDateFormat } from "helpers/date-time.helper";

type Props = {
issues: IIssue[];
start: string;
end: string;
};

const ProgressChart: React.FC<Props> = ({ issues, start, end }) => {
const startDate = new Date(start);
const endDate = new Date(end);
const getChartData = () => {
const dateRangeArray = getDatesInRange(startDate, endDate);
let count = 0;
const dateWiseData = dateRangeArray.map((d) => {
const current = d.toISOString().split("T")[0];
const total = issues.length;
const currentData = issues.filter(
(i) => i.completed_at && i.completed_at.toString().split("T")[0] === current
);
count = currentData ? currentData.length + count : count;

return {
currentDate: renderShortNumericDateFormat(current),
currentDateData: currentData,
pending: new Date(current) < new Date() ? total - count : null,
};
});
return dateWiseData;
};
const ChartData = getChartData();
return (
<div className="relative h-[200px] w-full ">
<div className="flex items-center justify-center h-full w-full absolute -left-8 py-3 text-xs">
<ResponsiveContainer width="100%" height="100%">
<AreaChart
width={300}
height={200}
data={ChartData}
margin={{
top: 0,
right: 0,
left: 0,
bottom: 0,
}}
>
<XAxis dataKey="currentDate" />
<YAxis />
<Tooltip />
<Area
type="monotone"
dataKey="pending"
stroke="#8884d8"
fill="#98d1fb"
activeDot={{ r: 8 }}
/>
<ReferenceLine
stroke="#16a34a"
strokeDasharray="3 3"
segment={[
{ x: `${renderShortNumericDateFormat(endDate)}`, y: 0 },
{ x: `${renderShortNumericDateFormat(startDate)}`, y: issues.length },
]}
/>
</AreaChart>
</ResponsiveContainer>
</div>
<div className="z-10 flex flex-col absolute top-2 right-2 justify-center items-start gap-1 text-xs">
<div className="flex justify-center items-center gap-2">
<span className="h-2 w-2 bg-green-600" />
<span>Ideal</span>
</div>
<div className="flex justify-center items-center gap-2">
<span className="h-2 w-2 bg-[#8884d8]" />
<span>Current</span>
</div>
</div>
</div>
);
};

export default ProgressChart;
236 changes: 117 additions & 119 deletions apps/app/components/core/sidebar/sidebar-progress-stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,130 +53,128 @@ export const SidebarProgressStats: React.FC<Props> = ({ groupedIssues, issues })
: null
);
return (
<div className="flex flex-col items-center justify-center w-full gap-2 ">
<Tab.Group>
<Tab.List
as="div"
className="flex items-center justify-between w-full rounded bg-gray-100 text-xs"
<Tab.Group>
<Tab.List
as="div"
className="flex items-center justify-between w-full rounded bg-gray-100 text-xs"
>
<Tab
className={({ selected }) =>
`w-1/2 rounded py-1 ${selected ? "bg-gray-300" : "hover:bg-gray-200"}`
}
>
<Tab
className={({ selected }) =>
`w-1/2 rounded py-1 ${selected ? "bg-gray-300" : "hover:bg-gray-200"}`
}
>
Assignees
</Tab>
<Tab
className={({ selected }) =>
`w-1/2 rounded py-1 ${selected ? "bg-gray-300 font-semibold" : "hover:bg-gray-200 "}`
}
>
Labels
</Tab>
<Tab
className={({ selected }) =>
`w-1/2 rounded py-1 ${selected ? "bg-gray-300 font-semibold" : "hover:bg-gray-200 "}`
Assignees
</Tab>
<Tab
className={({ selected }) =>
`w-1/2 rounded py-1 ${selected ? "bg-gray-300 font-semibold" : "hover:bg-gray-200 "}`
}
>
Labels
</Tab>
<Tab
className={({ selected }) =>
`w-1/2 rounded py-1 ${selected ? "bg-gray-300 font-semibold" : "hover:bg-gray-200 "}`
}
>
States
</Tab>
</Tab.List>
<Tab.Panels className="flex items-center justify-between w-full">
<Tab.Panel as="div" className="w-full flex flex-col ">
{members?.map((member, index) => {
const totalArray = issues?.filter((i) => i.assignees?.includes(member.member.id));
const completeArray = totalArray?.filter((i) => i.state_detail.group === "completed");
if (totalArray.length > 0) {
return (
<SingleProgressStats
key={index}
title={
<>
<Avatar user={member.member} />
<span>{member.member.first_name}</span>
</>
}
completed={completeArray.length}
total={totalArray.length}
/>
);
}
>
States
</Tab>
</Tab.List>
<Tab.Panels className="flex items-center justify-between w-full">
<Tab.Panel as="div" className="w-full flex flex-col ">
{members?.map((member, index) => {
const totalArray = issues?.filter((i) => i.assignees?.includes(member.member.id));
const completeArray = totalArray?.filter((i) => i.state_detail.group === "completed");
if (totalArray.length > 0) {
return (
<SingleProgressStats
key={index}
title={
<>
<Avatar user={member.member} />
<span>{member.member.first_name}</span>
</>
}
completed={completeArray.length}
total={totalArray.length}
/>
);
})}
{issues?.filter((i) => i.assignees?.length === 0).length > 0 ? (
<SingleProgressStats
title={
<>
<div className="h-5 w-5 rounded-full border-2 border-white bg-white">
<Image
src={User}
height="100%"
width="100%"
className="rounded-full"
alt="User"
/>
</div>
<span>No assignee</span>
</>
}
completed={
issues?.filter(
(i) => i.state_detail.group === "completed" && i.assignees?.length === 0
).length
}
})}
{issues?.filter((i) => i.assignees?.length === 0).length > 0 ? (
<SingleProgressStats
title={
<>
<div className="h-5 w-5 rounded-full border-2 border-white bg-white">
<Image
src={User}
height="100%"
width="100%"
className="rounded-full"
alt="User"
total={issues?.filter((i) => i.assignees?.length === 0).length}
/>
) : (
""
)}
</Tab.Panel>
<Tab.Panel as="div" className="w-full flex flex-col ">
{issueLabels?.map((issue, index) => {
const totalArray = issues?.filter((i) => i.labels?.includes(issue.id));
const completeArray = totalArray?.filter((i) => i.state_detail.group === "completed");
if (totalArray.length > 0) {
return (
<SingleProgressStats
key={index}
title={
<>
<span
className="block h-2 w-2 rounded-full "
style={{
backgroundColor: issue.color,
}}
/>
</div>
<span>No assignee</span>
</>
}
completed={
issues?.filter(
(i) => i.state_detail.group === "completed" && i.assignees?.length === 0
).length
}
total={issues?.filter((i) => i.assignees?.length === 0).length}
/>
) : (
""
)}
</Tab.Panel>
<Tab.Panel as="div" className="w-full flex flex-col ">
{issueLabels?.map((issue, index) => {
const totalArray = issues?.filter((i) => i.labels?.includes(issue.id));
const completeArray = totalArray?.filter((i) => i.state_detail.group === "completed");
if (totalArray.length > 0) {
return (
<SingleProgressStats
key={index}
title={
<>
<span
className="block h-2 w-2 rounded-full "
style={{
backgroundColor: issue.color,
}}
/>
<span className="text-xs capitalize">{issue.name}</span>
</>
}
completed={completeArray.length}
total={totalArray.length}
<span className="text-xs capitalize">{issue.name}</span>
</>
}
completed={completeArray.length}
total={totalArray.length}
/>
);
}
})}
</Tab.Panel>
<Tab.Panel as="div" className="w-full flex flex-col ">
{Object.keys(groupedIssues).map((group, index) => (
<SingleProgressStats
key={index}
title={
<>
<span
className="block h-2 w-2 rounded-full "
style={{
backgroundColor: stateGroupColours[group],
}}
/>
);
<span className="text-xs capitalize">{group}</span>
</>
}
})}
</Tab.Panel>
<Tab.Panel as="div" className="w-full flex flex-col ">
{Object.keys(groupedIssues).map((group, index) => (
<SingleProgressStats
key={index}
title={
<>
<span
className="block h-2 w-2 rounded-full "
style={{
backgroundColor: stateGroupColours[group],
}}
/>
<span className="text-xs capitalize">{group}</span>
</>
}
completed={groupedIssues[group].length}
total={issues.length}
/>
))}
</Tab.Panel>
</Tab.Panels>
</Tab.Group>
</div>
completed={groupedIssues[group].length}
total={issues.length}
/>
))}
</Tab.Panel>
</Tab.Panels>
</Tab.Group>
);
};
9 changes: 8 additions & 1 deletion apps/app/components/modules/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { groupBy } from "helpers/array.helper";
import { IIssue, IModule, ModuleIssueResponse } from "types";
// fetch-keys
import { MODULE_DETAILS } from "constants/fetch-keys";
import ProgressChart from "components/core/sidebar/progress-chart";

const defaultValues: Partial<IModule> = {
lead: "",
Expand Down Expand Up @@ -295,7 +296,13 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({
</div>
</div>
</div>
<div className="w-full">
<div className="flex flex-col items-center justify-center w-full gap-2 ">
<ProgressChart
issues={issues}
start={module?.start_date ?? ""}
end={module?.target_date ?? ""}
/>

<SidebarProgressStats issues={issues} groupedIssues={groupedIssues} />
</div>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { renderShortNumericDateFormat } from "helpers/date-time.helper";
import { CycleIssueResponse, ICycle, IIssue } from "types";
// fetch-keys
import { CYCLE_DETAILS } from "constants/fetch-keys";
import ProgressChart from "components/core/sidebar/progress-chart";

type Props = {
issues: IIssue[];
Expand Down Expand Up @@ -246,7 +247,14 @@ const CycleDetailSidebar: React.FC<Props> = ({ issues, cycle, isOpen, cycleIssue
</div>
<div className="py-1" />
</div>
<div className="w-full">
<div className="flex flex-col items-center justify-center w-full gap-2 ">
<div className="relative h-[200px] w-full ">
<ProgressChart
issues={issues}
start={cycle?.start_date ?? ""}
end={cycle?.end_date ?? ""}
/>
</div>
<SidebarProgressStats issues={issues} groupedIssues={groupedIssues} />
</div>
</>
Expand Down
Loading