From 61102952d0b4d073ad19bdefc500dd4f71715f15 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Tue, 7 Mar 2023 18:46:56 +0530 Subject: [PATCH] style :module list (#387) * chore: module favorite type and services * style: module list * style: module list and card * fix: link fix --- .../components/modules/single-module-card.tsx | 282 +++++++++++++----- .../projects/[projectId]/modules/index.tsx | 20 +- apps/app/services/modules.service.ts | 22 ++ apps/app/types/modules.d.ts | 1 + 4 files changed, 244 insertions(+), 81 deletions(-) diff --git a/apps/app/components/modules/single-module-card.tsx b/apps/app/components/modules/single-module-card.tsx index 8651f0a33..3526321e8 100644 --- a/apps/app/components/modules/single-module-card.tsx +++ b/apps/app/components/modules/single-module-card.tsx @@ -3,28 +3,53 @@ import React, { useState } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; import Image from "next/image"; +import useSWR, { mutate } from "swr"; +// toast +import useToast from "hooks/use-toast"; // components import { DeleteModuleModal } from "components/modules"; // ui import { AssigneesList, Avatar, CustomMenu } from "components/ui"; // icons import User from "public/user.png"; -import { CalendarDaysIcon } from "@heroicons/react/24/outline"; +import { + CalendarDaysIcon, + StarIcon, + UserCircleIcon, + UserGroupIcon, +} from "@heroicons/react/24/outline"; // helpers -import { renderShortNumericDateFormat } from "helpers/date-time.helper"; +import { + renderShortDateWithYearFormat, + renderShortNumericDateFormat, +} from "helpers/date-time.helper"; +// services +import stateService from "services/state.service"; +import modulesService from "services/modules.service"; // types import { IModule } from "types"; -// common -import { MODULE_STATUS } from "constants/module"; -import useToast from "hooks/use-toast"; +// fetch-key +import { MODULE_LIST, STATE_LIST } from "constants/fetch-keys"; +// helper import { copyTextToClipboard } from "helpers/string.helper"; +import { getStatesList } from "helpers/state.helper"; type Props = { module: IModule; handleEditModule: () => void; }; +const stateGroupColours: { + [key: string]: string; +} = { + backlog: "#3f76ff", + unstarted: "#ff9e9e", + started: "#d687ff", + cancelled: "#ff5353", + completed: "#096e8d", +}; + export const SingleModuleCard: React.FC = ({ module, handleEditModule }) => { const [moduleDeleteModal, setModuleDeleteModal] = useState(false); @@ -37,6 +62,80 @@ export const SingleModuleCard: React.FC = ({ module, handleEditModule }) setModuleDeleteModal(true); }; + const { data: stateGroups } = useSWR( + workspaceSlug && module.project_detail.id ? STATE_LIST(module.project_detail.id) : null, + workspaceSlug && module.project_detail.id + ? () => stateService.getStates(workspaceSlug as string, module.project_detail.id) + : null + ); + + const states = getStatesList(stateGroups ?? {}); + const selectedOption = states?.find( + (s) => s.name.replace(" ", "-").toLowerCase() === module.status?.replace(" ", "-").toLowerCase() + ); + + const handleAddToFavorites = () => { + if (!workspaceSlug && !projectId && !module) return; + + modulesService + .addModuleToFavorites(workspaceSlug as string, projectId as string, { + module: module.id, + }) + .then(() => { + mutate( + MODULE_LIST(projectId as string), + (prevData) => + (prevData ?? []).map((m) => ({ + ...m, + is_favorite: m.id === module.id ? true : m.is_favorite, + })), + false + ); + + setToastAlert({ + type: "success", + title: "Success!", + message: "Successfully added the module to favorites.", + }); + }) + .catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "Couldn't add the module to favorites. Please try again.", + }); + }); + }; + + const handleRemoveFromFavorites = () => { + if (!workspaceSlug || !module) return; + + modulesService + .removeModuleFromFavorites(workspaceSlug as string, projectId as string, module.id) + .then(() => { + mutate( + MODULE_LIST(projectId as string), + (prevData) => + (prevData ?? []).map((m) => ({ + ...m, + is_favorite: m.id === module.id ? false : m.is_favorite, + })), + false + ); + setToastAlert({ + type: "success", + title: "Success!", + message: "Successfully removed the module from favorites.", + }); + }) + .catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "Couldn't remove the module from favorites. Please try again.", + }); + }); + }; const handleCopyText = () => { const originURL = @@ -53,6 +152,9 @@ export const SingleModuleCard: React.FC = ({ module, handleEditModule }) }); }; + const endDate = new Date(module.target_date ?? ""); + const startDate = new Date(module.start_date ?? ""); + return ( <> = ({ module, handleEditModule }) setIsOpen={setModuleDeleteModal} data={module} /> -
-
- - Edit module - Delete module - Copy module link - -
- - - - {module.name} - -
-
-
LEAD
-
- {module.lead_detail ? ( - - ) : ( -
- N/A - N/A -
- )} +
+
+ +
+
+ + + {module.name} + + +
+
+ + Start : + {renderShortDateWithYearFormat(startDate)} +
+
+ + End : + {renderShortDateWithYearFormat(endDate)}
-
-
MEMBERS
-
- {module.members_detail && module.members_detail.length > 0 ? ( - - ) : ( -
- N/A - N/A -
- )} +
+
+ + Lead : +
+ {module.lead_detail ? ( +
+ + {module.lead_detail.first_name} +
+ ) : ( +
+ N/A + N/A +
+ )} +
-
-
-
END DATE
-
- - {module.target_date ? renderShortNumericDateFormat(module?.target_date) : "N/A"} -
-
-
-
STATUS
-
- s.value === module.status)?.color, - }} - /> - {module.status} +
+ + Members +
+ {module.members_detail && module.members_detail.length > 0 ? ( + + ) : ( +
+ N/A + N/A +
+ )} +
- - +
+
+ {module?.status?.replace("-", " ")} +
+
+ + {module.is_favorite ? ( + + ) : ( + + )} + + + + + Edit module + + + Delete module + + + Copy module link + + + +
+
+
+
); diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx index c0824dcdf..132a2b8d9 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx @@ -89,14 +89,18 @@ const ProjectModules: NextPage = () => { {modules ? ( modules.length > 0 ? (
-
- {modules.map((module) => ( - handleEditModule(module)} - /> - ))} +
+

Module

+ +
+ {modules.map((module) => ( + handleEditModule(module)} + /> + ))} +
) : ( diff --git a/apps/app/services/modules.service.ts b/apps/app/services/modules.service.ts index 3c728b8a7..b874a7dc8 100644 --- a/apps/app/services/modules.service.ts +++ b/apps/app/services/modules.service.ts @@ -151,6 +151,28 @@ class ProjectIssuesServices extends APIService { throw error?.response?.data; }); } + + async addModuleToFavorites( + workspaceSlug: string, + projectId: string, + data: { + module: string; + } + ): Promise { + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-modules/`, data) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } + + async removeModuleFromFavorites(workspaceSlug: string, projectId: string, moduleId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/user-favorite-modules/${moduleId}/`) + .then((response) => response?.data) + .catch((error) => { + throw error?.response?.data; + }); + } } export default new ProjectIssuesServices(); diff --git a/apps/app/types/modules.d.ts b/apps/app/types/modules.d.ts index c3de50f72..ef6749fce 100644 --- a/apps/app/types/modules.d.ts +++ b/apps/app/types/modules.d.ts @@ -22,6 +22,7 @@ export interface IModule { members: string[]; members_list: string[]; members_detail: IUserLite[]; + is_favorite: boolean; name: string; project: string; project_detail: IProject;