chore: cycles loading, fix: cycles favorite mutation (#379)

This commit is contained in:
Aaryan Khandelwal 2023-03-07 11:04:51 +05:30 committed by GitHub
parent b54a1f221f
commit 64978969a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 206 additions and 132 deletions

View file

@ -14,6 +14,7 @@ import { CompletedCycleIcon } from "components/icons";
import { ICycle, SelectCycleType } from "types";
// fetch-keys
import { CYCLE_COMPLETE_LIST } from "constants/fetch-keys";
import { Loader } from "components/ui";
export interface CompletedCyclesListProps {
setCreateUpdateCycleModal: React.Dispatch<React.SetStateAction<boolean>>;
@ -49,38 +50,42 @@ export const CompletedCyclesList: React.FC<CompletedCyclesListProps> = ({
return (
<>
{completedCycles && (
<>
<DeleteCycleModal
isOpen={
cycleDeleteModal &&
!!selectedCycleForDelete &&
selectedCycleForDelete.actionType === "delete"
}
setIsOpen={setCycleDeleteModal}
data={selectedCycleForDelete}
/>
{completedCycles?.completed_cycles.length > 0 ? (
<div className="grid grid-cols-1 gap-9 md:grid-cols-2 lg:grid-cols-3">
{completedCycles.completed_cycles.map((cycle) => (
<SingleCycleCard
key={cycle.id}
cycle={cycle}
handleDeleteCycle={() => handleDeleteCycle(cycle)}
handleEditCycle={() => handleEditCycle(cycle)}
/>
))}
</div>
) : (
<div className="flex flex-col items-center justify-center gap-4 text-center">
<CompletedCycleIcon height="56" width="56" />
<h3 className="text-gray-500">
No completed cycles yet. Create with{" "}
<pre className="inline rounded bg-gray-200 px-2 py-1">Q</pre>.
</h3>
</div>
)}
</>
<DeleteCycleModal
isOpen={
cycleDeleteModal &&
!!selectedCycleForDelete &&
selectedCycleForDelete.actionType === "delete"
}
setIsOpen={setCycleDeleteModal}
data={selectedCycleForDelete}
/>
{completedCycles ? (
completedCycles.completed_cycles.length > 0 ? (
<div className="grid grid-cols-1 gap-9 md:grid-cols-2 lg:grid-cols-3">
{completedCycles.completed_cycles.map((cycle) => (
<SingleCycleCard
key={cycle.id}
cycle={cycle}
handleDeleteCycle={() => handleDeleteCycle(cycle)}
handleEditCycle={() => handleEditCycle(cycle)}
/>
))}
</div>
) : (
<div className="flex flex-col items-center justify-center gap-4 text-center">
<CompletedCycleIcon height="56" width="56" />
<h3 className="text-gray-500">
No completed cycles yet. Create with{" "}
<pre className="inline rounded bg-gray-200 px-2 py-1">Q</pre>.
</h3>
</div>
)
) : (
<Loader className="grid grid-cols-1 gap-9 md:grid-cols-2 lg:grid-cols-3">
<Loader.Item height="200px" />
<Loader.Item height="200px" />
<Loader.Item height="200px" />
</Loader>
)}
</>
);

View file

@ -6,12 +6,13 @@ import { DeleteCycleModal, SingleCycleCard } from "components/cycles";
import { CompletedCycleIcon, CurrentCycleIcon, UpcomingCycleIcon } from "components/icons";
// types
import { ICycle, SelectCycleType } from "types";
import { Loader } from "components/ui";
type TCycleStatsViewProps = {
cycles: ICycle[];
cycles: ICycle[] | undefined;
setCreateUpdateCycleModal: React.Dispatch<React.SetStateAction<boolean>>;
setSelectedCycle: React.Dispatch<React.SetStateAction<SelectCycleType>>;
type: "current" | "upcoming" | "completed";
type: "current" | "upcoming" | "draft";
};
export const CyclesList: React.FC<TCycleStatsViewProps> = ({
@ -44,31 +45,37 @@ export const CyclesList: React.FC<TCycleStatsViewProps> = ({
setIsOpen={setCycleDeleteModal}
data={selectedCycleForDelete}
/>
{cycles.length > 0 ? (
<div className="grid grid-cols-1 gap-9 md:grid-cols-2 lg:grid-cols-3">
{cycles.map((cycle) => (
<SingleCycleCard
key={cycle.id}
cycle={cycle}
handleDeleteCycle={() => handleDeleteCycle(cycle)}
handleEditCycle={() => handleEditCycle(cycle)}
/>
))}
</div>
{cycles ? (
cycles.length > 0 ? (
<div className="grid grid-cols-1 gap-9 md:grid-cols-2 lg:grid-cols-3">
{cycles.map((cycle) => (
<SingleCycleCard
key={cycle.id}
cycle={cycle}
handleDeleteCycle={() => handleDeleteCycle(cycle)}
handleEditCycle={() => handleEditCycle(cycle)}
/>
))}
</div>
) : (
<div className="flex flex-col items-center justify-center gap-4 text-center">
{type === "upcoming" ? (
<UpcomingCycleIcon height="56" width="56" />
) : type === "draft" ? (
<CompletedCycleIcon height="56" width="56" />
) : (
<CurrentCycleIcon height="56" width="56" />
)}
<h3 className="text-gray-500">
No {type} {type === "current" ? "cycle" : "cycles"} yet. Create with{" "}
<pre className="inline rounded bg-gray-200 px-2 py-1">Q</pre>.
</h3>
</div>
)
) : (
<div className="flex flex-col items-center justify-center gap-4 text-center">
{type === "upcoming" ? (
<UpcomingCycleIcon height="56" width="56" />
) : type === "completed" ? (
<CompletedCycleIcon height="56" width="56" />
) : (
<CurrentCycleIcon height="56" width="56" />
)}
<h3 className="text-gray-500">
No {type} {type === "current" ? "cycle" : "cycles"} yet. Create with{" "}
<pre className="inline rounded bg-gray-200 px-2 py-1">Q</pre>.
</h3>
</div>
<Loader className="grid grid-cols-1 gap-9 md:grid-cols-2 lg:grid-cols-3">
<Loader.Item height="300px" />
</Loader>
)}
</>
);

View file

@ -43,11 +43,7 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
await cycleService
.createCycle(workspaceSlug as string, projectId as string, payload)
.then((res) => {
switch (
res?.start_date && res.end_date
? getDateRangeStatus(res?.start_date, res.end_date)
: "draft"
) {
switch (getDateRangeStatus(res.start_date, res.end_date)) {
case "completed":
mutate(CYCLE_COMPLETE_LIST(projectId as string));
break;
@ -81,11 +77,7 @@ export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
await cycleService
.updateCycle(workspaceSlug as string, projectId as string, cycleId, payload)
.then((res) => {
switch (
res?.start_date && res.end_date
? getDateRangeStatus(res?.start_date, res.end_date)
: "draft"
) {
switch (getDateRangeStatus(res.start_date, res.end_date)) {
case "completed":
mutate(CYCLE_COMPLETE_LIST(projectId as string));
break;

View file

@ -17,13 +17,25 @@ import { Disclosure, Transition } from "@headlessui/react";
import { CalendarDaysIcon } from "@heroicons/react/20/solid";
import { ChevronDownIcon, PencilIcon, StarIcon } from "@heroicons/react/24/outline";
// helpers
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
import { getDateRangeStatus, renderShortDateWithYearFormat } from "helpers/date-time.helper";
import { groupBy } from "helpers/array.helper";
import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper";
// types
import { CycleIssueResponse, ICycle } from "types";
import {
CompletedCyclesResponse,
CurrentAndUpcomingCyclesResponse,
CycleIssueResponse,
DraftCyclesResponse,
ICycle,
} from "types";
// fetch-keys
import { CYCLE_ISSUES, CYCLE_LIST } from "constants/fetch-keys";
import {
CYCLE_COMPLETE_LIST,
CYCLE_CURRENT_AND_UPCOMING_LIST,
CYCLE_DRAFT_LIST,
CYCLE_ISSUES,
CYCLE_LIST,
} from "constants/fetch-keys";
type TSingleStatProps = {
cycle: ICycle;
@ -75,15 +87,45 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = (props) => {
cycle: cycle.id,
})
.then(() => {
mutate<ICycle[]>(
CYCLE_LIST(projectId as string),
(prevData) =>
(prevData ?? []).map((c) => ({
...c,
is_favorite: c.id === cycle.id ? true : c.is_favorite,
})),
false
);
const cycleStatus = getDateRangeStatus(cycle.start_date, cycle.end_date);
if (cycleStatus === "current" || cycleStatus === "upcoming")
mutate<CurrentAndUpcomingCyclesResponse>(
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
);
else if (cycleStatus === "completed")
mutate<CompletedCyclesResponse>(
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
);
else
mutate<DraftCyclesResponse>(
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
);
setToastAlert({
type: "success",
@ -106,15 +148,45 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = (props) => {
cyclesService
.removeCycleFromFavorites(workspaceSlug as string, projectId as string, cycle.id)
.then(() => {
mutate<ICycle[]>(
CYCLE_LIST(projectId as string),
(prevData) =>
(prevData ?? []).map((c) => ({
...c,
is_favorite: c.id === cycle.id ? false : c.is_favorite,
})),
false
);
const cycleStatus = getDateRangeStatus(cycle.start_date, cycle.end_date);
if (cycleStatus === "current" || cycleStatus === "upcoming")
mutate<CurrentAndUpcomingCyclesResponse>(
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
);
else if (cycleStatus === "completed")
mutate<CompletedCyclesResponse>(
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
);
else
mutate<DraftCyclesResponse>(
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
);
setToastAlert({
type: "success",
@ -167,16 +239,12 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = (props) => {
</a>
</Link>
{cycle.is_favorite ? (
<button onClick={handleRemoveFromFavorites} className="p-1 ">
<span>
<StarIcon className="h-4 w-4 text-orange-400" fill="#f6ad55" />
</span>
<button onClick={handleRemoveFromFavorites}>
<StarIcon className="h-4 w-4 text-orange-400" fill="#f6ad55" />
</button>
) : (
<button onClick={handleAddToFavorites} className="p-1">
<span>
<StarIcon className="h-4 w-4 " color="#858E96" />
</span>
<button onClick={handleAddToFavorites}>
<StarIcon className="h-4 w-4 " color="#858E96" />
</button>
)}
</div>