diff --git a/web/components/modules/index.ts b/web/components/modules/index.ts index 2a7f54fb3..a26295381 100644 --- a/web/components/modules/index.ts +++ b/web/components/modules/index.ts @@ -5,4 +5,5 @@ export * from "./form"; export * from "./gantt-chart"; export * from "./modal"; export * from "./sidebar"; -export * from "./single-module-card"; +export * from "./module-detail-card"; +export * from "./module-list"; diff --git a/web/components/modules/single-module-card.tsx b/web/components/modules/module-detail-card.tsx similarity index 86% rename from web/components/modules/single-module-card.tsx rename to web/components/modules/module-detail-card.tsx index 7f7d761b5..ed30bfcb4 100644 --- a/web/components/modules/single-module-card.tsx +++ b/web/components/modules/module-detail-card.tsx @@ -12,16 +12,10 @@ import useToast from "hooks/use-toast"; // components import { DeleteModuleModal } from "components/modules"; // ui -import { AssigneesList, Avatar, CustomMenu, Tooltip } from "components/ui"; +import { AssigneesList, CustomMenu, Tooltip } from "components/ui"; // icons -import { - CalendarDaysIcon, - LinkIcon, - PencilIcon, - StarIcon, - TrashIcon, -} from "@heroicons/react/24/outline"; -import { CalendarMonthIcon, TargetIcon } from "components/icons"; +import { CalendarDaysIcon, LinkIcon, PencilIcon, StarIcon, TrashIcon } from "@heroicons/react/24/outline"; +import { TargetIcon } from "components/icons"; // helpers import { copyTextToClipboard, truncateText } from "helpers/string.helper"; @@ -37,7 +31,7 @@ type Props = { user: ICurrentUserResponse | undefined; }; -export const SingleModuleCard: React.FC = ({ module, handleEditModule, user }) => { +export const ModuleDetailCard: React.FC = ({ module, handleEditModule, user }) => { const [moduleDeleteModal, setModuleDeleteModal] = useState(false); const router = useRouter(); @@ -45,8 +39,7 @@ export const SingleModuleCard: React.FC = ({ module, handleEditModule, us const { setToastAlert } = useToast(); - const completionPercentage = - ((module.completed_issues + module.cancelled_issues) / module.total_issues) * 100; + const completionPercentage = ((module.completed_issues + module.cancelled_issues) / module.total_issues) * 100; const handleDeleteModule = () => { if (!module) return; @@ -93,24 +86,19 @@ export const SingleModuleCard: React.FC = ({ module, handleEditModule, us false ); - modulesService - .removeModuleFromFavorites(workspaceSlug as string, projectId as string, module.id) - .catch(() => { - setToastAlert({ - type: "error", - title: "Error!", - message: "Couldn't remove the module from favorites. Please try again.", - }); + modulesService.removeModuleFromFavorites(workspaceSlug as string, projectId as string, module.id).catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "Couldn't remove the module from favorites. Please try again.", }); + }); }; const handleCopyText = () => { - const originURL = - typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; + const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; - copyTextToClipboard( - `${originURL}/${workspaceSlug}/projects/${projectId}/modules/${module.id}` - ).then(() => { + copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/modules/${module.id}`).then(() => { setToastAlert({ type: "success", title: "Link Copied!", @@ -125,12 +113,7 @@ export const SingleModuleCard: React.FC = ({ module, handleEditModule, us return ( <> - +
diff --git a/web/components/modules/module-list.tsx b/web/components/modules/module-list.tsx new file mode 100644 index 000000000..adc458e8b --- /dev/null +++ b/web/components/modules/module-list.tsx @@ -0,0 +1,131 @@ +import React, { useEffect, useState } from "react"; + +import { useRouter } from "next/router"; + +import useSWR from "swr"; + +// hooks +import useUserAuth from "hooks/use-user-auth"; +// services +import modulesService from "services/modules.service"; +// components +import { CreateUpdateModuleModal, ModulesListGanttChartView, ModuleDetailCard } from "components/modules"; +// ui +import { EmptyState, Loader } from "components/ui"; +// icons +import { PlusIcon } from "@heroicons/react/24/outline"; +// images +import emptyModule from "public/empty-state/module.svg"; +// types +import type { IModule, SelectModuleType } from "types/modules"; +// fetch-keys +import { MODULE_LIST } from "constants/fetch-keys"; + +type Props = { + modulesView: string; + modules?: IModule[] | null; +}; + +export const ModuleList: React.FC = (props) => { + const { modulesView, modules } = props; + + // router + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + // states + const [createUpdateModule, setCreateUpdateModule] = useState(false); + const [selectedModule, setSelectedModule] = useState(); + + // hooks + const { user } = useUserAuth(); + + // TODO: remove this + const { mutate: mutateModules } = useSWR( + workspaceSlug && projectId ? MODULE_LIST(projectId as string) : null, + workspaceSlug && projectId ? () => modulesService.getModules(workspaceSlug as string, projectId as string) : null + ); + + const handleEditModule = (module: IModule) => { + setSelectedModule({ ...module, actionType: "edit" }); + setCreateUpdateModule(true); + }; + + /** + * Close the create/update module + * modal and reset the selected module + */ + useEffect(() => { + if (createUpdateModule) return; + + const timer = setTimeout(() => { + setSelectedModule(undefined); + clearTimeout(timer); + }, 500); + }, [createUpdateModule]); + + return ( + <> + + + {/* modules are loaded & there number is more than 0 */} + {modules && modules.length > 0 && ( + <> + {modulesView === "grid" && ( +
+
+ {modules.map((moduleDetail) => ( + handleEditModule(moduleDetail)} + user={user} + /> + ))} +
+
+ )} + {modulesView === "gantt_chart" && ( + + )} + + )} + + {/* modules are still loading */} + {!modules && ( + + + + + + + + + )} + + {/* modules are loaded & there number is 0 */} + {modules && modules.length === 0 && ( + , + text: "New Module", + onClick: () => { + const e = new KeyboardEvent("keydown", { + key: "m", + }); + document.dispatchEvent(e); + }, + }} + /> + )} + + ); +}; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx index edf504af1..0f1d5bc7a 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { useRouter } from "next/router"; @@ -6,29 +6,26 @@ import useSWR from "swr"; // layouts import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy"; -// hooks -import useUserAuth from "hooks/use-user-auth"; // services import projectService from "services/project.service"; -import modulesService from "services/modules.service"; +// store +import { observer } from "mobx-react-lite"; +import { useMobxStore } from "lib/mobx/store-provider"; // components -import { CreateUpdateModuleModal, ModulesListGanttChartView, SingleModuleCard } from "components/modules"; +import { ModuleList } from "components/modules"; // ui -import { EmptyState, Icon, Loader, PrimaryButton, Tooltip } from "components/ui"; +import { Icon, PrimaryButton, Tooltip } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons import { PlusIcon } from "@heroicons/react/24/outline"; -// images -import emptyModule from "public/empty-state/module.svg"; // types -import { IModule, SelectModuleType } from "types/modules"; import type { NextPage } from "next"; // fetch-keys import { MODULE_LIST, PROJECT_DETAILS } from "constants/fetch-keys"; // helper import { replaceUnderscoreIfSnakeCase, truncateText } from "helpers/string.helper"; -const moduleViewOptions: { type: "grid" | "gantt_chart"; icon: any }[] = [ +const moduleViewOptions = [ { type: "gantt_chart", icon: "view_timeline", @@ -37,42 +34,31 @@ const moduleViewOptions: { type: "grid" | "gantt_chart"; icon: any }[] = [ type: "grid", icon: "table_rows", }, -]; +] as const; const ProjectModules: NextPage = () => { - const [selectedModule, setSelectedModule] = useState(); - const [createUpdateModule, setCreateUpdateModule] = useState(false); - - const [modulesView, setModulesView] = useState<"grid" | "gantt_chart">("grid"); - + // router const router = useRouter(); const { workspaceSlug, projectId } = router.query; - const { user } = useUserAuth(); + // store + const { module: moduleStore } = useMobxStore(); + + // states + const [modulesView, setModulesView] = useState<"grid" | "gantt_chart">("grid"); const { data: activeProject } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null ); - const { data: modules, mutate: mutateModules } = useSWR( - workspaceSlug && projectId ? MODULE_LIST(projectId as string) : null, - workspaceSlug && projectId ? () => modulesService.getModules(workspaceSlug as string, projectId as string) : null + // TODO: remove + "tesings" + useSWR( + workspaceSlug && projectId ? MODULE_LIST(projectId.toString()) + "tesings" : null, + workspaceSlug && projectId ? () => moduleStore.fetchModules(workspaceSlug.toString(), projectId.toString()) : null ); - const handleEditModule = (module: IModule) => { - setSelectedModule({ ...module, actionType: "edit" }); - setCreateUpdateModule(true); - }; - - useEffect(() => { - if (createUpdateModule) return; - - const timer = setTimeout(() => { - setSelectedModule(undefined); - clearTimeout(timer); - }, 500); - }, [createUpdateModule]); + const modules = moduleStore.modules[projectId?.toString()!]; return ( {
} > - - {modules ? ( - modules.length > 0 ? ( - <> - {modulesView === "grid" && ( -
-
- {modules.map((module) => ( - handleEditModule(module)} - user={user} - /> - ))} -
-
- )} - {modulesView === "gantt_chart" && ( - - )} - - ) : ( - , - text: "New Module", - onClick: () => { - const e = new KeyboardEvent("keydown", { - key: "m", - }); - document.dispatchEvent(e); - }, - }} - /> - ) - ) : ( - - - - - - - - - )} + ); }; -export default ProjectModules; +export default observer(ProjectModules);