plane/apps/app/components/cycles/cycles-view.tsx

243 lines
7.2 KiB
TypeScript
Raw Normal View History

2023-05-28 20:44:40 +00:00
import React, { useState } from "react";
import { useRouter } from "next/router";
import { mutate } from "swr";
// services
import cyclesService from "services/cycles.service";
// hooks
2023-05-28 20:44:40 +00:00
import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// components
import {
2023-05-28 20:44:40 +00:00
CreateUpdateCycleModal,
CyclesListGanttChartView,
2023-05-28 20:44:40 +00:00
DeleteCycleModal,
SingleCycleCard,
SingleCycleList,
} from "components/cycles";
// ui
import { EmptyState, Loader } from "components/ui";
// icons
import { PlusIcon } from "@heroicons/react/24/outline";
2023-05-28 20:44:40 +00:00
// images
import emptyCycle from "public/empty-state/cycle.svg";
2023-05-28 20:44:40 +00:00
// helpers
import { getDateRangeStatus } from "helpers/date-time.helper";
// types
2023-05-28 20:44:40 +00:00
import { ICycle } from "types";
// fetch-keys
import {
2023-05-28 21:08:16 +00:00
COMPLETED_CYCLES_LIST,
CURRENT_CYCLE_LIST,
CYCLES_LIST,
DRAFT_CYCLES_LIST,
UPCOMING_CYCLES_LIST,
2023-05-28 20:44:40 +00:00
} from "constants/fetch-keys";
type Props = {
2023-05-28 20:44:40 +00:00
cycles: ICycle[] | undefined;
viewType: string | null;
};
2023-05-28 20:44:40 +00:00
export const CyclesView: React.FC<Props> = ({ cycles, viewType }) => {
const [createUpdateCycleModal, setCreateUpdateCycleModal] = useState(false);
const [selectedCycleToUpdate, setSelectedCycleToUpdate] = useState<ICycle | null>(null);
const [deleteCycleModal, setDeleteCycleModal] = useState(false);
const [selectedCycleToDelete, setSelectedCycleToDelete] = useState<ICycle | null>(null);
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
2023-05-28 20:44:40 +00:00
const { setToastAlert } = useToast();
const handleEditCycle = (cycle: ICycle) => {
setSelectedCycleToUpdate(cycle);
setCreateUpdateCycleModal(true);
};
2023-05-28 20:44:40 +00:00
const handleDeleteCycle = (cycle: ICycle) => {
setSelectedCycleToDelete(cycle);
setDeleteCycleModal(true);
};
const handleAddToFavorites = (cycle: ICycle) => {
if (!workspaceSlug || !projectId) return;
const cycleStatus = getDateRangeStatus(cycle.start_date, cycle.end_date);
const fetchKey =
cycleStatus === "current"
2023-05-28 21:08:16 +00:00
? CURRENT_CYCLE_LIST(projectId as string)
2023-05-28 20:44:40 +00:00
: cycleStatus === "upcoming"
2023-05-28 21:08:16 +00:00
? UPCOMING_CYCLES_LIST(projectId as string)
2023-05-28 20:44:40 +00:00
: cycleStatus === "completed"
2023-05-28 21:08:16 +00:00
? COMPLETED_CYCLES_LIST(projectId as string)
: DRAFT_CYCLES_LIST(projectId as string);
2023-05-28 20:44:40 +00:00
mutate<ICycle[]>(
fetchKey,
(prevData) =>
(prevData ?? []).map((c) => ({
...c,
is_favorite: c.id === cycle.id ? true : c.is_favorite,
})),
false
);
mutate(
2023-05-28 21:08:16 +00:00
CYCLES_LIST(projectId as string),
2023-05-28 20:44:40 +00:00
(prevData: any) =>
(prevData ?? []).map((c: any) => ({
...c,
is_favorite: c.id === cycle.id ? true : c.is_favorite,
})),
false
);
cyclesService
.addCycleToFavorites(workspaceSlug as string, projectId as string, {
cycle: cycle.id,
})
.catch(() => {
setToastAlert({
type: "error",
title: "Error!",
message: "Couldn't add the cycle to favorites. Please try again.",
});
});
};
const handleRemoveFromFavorites = (cycle: ICycle) => {
if (!workspaceSlug || !projectId) return;
const cycleStatus = getDateRangeStatus(cycle.start_date, cycle.end_date);
const fetchKey =
cycleStatus === "current"
2023-05-28 21:08:16 +00:00
? CURRENT_CYCLE_LIST(projectId as string)
2023-05-28 20:44:40 +00:00
: cycleStatus === "upcoming"
2023-05-28 21:08:16 +00:00
? UPCOMING_CYCLES_LIST(projectId as string)
2023-05-28 20:44:40 +00:00
: cycleStatus === "completed"
2023-05-28 21:08:16 +00:00
? COMPLETED_CYCLES_LIST(projectId as string)
: DRAFT_CYCLES_LIST(projectId as string);
2023-05-28 20:44:40 +00:00
mutate<ICycle[]>(
fetchKey,
(prevData) =>
(prevData ?? []).map((c) => ({
...c,
is_favorite: c.id === cycle.id ? false : c.is_favorite,
})),
false
);
mutate(
2023-05-28 21:08:16 +00:00
CYCLES_LIST(projectId as string),
2023-05-28 20:44:40 +00:00
(prevData: any) =>
(prevData ?? []).map((c: any) => ({
...c,
is_favorite: c.id === cycle.id ? false : c.is_favorite,
})),
false
);
cyclesService
.removeCycleFromFavorites(workspaceSlug as string, projectId as string, cycle.id)
.catch(() => {
setToastAlert({
type: "error",
title: "Error!",
message: "Couldn't remove the cycle from favorites. Please try again.",
});
});
};
return (
<>
2023-05-28 20:44:40 +00:00
<CreateUpdateCycleModal
isOpen={createUpdateCycleModal}
handleClose={() => setCreateUpdateCycleModal(false)}
data={selectedCycleToUpdate}
user={user}
2023-05-28 20:44:40 +00:00
/>
<DeleteCycleModal
isOpen={deleteCycleModal}
setIsOpen={setDeleteCycleModal}
data={selectedCycleToDelete}
user={user}
2023-05-28 20:44:40 +00:00
/>
{cycles ? (
cycles.length > 0 ? (
viewType === "list" ? (
<div className="divide-y divide-custom-border-300">
2023-05-28 20:44:40 +00:00
{cycles.map((cycle) => (
<div className="hover:bg-custom-background-80">
<div className="flex flex-col border-custom-border-300">
2023-05-28 20:44:40 +00:00
<SingleCycleList
key={cycle.id}
cycle={cycle}
handleDeleteCycle={() => handleDeleteCycle(cycle)}
handleEditCycle={() => handleEditCycle(cycle)}
handleAddToFavorites={() => handleAddToFavorites(cycle)}
handleRemoveFromFavorites={() => handleRemoveFromFavorites(cycle)}
/>
</div>
</div>
))}
</div>
) : viewType === "board" ? (
<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)}
handleAddToFavorites={() => handleAddToFavorites(cycle)}
handleRemoveFromFavorites={() => handleRemoveFromFavorites(cycle)}
/>
2023-05-28 20:44:40 +00:00
))}
</div>
) : (
<CyclesListGanttChartView cycles={cycles ?? []} />
)
) : (
<EmptyState
title="Plan your project with cycles"
description="Cycle is a custom time period in which a team works to complete items on their backlog."
image={emptyCycle}
buttonText="New Cycle"
buttonIcon={<PlusIcon className="h-4 w-4" />}
onClick={() => {
const e = new KeyboardEvent("keydown", {
key: "q",
});
document.dispatchEvent(e);
}}
2023-05-28 20:44:40 +00:00
/>
)
) : viewType === "list" ? (
<Loader className="space-y-4">
<Loader.Item height="50px" />
<Loader.Item height="50px" />
<Loader.Item height="50px" />
</Loader>
) : viewType === "board" ? (
<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>
) : (
<Loader>
<Loader.Item height="300px" />
</Loader>
)}
</>
);
};