style: cycle sidebar, fix: cycle card bug fix (#383)

* style: new cycle sidebar

* style: other information section

* style: progress bar bg fix

* fix: cycle card bug fix

* style: progress chart

* style: chart tooltip
This commit is contained in:
Anmol Singh Bhatia 2023-03-07 13:43:09 +05:30 committed by GitHub
parent 64978969a0
commit 0246e0585b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 395 additions and 280 deletions

View File

@ -1,17 +1,10 @@
import React from "react"; import React from "react";
import { import { XAxis, YAxis, Tooltip, AreaChart, Area, ReferenceLine, TooltipProps} from "recharts";
XAxis,
YAxis,
Tooltip,
ResponsiveContainer,
AreaChart,
Area,
ReferenceLine,
} from "recharts";
//types //types
import { IIssue } from "types"; import { IIssue } from "types";
import { NameType, ValueType } from "recharts/types/component/DefaultTooltipContent";
// helper // helper
import { getDatesInRange, renderShortNumericDateFormat } from "helpers/date-time.helper"; import { getDatesInRange, renderShortNumericDateFormat } from "helpers/date-time.helper";
@ -43,53 +36,69 @@ const ProgressChart: React.FC<Props> = ({ issues, start, end }) => {
}); });
return dateWiseData; return dateWiseData;
}; };
const CustomTooltip = ({ active, payload }: TooltipProps<ValueType, NameType>) => {
if (active && payload && payload.length) {
console.log(payload[0].payload.currentDate);
return (
<div className="rounded-sm bg-gray-300 p-1 text-xs text-gray-800">
<p>{payload[0].payload.currentDate}</p>
</div>
);
}
return null;
};
const ChartData = getChartData(); const ChartData = getChartData();
return ( return (
<div className="relative h-[200px] w-full "> <div className="absolute -left-12 flex h-full w-full items-center justify-center text-xs">
<div className="flex justify-start items-start gap-4 text-xs"> <AreaChart
<div className="flex justify-center items-center gap-1"> width={360}
<span className="h-2 w-2 bg-green-600 rounded-full" /> height={160}
<span>Ideal</span> data={ChartData}
</div> margin={{
<div className="flex justify-center items-center gap-1"> top: 12,
<span className="h-2 w-2 bg-[#8884d8] rounded-full" /> right: 12,
<span>Current</span> left: 0,
</div> bottom: 12,
</div> }}
<div className="flex items-center justify-center h-full w-full absolute -left-8 py-3 text-xs"> >
<ResponsiveContainer width="100%" height="100%"> <defs>
<AreaChart <linearGradient id="linearblue" x1="0" y1="0" x2="0" y2="1">
width={300} <stop offset="0%" stopColor="#3F76FF" stopOpacity={0.7} />
height={200} <stop offset="50%" stopColor="#3F76FF" stopOpacity={0.1} />
data={ChartData} <stop offset="100%" stopColor="#3F76FF" stopOpacity={0} />
margin={{ </linearGradient>
top: 0, </defs>
right: 0, <XAxis
left: 0, dataKey="currentDate"
bottom: 0, stroke="#9ca3af"
}} tick={{ fontSize: "12px", fill: "#1f2937" }}
> tickSize={10}
<XAxis dataKey="currentDate" /> minTickGap={10}
<YAxis /> />
<Tooltip /> <YAxis
<Area stroke="#9ca3af"
type="monotone" tick={{ fontSize: "12px", fill: "#1f2937" }}
dataKey="pending" tickSize={10}
stroke="#8884d8" minTickGap={10}
fill="#98d1fb" />
activeDot={{ r: 8 }} <Tooltip content={<CustomTooltip />} />
/> <Area
<ReferenceLine type="monotone"
stroke="#16a34a" dataKey="pending"
strokeDasharray="3 3" stroke="#8884d8"
segment={[ fill="url(#linearblue)"
{ x: `${renderShortNumericDateFormat(endDate)}`, y: 0 }, activeDot={{ r: 8 }}
{ x: `${renderShortNumericDateFormat(startDate)}`, y: issues.length }, />
]} <ReferenceLine
/> stroke="#16a34a"
</AreaChart> strokeDasharray="3 3"
</ResponsiveContainer> segment={[
</div> { x: `${renderShortNumericDateFormat(endDate)}`, y: 0 },
{ x: `${renderShortNumericDateFormat(startDate)}`, y: issues.length },
]}
/>
</AreaChart>
</div> </div>
); );
}; };

