Skip to content

Commit

Permalink
refactor: modules list page (#2521)
Browse files Browse the repository at this point in the history
* refactor: modules list page

* chore: update handle favorites logic for modules

* fix: build errors
  • Loading branch information
aaryan610 authored Oct 23, 2023
1 parent 07d548e commit d72d3da
Show file tree
Hide file tree
Showing 20 changed files with 275 additions and 360 deletions.
2 changes: 1 addition & 1 deletion web/components/headers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export * from "./workspace-dashboard";
export * from "./projects";
export * from "./profile-preferences";
export * from "./cycles";
export * from "./modules";
export * from "./modules-list";
export * from "./project-settings";
export * from "./workspace-settings";
export * from "./pages";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import { Dispatch, FC, SetStateAction } from "react";
import { useRouter } from "next/router";
import Link from "next/link";
import { observer } from "mobx-react-lite";
import { Plus } from "lucide-react";
// components
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// hooks
import useLocalStorage from "hooks/use-local-storage";
// ui
import { Breadcrumbs, BreadcrumbItem, Button, Tooltip } from "@plane/ui";
import { Icon } from "components/ui";
// helper
import { replaceUnderscoreIfSnakeCase, truncateText } from "helpers/string.helper";

export interface IModulesHeader {
name: string | undefined;
modulesView: string;
setModulesView: Dispatch<SetStateAction<"grid" | "gantt_chart">>;
}

const moduleViewOptions: { type: "grid" | "gantt_chart"; icon: any }[] = [
{
type: "gantt_chart",
Expand All @@ -26,11 +23,15 @@ const moduleViewOptions: { type: "grid" | "gantt_chart"; icon: any }[] = [
},
];

export const ModulesHeader: FC<IModulesHeader> = (props) => {
const { name, modulesView, setModulesView } = props;
export const ModulesListHeader: React.FC = observer(() => {
// router
const router = useRouter();
const { workspaceSlug } = router.query;
const { workspaceSlug, projectId } = router.query;

const { project: projectStore } = useMobxStore();
const projectDetails = projectId ? projectStore.project_details[projectId.toString()] : undefined;

const { storedValue: modulesView, setValue: setModulesView } = useLocalStorage("modules_view", "grid");

return (
<div
Expand All @@ -48,7 +49,7 @@ export const ModulesHeader: FC<IModulesHeader> = (props) => {
</Link>
}
/>
<BreadcrumbItem title={`${truncateText(name ?? "Project", 32)} Modules`} />
<BreadcrumbItem title={`${truncateText(projectDetails?.name ?? "Project", 32)} Modules`} />
</Breadcrumbs>
</div>
</div>
Expand Down Expand Up @@ -83,4 +84,4 @@ export const ModulesHeader: FC<IModulesHeader> = (props) => {
</div>
</div>
);
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export const CycleIssueQuickActions: React.FC<Props> = (props) => {
setDeleteIssueModal(true);
}}
>
<div className="flex items-center gap-2 text-red-500">
<div className="flex items-center gap-2">
<Trash2 className="h-3 w-3" />
Delete issue
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export const ModuleIssueQuickActions: React.FC<Props> = (props) => {
setDeleteIssueModal(true);
}}
>
<div className="flex items-center gap-2 text-red-500">
<div className="flex items-center gap-2">
<Trash2 className="h-3 w-3" />
Delete issue
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export const ProjectIssueQuickActions: React.FC<Props> = (props) => {
setDeleteIssueModal(true);
}}
>
<div className="flex items-center gap-2 text-red-500">
<div className="flex items-center gap-2">
<Trash2 className="h-3 w-3" />
Delete issue
</div>
Expand Down
39 changes: 8 additions & 31 deletions web/components/issues/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { Dialog, Transition } from "@headlessui/react";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// services
import { ModuleService } from "services/module.service";
import { IssueService, IssueDraftService } from "services/issue";
import { IssueDraftService } from "services/issue";
// hooks
import useToast from "hooks/use-toast";
import useLocalStorage from "hooks/use-local-storage";
Expand Down Expand Up @@ -40,8 +39,6 @@ export interface IssuesModalProps {
onSubmit?: (data: Partial<IIssue>) => Promise<void>;
}

const moduleService = new ModuleService();
const issueService = new IssueService();
const issueDraftService = new IssueDraftService();

export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((props) => {
Expand Down Expand Up @@ -170,35 +167,15 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
}, [activeProject, data, projectId, projects, isOpen]);

const addIssueToCycle = async (issueId: string, cycleId: string) => {
if (!workspaceSlug || !activeProject || !user) return;
if (!workspaceSlug || !activeProject) return;

await issueService
.addIssueToCycle(
workspaceSlug.toString(),
activeProject,
cycleId,
{
issues: [issueId],
},
user
)
.then(() => cycleIssueStore.fetchIssues(workspaceSlug.toString(), activeProject, cycleId));
cycleIssueStore.addIssueToCycle(workspaceSlug.toString(), activeProject, cycleId, issueId);
};

const addIssueToModule = async (issueId: string, moduleId: string) => {
if (!workspaceSlug || !activeProject || !user) return;
if (!workspaceSlug || !activeProject) return;

await moduleService
.addIssuesToModule(
workspaceSlug.toString(),
activeProject,
moduleId,
{
issues: [issueId],
},
user
)
.then(() => moduleIssueStore.fetchIssues(workspaceSlug.toString(), activeProject, moduleId));
moduleIssueStore.addIssueToModule(workspaceSlug.toString(), activeProject, moduleId, issueId);
};

const createIssue = async (payload: Partial<IIssue>) => {
Expand Down Expand Up @@ -267,10 +244,10 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
};

const updateIssue = async (payload: Partial<IIssue>) => {
if (!user) return;
if (!workspaceSlug || !activeProject || !data) return;

await issueService
.patchIssue(workspaceSlug as string, activeProject ?? "", data?.id ?? "", payload, user)
await issueDetailStore
.updateIssue(workspaceSlug.toString(), activeProject, data.id, payload)
.then(() => {
if (!createMore) onFormSubmitClose();

Expand Down
41 changes: 17 additions & 24 deletions web/components/modules/delete-module-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,56 +1,47 @@
import React, { useState } from "react";

import { useRouter } from "next/router";

import { mutate } from "swr";

// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
import { ModuleService } from "services/module.service";
// hooks
import useToast from "hooks/use-toast";
// ui
import { Button } from "@plane/ui";
// icons
import { AlertTriangle } from "lucide-react";
// types
import type { IUser, IModule } from "types";
// fetch-keys
import { MODULE_LIST } from "constants/fetch-keys";
import type { IModule } from "types";
import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";

type Props = {
data: IModule;
isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
data?: IModule;
user: IUser | undefined;
onClose: () => void;
};

// services
const moduleService = new ModuleService();
export const DeleteModuleModal: React.FC<Props> = observer((props) => {
const { data, isOpen, onClose } = props;

export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data, user }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false);

const router = useRouter();
const { workspaceSlug, projectId, moduleId } = router.query;

const { module: moduleStore } = useMobxStore();

const { setToastAlert } = useToast();

const handleClose = () => {
setIsOpen(false);
onClose();
setIsDeleteLoading(false);
};

const handleDeletion = async () => {
setIsDeleteLoading(true);
if (!workspaceSlug || !projectId) return;

if (!workspaceSlug || !projectId || !data) return;

mutate<IModule[]>(MODULE_LIST(projectId as string), (prevData) => prevData?.filter((m) => m.id !== data.id), false);
setIsDeleteLoading(true);

await moduleService
.deleteModule(workspaceSlug as string, projectId as string, data.id, user)
await moduleStore
.deleteModule(workspaceSlug.toString(), projectId.toString(), data.id)
.then(() => {
if (moduleId) router.push(`/${workspaceSlug}/projects/${data.project}/modules`);
handleClose();
Expand All @@ -61,6 +52,8 @@ export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data, us
title: "Error!",
message: "Module could not be deleted. Please try again.",
});
})
.finally(() => {
setIsDeleteLoading(false);
});
};
Expand Down Expand Up @@ -126,4 +119,4 @@ export const DeleteModuleModal: React.FC<Props> = ({ isOpen, setIsOpen, data, us
</Dialog>
</Transition.Root>
);
};
});
63 changes: 12 additions & 51 deletions web/components/modules/gantt-chart/modules-list-layout.tsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,26 @@
import { FC } from "react";

import { useRouter } from "next/router";

import { KeyedMutator } from "swr";

// services
import { ModuleService } from "services/module.service";
// hooks
import useUser from "hooks/use-user";
import useProjectDetails from "hooks/use-project-details";
import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// components
import { GanttChartRoot, IBlockUpdateData } from "components/gantt-chart";
import { ModuleGanttBlock, ModuleGanttSidebarBlock } from "components/modules";
// types
import { IModule } from "types";

type Props = {
modules: IModule[];
mutateModules: KeyedMutator<IModule[]>;
};

// services
const moduleService = new ModuleService();

export const ModulesListGanttChartView: FC<Props> = ({ modules, mutateModules }) => {
export const ModulesListGanttChartView: React.FC = observer(() => {
const router = useRouter();
const { workspaceSlug } = router.query;

const { user } = useUser();
const { projectDetails } = useProjectDetails();
const { workspaceSlug, projectId } = router.query;

const handleModuleUpdate = (module: IModule, payload: IBlockUpdateData) => {
if (!workspaceSlug || !user) return;

mutateModules((prevData: any) => {
if (!prevData) return prevData;

const newList = prevData.map((p: any) => ({
...p,
...(p.id === module.id
? {
start_date: payload.start_date ? payload.start_date : p.start_date,
target_date: payload.target_date ? payload.target_date : p.target_date,
sort_order: payload.sort_order ? payload.sort_order.newSortOrder : p.sort_order,
}
: {}),
}));
const { project: projectStore, module: moduleStore } = useMobxStore();

if (payload.sort_order) {
const removedElement = newList.splice(payload.sort_order.sourceIndex, 1)[0];
newList.splice(payload.sort_order.destinationIndex, 0, removedElement);
}
const projectDetails = projectId ? projectStore.project_details[projectId.toString()] : undefined;
const modules = moduleStore.projectModules;

return newList;
}, false);

const newPayload: any = { ...payload };

if (newPayload.sort_order && payload.sort_order) newPayload.sort_order = payload.sort_order.newSortOrder;
const handleModuleUpdate = (module: IModule, payload: IBlockUpdateData) => {
if (!workspaceSlug) return;

moduleService.patchModule(workspaceSlug.toString(), module.project, module.id, newPayload, user);
moduleStore.updateModuleGanttStructure(workspaceSlug.toString(), module.project, module, payload);
};

const blockFormat = (blocks: IModule[]) =>
Expand Down Expand Up @@ -93,4 +54,4 @@ export const ModulesListGanttChartView: FC<Props> = ({ modules, mutateModules })
/>
</div>
);
};
});
3 changes: 2 additions & 1 deletion web/components/modules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export * from "./delete-module-modal";
export * from "./form";
export * from "./gantt-chart";
export * from "./modal";
export * from "./modules-list-view";
export * from "./sidebar";
export * from "./single-module-card";
export * from "./module-card-item";
Loading

1 comment on commit d72d3da

@vercel
Copy link

@vercel vercel bot commented on d72d3da Oct 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

plane-dev – ./web/

plane-dev-plane.vercel.app
plane-dev-git-develop-plane.vercel.app
plane-dev.vercel.app
crew42.plane.so

Please sign in to comment.