From 626aae696f2279d592c564718cd988ee8f1ef511 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Mon, 6 Mar 2023 16:36:22 +0530 Subject: [PATCH] feat: favorite cycle and style: style improvements (#376) * style: consistent btn * style: caret direction for disclosure * fix: progress tooltip value rounded * chore: favorite cycle serivces * chore: favorite cycle type and constant * feat: favorite cycle feat added * refactor: favorite services and type * fix: build fix --- .../components/cycles/single-cycle-card.tsx | 127 ++++++++++++++---- .../ui/linear-progress-indicator.tsx | 2 +- .../projects/[projectId]/cycles/index.tsx | 18 +-- apps/app/services/cycles.service.ts | 23 ++++ apps/app/types/cycles.d.ts | 1 + 5 files changed, 136 insertions(+), 35 deletions(-) diff --git a/apps/app/components/cycles/single-cycle-card.tsx b/apps/app/components/cycles/single-cycle-card.tsx index 79d6b7c77..201090ac2 100644 --- a/apps/app/components/cycles/single-cycle-card.tsx +++ b/apps/app/components/cycles/single-cycle-card.tsx @@ -4,7 +4,7 @@ import Link from "next/link"; import Image from "next/image"; import { useRouter } from "next/router"; -import useSWR from "swr"; +import useSWR, { mutate } from "swr"; // services import cyclesService from "services/cycles.service"; @@ -23,7 +23,7 @@ import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helpe // types import { CycleIssueResponse, ICycle } from "types"; // fetch-keys -import { CYCLE_ISSUES } from "constants/fetch-keys"; +import { CYCLE_ISSUES, CYCLE_LIST } from "constants/fetch-keys"; type TSingleStatProps = { cycle: ICycle; @@ -67,6 +67,70 @@ export const SingleCycleCard: React.FC = (props) => { ...groupBy(cycleIssues ?? [], "issue_detail.state_detail.group"), }; + const handleAddToFavorites = () => { + if (!workspaceSlug && !projectId && !cycle) return; + + cyclesService + .addCycleToFavorites(workspaceSlug as string, projectId as string, { + cycle: cycle.id, + }) + .then(() => { + mutate( + CYCLE_LIST(projectId as string), + (prevData) => + (prevData ?? []).map((c) => ({ + ...c, + is_favorite: c.id === cycle.id ? true : c.is_favorite, + })), + false + ); + + setToastAlert({ + type: "success", + title: "Success!", + message: "Successfully added the cycle to favorites.", + }); + }) + .catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "Couldn't add the cycle to favorites. Please try again.", + }); + }); + }; + + const handleRemoveFromFavorites = () => { + if (!workspaceSlug || !cycle) return; + + cyclesService + .removeCycleFromFavorites(workspaceSlug as string, projectId as string, cycle.id) + .then(() => { + mutate( + CYCLE_LIST(projectId as string), + (prevData) => + (prevData ?? []).map((c) => ({ + ...c, + is_favorite: c.id === cycle.id ? false : c.is_favorite, + })), + false + ); + + setToastAlert({ + type: "success", + title: "Success!", + message: "Successfully removed the cycle from favorites.", + }); + }) + .catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "Couldn't remove the cycle from favorites. Please try again.", + }); + }); + }; + const handleCopyText = () => { const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; @@ -95,31 +159,41 @@ export const SingleCycleCard: React.FC = (props) => { return (
- - -
-
-

{cycle.name}

- {/* +
+
+ + +

{cycle.name}

+
+ + {cycle.is_favorite ? ( + + ) : ( +
+ + + )} +
-
-
- - Start : - {renderShortDateWithYearFormat(startDate)} -
-
- - End : - {renderShortDateWithYearFormat(endDate)} -
-
+
+
+ + Start : + {renderShortDateWithYearFormat(startDate)}
- - +
+ + End : + {renderShortDateWithYearFormat(endDate)} +
+
+
@@ -170,7 +244,10 @@ export const SingleCycleCard: React.FC = (props) => { Progress -
diff --git a/apps/app/components/ui/linear-progress-indicator.tsx b/apps/app/components/ui/linear-progress-indicator.tsx index 8145c7f4d..02d4f5fcb 100644 --- a/apps/app/components/ui/linear-progress-indicator.tsx +++ b/apps/app/components/ui/linear-progress-indicator.tsx @@ -18,7 +18,7 @@ export const LinearProgressIndicator: React.FC = ({ data }) => { progress += item.value; return ( - +
); diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx index 595a07bfa..29d30950b 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx @@ -132,10 +132,10 @@ const ProjectCycles: NextPage = () => { > - ` rounded-3xl border px-6 py-3 ${ + `rounded-3xl border px-5 py-1.5 text-sm sm:px-7 sm:py-2 sm:text-base ${ selected - ? "bg-theme text-white" - : "border-gray-400 bg-white text-gray-900 hover:bg-gray-200" + ? "border-theme bg-theme text-white" + : "border-gray-300 bg-white hover:bg-hover-gray" }` } > @@ -143,10 +143,10 @@ const ProjectCycles: NextPage = () => { - ` rounded-3xl border px-6 py-3 ${ + `rounded-3xl border px-5 py-1.5 text-sm sm:px-7 sm:py-2 sm:text-base ${ selected - ? "bg-theme text-white" - : "border-gray-400 bg-white text-gray-900 hover:bg-gray-200" + ? "border-theme bg-theme text-white" + : "border-gray-300 bg-white hover:bg-hover-gray" }` } > @@ -154,10 +154,10 @@ const ProjectCycles: NextPage = () => { - ` rounded-3xl border px-6 py-3 ${ + `rounded-3xl border px-5 py-1.5 text-sm sm:px-7 sm:py-2 sm:text-base ${ selected - ? "bg-theme text-white" - : "border-gray-400 bg-white text-gray-900 hover:bg-gray-200" + ? "border-theme bg-theme text-white" + : "border-gray-300 bg-white hover:bg-hover-gray" }` } > diff --git a/apps/app/services/cycles.service.ts b/apps/app/services/cycles.service.ts index eac138030..5c13574a2 100644 --- a/apps/app/services/cycles.service.ts +++ b/apps/app/services/cycles.service.ts @@ -128,6 +128,29 @@ class ProjectCycleServices extends APIService { throw error?.response?.data; }); } + + async addCycleToFavorites( + workspaceSlug: string, + projectId: string, + data: { + cycle: string; + } + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-cycles/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removeCycleFromFavorites(workspaceSlug: string, projectId: string, cycleId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-cycles/${cycleId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + } export default new ProjectCycleServices(); diff --git a/apps/app/types/cycles.d.ts b/apps/app/types/cycles.d.ts index 928166a32..4dc895504 100644 --- a/apps/app/types/cycles.d.ts +++ b/apps/app/types/cycles.d.ts @@ -9,6 +9,7 @@ export interface ICycle { description: string; start_date: string | null; end_date: string | null; + is_favorite: boolean; created_by: string; updated_by: string; project: string;