View File

@ -89,32 +89,44 @@ export const SidebarProgressStats: React.FC<Props> = ({ groupedIssues, issues })
> >
<Tab.List <Tab.List
as="div" as="div"
className="flex items-center justify-between w-full rounded bg-gray-100 text-xs" className="flex items-center justify-between px-1 py-1.5 w-full rounded-md bg-gray-100 text-xs"
> >
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
`w-1/2 rounded py-1 ${selected ? "bg-gray-300" : "hover:bg-gray-200"}` `rounded w-1/3 p-1 text-sm text-gray-900 ${
} selected
? " bg-theme text-white"
: " hover:bg-hover-gray"
}`
}
> >
Assignees Assignees
</Tab> </Tab>
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
`w-1/2 rounded py-1 ${selected ? "bg-gray-300 font-semibold" : "hover:bg-gray-200 "}` `rounded w-1/3 p-1 text-sm text-gray-900 ${
} selected
? " bg-theme text-white"
: " hover:bg-hover-gray"
}`
}
> >
Labels Labels
</Tab> </Tab>
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
`w-1/2 rounded py-1 ${selected ? "bg-gray-300 font-semibold" : "hover:bg-gray-200 "}` `rounded w-1/3 p-1 text-sm text-gray-900 ${
} selected
? " bg-theme text-white"
: " hover:bg-hover-gray"
}`
}
> >
States States
</Tab> </Tab>
</Tab.List> </Tab.List>
<Tab.Panels className="flex items-center justify-between w-full"> <Tab.Panels className="flex items-center justify-between p-1 w-full">
<Tab.Panel as="div" className="w-full flex flex-col "> <Tab.Panel as="div" className="w-full flex flex-col text-xs ">
{members?.map((member, index) => { {members?.map((member, index) => {
const totalArray = issues?.filter((i) => i.assignees?.includes(member.member.id)); const totalArray = issues?.filter((i) => i.assignees?.includes(member.member.id));
const completeArray = totalArray?.filter((i) => i.state_detail.group === "completed"); const completeArray = totalArray?.filter((i) => i.state_detail.group === "completed");
@ -170,15 +182,15 @@ export const SidebarProgressStats: React.FC<Props> = ({ groupedIssues, issues })
<SingleProgressStats <SingleProgressStats
key={index} key={index}
title={ title={
<> <div className="flex items-center gap-2">
<span <span
className="block h-2 w-2 rounded-full " className="block h-3 w-3 rounded-full "
style={{ style={{
backgroundColor: issue.color, backgroundColor: issue.color,
}} }}
/> />
<span className="text-xs capitalize">{issue.name}</span> <span className="text-xs capitalize">{issue.name}</span>
</> </div>
} }
completed={completeArray.length} completed={completeArray.length}
total={totalArray.length} total={totalArray.length}
@ -192,15 +204,15 @@ export const SidebarProgressStats: React.FC<Props> = ({ groupedIssues, issues })
<SingleProgressStats <SingleProgressStats
key={index} key={index}
title={ title={
<> <div className="flex items-center gap-2">
<span <span
className="block h-2 w-2 rounded-full " className="block h-3 w-3 rounded-full "
style={{ style={{
backgroundColor: stateGroupColours[group], backgroundColor: stateGroupColours[group],
}} }}
/> />
<span className="text-xs capitalize">{group}</span> <span className="text-xs capitalize">{group}</span>
</> </div>
} }
completed={groupedIssues[group].length} completed={groupedIssues[group].length}
total={issues.length} total={issues.length}

View File

@ -13,7 +13,7 @@ export const SingleProgressStats: React.FC<TSingleProgressStatsProps> = ({
completed, completed,
total, total,
}) => ( }) => (
<div className="flex w-full items-center justify-between border-b-[1px] py-3 text-xs"> <div className="flex w-full items-center justify-between py-3 text-xs">
<div className="flex w-1/2 items-center justify-start gap-2">{title}</div> <div className="flex w-1/2 items-center justify-start gap-2">{title}</div>
<div className="flex w-1/2 items-center justify-end gap-1 px-2"> <div className="flex w-1/2 items-center justify-end gap-1 px-2">
<div className="flex h-5 items-center justify-center gap-1 "> <div className="flex h-5 items-center justify-center gap-1 ">

View File

@ -7,19 +7,21 @@ import { mutate } from "swr";
// react-hook-form // react-hook-form
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { Popover, Transition } from "@headlessui/react"; import { Disclosure, Popover, Transition } from "@headlessui/react";
import DatePicker from "react-datepicker"; import DatePicker from "react-datepicker";
// icons // icons
import { import {
CalendarDaysIcon, CalendarDaysIcon,
ChartPieIcon, ChartPieIcon,
LinkIcon, ArrowLongRightIcon,
Squares2X2Icon,
TrashIcon, TrashIcon,
UserIcon, DocumentDuplicateIcon,
UserCircleIcon,
ChevronDownIcon,
DocumentIcon,
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
// ui // ui
import { Loader, ProgressBar } from "components/ui"; import { CustomMenu, Loader, ProgressBar } from "components/ui";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
// services // services
@ -29,7 +31,7 @@ import { SidebarProgressStats } from "components/core";
import ProgressChart from "components/core/sidebar/progress-chart"; import ProgressChart from "components/core/sidebar/progress-chart";
import { DeleteCycleModal } from "components/cycles"; import { DeleteCycleModal } from "components/cycles";
// helpers // helpers
import { copyTextToClipboard } from "helpers/string.helper"; import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper";
import { groupBy } from "helpers/array.helper"; import { groupBy } from "helpers/array.helper";
import { renderDateFormat, renderShortNumericDateFormat } from "helpers/date-time.helper"; import { renderDateFormat, renderShortNumericDateFormat } from "helpers/date-time.helper";
// types // types
@ -100,6 +102,25 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
}); });
}; };
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: "Cycle link copied to clipboard",
});
})
.catch(() => {
setToastAlert({
type: "error",
title: "Some error occurred",
});
});
};
useEffect(() => { useEffect(() => {
if (cycle) if (cycle)
reset({ reset({
@ -116,218 +137,293 @@ export const CycleDetailsSidebar: React.FC<Props> = ({
<div <div
className={`fixed top-0 ${ className={`fixed top-0 ${
isOpen ? "right-0" : "-right-[24rem]" isOpen ? "right-0" : "-right-[24rem]"
} z-20 h-full w-[24rem] overflow-y-auto border-l bg-gray-50 p-5 duration-300`} } z-20 h-full w-[24rem] overflow-y-auto border-l bg-gray-50 py-5 duration-300`}
> >
{cycle ? ( {cycle ? (
<> <>
<div className="flex gap-1 text-sm my-2"> <div className="flex flex-col items-start justify-center">
<div className="flex items-center "> <div className="flex gap-2.5 px-7 text-sm">
<span <div className="flex items-center ">
className={`flex items-center gap-1 text-left capitalize p-1 text-xs h-full w-full text-gray-900`} <span
> className={`flex items-center rounded border-[0.5px] border-gray-200 bg-gray-100 px-2.5 py-1.5 text-center text-sm capitalize text-gray-800 `}
<Squares2X2Icon className="h-4 w-4 flex-shrink-0" /> >
{cycleStatus === "current" {capitalizeFirstLetter(cycleStatus)}
? "In Progress" </span>
: cycleStatus === "completed"
? "Completed"
: cycleStatus === "upcoming"
? "Upcoming"
: "Draft"}
</span>
</div>
<div className="flex justify-center items-center gap-2 rounded-md border bg-transparent h-full p-2 px-4 text-xs font-medium text-gray-900 hover:bg-gray-100 hover:text-gray-900 focus:outline-none">
<Popover className="flex justify-center items-center relative rounded-lg">
{({ open }) => (
<>
<Popover.Button
className={`group flex items-center ${open ? "bg-gray-100" : ""}`}
>
<CalendarDaysIcon className="h-4 w-4 flex-shrink-0 mr-2" />
<span>
{renderShortNumericDateFormat(`${cycle.start_date}`)
? renderShortNumericDateFormat(`${cycle.start_date}`)
: "N/A"}
</span>
</Popover.Button>
<Transition
as={React.Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute top-10 -left-10 z-20 transform overflow-hidden">
<DatePicker
selected={startDateRange}
onChange={(date) => {
submitChanges({
start_date: renderDateFormat(date),
});
setStartDateRange(date);
}}
selectsStart
startDate={startDateRange}
endDate={endDateRange}
inline
/>
</Popover.Panel>
</Transition>
</>
)}
</Popover>
<Popover className="flex justify-center items-center relative rounded-lg">
{({ open }) => (
<>
<Popover.Button
className={`group flex items-center ${open ? "bg-gray-100" : ""}`}
>
<span>
-{" "}
{renderShortNumericDateFormat(`${cycle.end_date}`)
? renderShortNumericDateFormat(`${cycle.end_date}`)
: "N/A"}
</span>
</Popover.Button>
<Transition
as={React.Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute top-10 -right-20 z-20 transform overflow-hidden">
<DatePicker
selected={endDateRange}
onChange={(date) => {
submitChanges({
end_date: renderDateFormat(date),
});
setEndDateRange(date);
}}
selectsEnd
startDate={startDateRange}
endDate={endDateRange}
minDate={startDateRange}
inline
/>
</Popover.Panel>
</Transition>
</>
)}
</Popover>
</div>
</div>
<div className="flex items-center justify-between pb-3">
<h4 className="text-sm font-medium">{cycle.name}</h4>
<div className="flex flex-wrap items-center gap-2">
<button
type="button"
className="rounded-md border p-2 shadow-sm duration-300 hover:bg-gray-100 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
onClick={() =>
copyTextToClipboard(
`https://app.plane.so/${workspaceSlug}/projects/${projectId}/cycles/${cycle.id}`
)
.then(() => {
setToastAlert({
type: "success",
title: "Cycle link copied to clipboard",
});
})
.catch(() => {
setToastAlert({
type: "error",
title: "Some error occurred",
});
})
}
>
<LinkIcon className="h-3.5 w-3.5" />
</button>
<button
type="button"
className="rounded-md border border-red-500 p-2 text-red-500 shadow-sm duration-300 hover:bg-red-50 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500"
onClick={() => setCycleDeleteModal(true)}
>
<TrashIcon className="h-3.5 w-3.5" />
</button>
</div>
</div>
<div className="divide-y-2 divide-gray-100 text-xs">
<div className="py-1">
<div className="flex flex-wrap items-center py-2">
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2">
<UserIcon className="h-4 w-4 flex-shrink-0" />
<p>Owned by</p>
</div>
<div className="sm:basis-1/2 flex items-center gap-1">
{cycle.owned_by &&
(cycle.owned_by.avatar && cycle.owned_by.avatar !== "" ? (
<div className="h-5 w-5 rounded-full border-2 border-transparent">
<Image
src={cycle.owned_by.avatar}
height="100%"
width="100%"
className="rounded-full"
alt={cycle.owned_by?.first_name}
/>
</div>
) : (
<div className="grid h-5 w-5 place-items-center rounded-full border-2 border-white bg-gray-700 capitalize text-white">
{cycle.owned_by &&
cycle.owned_by?.first_name &&
cycle.owned_by?.first_name !== ""
? cycle.owned_by?.first_name.charAt(0)
: cycle.owned_by?.email.charAt(0)}
</div>
))}
{cycle.owned_by?.first_name !== ""
? cycle.owned_by?.first_name
: cycle.owned_by?.email}
</div>
</div> </div>
<div className="flex flex-wrap items-center py-2"> <div className="relative flex h-full w-52 items-center justify-center gap-2 text-sm text-gray-800">
<div className="flex items-center gap-x-2 text-sm sm:basis-1/2"> <Popover className="flex h-full items-center justify-center rounded-lg">
<ChartPieIcon className="h-4 w-4 flex-shrink-0" /> {({ open }) => (
<p>Progress</p> <>
<Popover.Button
className={`group flex h-full items-center gap-1 rounded border-[0.5px] border-gray-200 bg-gray-100 px-2.5 py-1.5 text-gray-800 ${
open ? "bg-gray-100" : ""
}`}
>
<CalendarDaysIcon className="h-3 w-3" />
<span>
{renderShortNumericDateFormat(`${cycle.start_date}`)
? renderShortNumericDateFormat(`${cycle.start_date}`)
: "N/A"}
</span>
</Popover.Button>
<Transition
as={React.Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden">
<DatePicker
selected={startDateRange}
onChange={(date) => {
submitChanges({
start_date: renderDateFormat(date),
});
setStartDateRange(date);
}}
selectsStart
startDate={startDateRange}
endDate={endDateRange}
maxDate={endDateRange}
shouldCloseOnSelect
inline
/>
</Popover.Panel>
</Transition>
</>
)}
</Popover>
<span>
<ArrowLongRightIcon className="h-3 w-3" />
</span>
<Popover className="flex h-full items-center justify-center rounded-lg">
{({ open }) => (
<>
<Popover.Button
className={`group flex items-center gap-1 rounded border-[0.5px] border-gray-200 bg-gray-100 px-2.5 py-1.5 text-gray-800 ${
open ? "bg-gray-100" : ""
}`}
>
<CalendarDaysIcon className="h-3 w-3 " />
<span>
{renderShortNumericDateFormat(`${cycle.end_date}`)
? renderShortNumericDateFormat(`${cycle.end_date}`)
: "N/A"}
</span>
</Popover.Button>
<Transition
as={React.Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute top-10 -right-5 z-20 transform overflow-hidden">
<DatePicker
selected={endDateRange}
onChange={(date) => {
submitChanges({
end_date: renderDateFormat(date),
});
setEndDateRange(date);
}}
selectsEnd
startDate={startDateRange}
endDate={endDateRange}
// minDate={startDateRange}
inline
/>
</Popover.Panel>
</Transition>
</>
)}
</Popover>
</div>
</div>
<div className="flex flex-col gap-6 px-7 py-6">
<div className="flex flex-col items-start justify-start gap-2 ">
<div className="flex items-center justify-start gap-2 ">
<h4 className="text-xl font-semibold text-gray-900">{cycle.name}</h4>
<CustomMenu width="lg" ellipsis>
<CustomMenu.MenuItem onClick={handleCopyText}>
<span className="flex items-center justify-start gap-2 text-gray-800">
<DocumentDuplicateIcon className="h-4 w-4" />
<span>Copy Link</span>
</span>
</CustomMenu.MenuItem>
<CustomMenu.MenuItem onClick={() => setCycleDeleteModal(true)}>
<span className="flex items-center justify-start gap-2 text-gray-800">
<TrashIcon className="h-4 w-4" />
<span>Delete</span>
</span>
</CustomMenu.MenuItem>
</CustomMenu>
</div> </div>
<div className="flex items-center gap-2 sm:basis-1/2">
<div className="grid flex-shrink-0 place-items-center"> <span className="whitespace-normal text-sm leading-5 text-black">
{cycle.description}
</span>
</div>
<div className="flex flex-col gap-4 text-sm">
<div className="flex items-center justify-start gap-1">
<div className="flex w-40 items-center justify-start gap-2">
<UserCircleIcon className="h-5 w-5 text-gray-400" />
<span>Lead</span>
</div>
<div className="flex items-center gap-2.5">
{cycle.owned_by.avatar && cycle.owned_by.avatar !== "" ? (
<Image
src={cycle.owned_by.avatar}
height={12}
width={12}
className="rounded-full"
alt={cycle.owned_by.first_name}
/>
) : (
<span className="flex h-5 w-5 items-center justify-center rounded-full bg-gray-800 capitalize text-white">
{cycle.owned_by.first_name.charAt(0)}
</span>
)}
<span className="text-gray-900">{cycle.owned_by.first_name}</span>
</div>
</div>
<div className="flex items-center justify-start gap-1">
<div className="flex w-40 items-center justify-start gap-2">
<ChartPieIcon className="h-5 w-5 text-gray-400" />
<span>Progress</span>
</div>
<div className="flex items-center gap-2.5 text-gray-800">
<span className="h-4 w-4"> <span className="h-4 w-4">
<ProgressBar <ProgressBar
value={groupedIssues.completed.length} value={groupedIssues.completed.length}
maxValue={cycleIssues?.length} maxValue={cycleIssues?.length}
/> />
</span> </span>
{groupedIssues.completed.length}/{cycleIssues?.length}
</div> </div>
{groupedIssues.completed.length}/{cycleIssues?.length}
</div> </div>
</div> </div>
</div> </div>
<div className="py-1" />
</div> </div>
<div className="flex flex-col items-center justify-center w-full gap-2 ">
{isStartValid && isEndValid ? ( <div className="flex w-full flex-col items-center justify-start gap-2 border-t border-gray-300 px-7 py-6 ">
<div className="relative h-[200px] w-full "> <Disclosure>
<ProgressChart {({ open }) => (
issues={issues} <div
start={cycle?.start_date ?? ""} className={`relative flex h-full w-full flex-col ${open ? "" : "flex-row"}`}
end={cycle?.end_date ?? ""} >
/> <div className="flex w-full items-center justify-between gap-2 ">
</div> <div className="flex items-center justify-start gap-2 text-sm">
) : ( <span className="font-medium text-gray-500">Progress</span>
"" {!open ? (
)} <span className="rounded bg-[#09A953]/10 px-1.5 py-0.5 text-xs text-[#09A953]">
{issues.length > 0 ? ( {Math.round(
<SidebarProgressStats issues={issues} groupedIssues={groupedIssues} /> (groupedIssues.completed.length / cycleIssues?.length) * 100
) : ( )}
"" %
)} </span>
) : (
""
)}
</div>
<Disclosure.Button>
<ChevronDownIcon
className={`h-3 w-3 ${open ? "rotate-180 transform" : ""}`}
aria-hidden="true"
/>
</Disclosure.Button>
</div>
<Transition show={open}>
<Disclosure.Panel>
{isStartValid && isEndValid ? (
<div className=" h-full w-full py-4">
<div className="flex items-start justify-between gap-4 py-2 text-xs">
<div className="flex items-center gap-1">
<span>
<DocumentIcon className="h-3 w-3 text-gray-500" />
</span>
<span>
Pending Issues -{" "}
{cycleIssues?.length - groupedIssues.completed.length}{" "}
</span>
</div>
<div className="flex items-center gap-3 text-gray-900">
<div className="flex items-center justify-center gap-1">
<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">
<span className="h-2.5 w-2.5 rounded-full bg-[#4C8FFF]" />
<span>Current</span>
</div>
</div>
</div>
<div className="relative h-40 w-96">
<ProgressChart
issues={issues}
start={cycle?.start_date ?? ""}
end={cycle?.end_date ?? ""}
/>
</div>
</div>
) : (
""
)}
</Disclosure.Panel>
</Transition>
</div>
)}
</Disclosure>
</div>
<div className="flex w-full flex-col items-center justify-start gap-2 border-t border-gray-300 px-7 py-6 ">
<Disclosure>
{({ open }) => (
<div
className={`relative flex h-full w-full flex-col ${open ? "" : "flex-row"}`}
>
<div className="flex w-full items-center justify-between gap-2 ">
<div className="flex items-center justify-start gap-2 text-sm">
<span className="font-medium text-gray-500">Other Information</span>
</div>
<Disclosure.Button>
<ChevronDownIcon
className={`h-3 w-3 ${open ? "rotate-180 transform" : ""}`}
aria-hidden="true"
/>
</Disclosure.Button>
</div>
<Transition show={open}>
<Disclosure.Panel>
{issues.length > 0 ? (
<div className=" h-full w-full py-4">
<SidebarProgressStats issues={issues} groupedIssues={groupedIssues} />
</div>
) : (
""
)}
</Disclosure.Panel>
</Transition>
</div>
)}
</Disclosure>
</div> </div>
</> </>
) : ( ) : (

View File

@ -275,12 +275,10 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = (props) => {
alt={cycle.owned_by.first_name} alt={cycle.owned_by.first_name}
/> />
) : ( ) : (
<button <span
className="flex h-5 w-5 items-center justify-center rounded-full bg-gray-800 capitalize text-white" className="flex h-5 w-5 items-center justify-center rounded-full bg-gray-800 capitalize text-white">
onClick={handleEditCycle}
>
{cycle.owned_by.first_name.charAt(0)} {cycle.owned_by.first_name.charAt(0)}
</button> </span>
)} )}
<span className="text-gray-900">{cycle.owned_by.first_name}</span> <span className="text-gray-900">{cycle.owned_by.first_name}</span>
</div> </div>

View File

@ -63,7 +63,7 @@ export const ProgressBar: React.FC<Props> = ({
return ( return (
<svg width={radius * 2} height={radius * 2}> <svg width={radius * 2} height={radius * 2}>
{renderOuterCircle()} {renderOuterCircle()}
<circle r={radius - strokeWidth} cx={radius} cy={radius} fill="#fff" /> <circle r={radius - strokeWidth} cx={radius} cy={radius} fill="#f9fafb" />
</svg> </svg>
); );
}; };