From 9a8dcc349f8665932b5a354680a3b4691a6ba58a Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Mon, 25 Sep 2023 17:43:55 +0530 Subject: [PATCH] chore: minor fixes --- web/components/project/index.ts | 2 +- ...eave-modal.tsx => leave-project-modal.tsx} | 49 +-- web/components/project/sidebar-list-item.tsx | 406 +++++++++--------- web/components/project/sidebar-list.tsx | 73 +--- web/layouts/app-layout/app-sidebar.tsx | 17 +- web/store/project.ts | 59 ++- 6 files changed, 303 insertions(+), 303 deletions(-) rename web/components/project/{confirm-project-leave-modal.tsx => leave-project-modal.tsx} (86%) diff --git a/web/components/project/index.ts b/web/components/project/index.ts index cd346eada..81bdd5a19 100644 --- a/web/components/project/index.ts +++ b/web/components/project/index.ts @@ -5,7 +5,7 @@ export * from "./settings-sidebar"; export * from "./single-integration-card"; export * from "./single-project-card"; export * from "./sidebar-list-item"; -export * from "./confirm-project-leave-modal"; +export * from "./leave-project-modal"; export * from "./member-select"; export * from "./members-select"; export * from "./label-select"; diff --git a/web/components/project/confirm-project-leave-modal.tsx b/web/components/project/leave-project-modal.tsx similarity index 86% rename from web/components/project/confirm-project-leave-modal.tsx rename to web/components/project/leave-project-modal.tsx index 7d6582869..64efb3815 100644 --- a/web/components/project/confirm-project-leave-modal.tsx +++ b/web/components/project/leave-project-modal.tsx @@ -1,18 +1,14 @@ -import React from "react"; -// next imports +import { FC } from "react"; import { useRouter } from "next/router"; -// react-hook-form import { Controller, useForm } from "react-hook-form"; -// headless ui import { Dialog, Transition } from "@headlessui/react"; -// icons import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; +import { observer } from "mobx-react-lite"; // ui import { DangerButton, Input, SecondaryButton } from "components/ui"; // fetch-keys import { PROJECTS_LIST } from "constants/fetch-keys"; // mobx react lite -import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; @@ -33,16 +29,17 @@ const defaultValues: FormData = { confirmLeave: "", }; -export const ConfirmProjectLeaveModal: React.FC = observer(() => { +export const LeaveProjectModal: FC<> = observer(() => { + // router const router = useRouter(); const { workspaceSlug } = router.query; - - const store: RootStore = useMobxStore(); - const { project } = store; - + // store + const { project: projectStore } = useMobxStore(); + // user const { user } = useUser(); + // project const { mutateProjects } = useProjects(); - + // toast const { setToastAlert } = useToast(); const { @@ -50,23 +47,21 @@ export const ConfirmProjectLeaveModal: React.FC = observer(() => { formState: { isSubmitting }, handleSubmit, reset, - watch, } = useForm({ defaultValues }); const handleClose = () => { - project.handleProjectLeaveModal(null); - + projectStore.handleProjectLeaveModal(null); reset({ ...defaultValues }); }; const onSubmit = async (data: any) => { if (data) { - if (data.projectName === project?.projectLeaveDetails?.name) { + if (data.projectName === projectStore?.projectLeaveDetails?.name) { if (data.confirmLeave === "Leave Project") { - return project + return projectStore .leaveProject( - project.projectLeaveDetails.workspaceSlug.toString(), - project.projectLeaveDetails.id.toString(), + projectStore.projectLeaveDetails.workspaceSlug.toString(), + projectStore.projectLeaveDetails.id.toString(), user ) .then((res) => { @@ -105,7 +100,7 @@ export const ConfirmProjectLeaveModal: React.FC = observer(() => { }; return ( - + {
-

Leave Project

@@ -155,10 +147,8 @@ export const ConfirmProjectLeaveModal: React.FC = observer(() => {

Enter the project name{" "} - - {project?.projectLeaveDetails?.name} - {" "} - to continue: + {project?.projectLeaveDetails?.name} to + continue:

{

- To confirm, type{" "} - Leave Project below: + To confirm, type Leave Project below:

= observer((props) => { const { workspaceSlug, projectId } = router.query; // toast const { setToastAlert } = useToast(); + // states + const [leaveProjectModalOpen, setLeaveProjectModal] = useState(false); const isAdmin = project.member_role === 20; const isViewerOrGuest = project.member_role === 10 || project.member_role === 5; @@ -126,218 +125,219 @@ export const ProjectSidebarListItem: React.FC = observer((props) => { }); }; + const handleLeaveProject = () => { + setLeaveProjectModal(true); + }; + return ( - - {({ open }) => ( - <> -
- {provided && ( - - - - )} - - - - {!sidebarCollapse && ( - - )} - - - - {!sidebarCollapse && ( - - {!shortContextMenu && isAdmin && ( - - - - Delete project - - - )} - {!project.is_favorite && ( - - - - Add to favorites - - - )} - {project.is_favorite && ( - - - - Remove from favorites - - - )} - - - - Copy project link - - - - {/* publish project settings */} - {isAdmin && ( - projectPublish.handleProjectModal(project?.id)}> -
-
- +
+ {project.emoji ? ( + + {renderEmoji(project.emoji)} + + ) : project.icon_prop ? ( +
+ {renderEmoji(project.icon_prop)}
-
{project.is_deployed ? "Publish settings" : "Publish"}
-
- - )} + ) : ( + + {project?.name.charAt(0)} + + )} - {project.archive_in > 0 && ( - router.push(`/${workspaceSlug}/projects/${project?.id}/archived-issues/`)} - > -
- - Archived Issues -
-
- )} - router.push(`/${workspaceSlug}/projects/${project?.id}/draft-issues`)} + {!sidebarCollapse && ( +

{project.name}

+ )} +
+ {!sidebarCollapse && ( + + )} + + + + {!sidebarCollapse && ( + -
- - Draft Issues -
- - router.push(`/${workspaceSlug}/projects/${project?.id}/settings`)}> -
- - Settings -
-
+ {!shortContextMenu && isAdmin && ( + + + + Delete project + + + )} + {!project.is_favorite && ( + + + + Add to favorites + + + )} + {project.is_favorite && ( + + + + Remove from favorites + + + )} + + + + Copy project link + + - {/* leave project */} - {isViewerOrGuest && ( + {/* publish project settings */} + {isAdmin && ( + projectPublish.handleProjectModal(project?.id)}> +
+
+ +
+
{project.is_deployed ? "Publish settings" : "Publish"}
+
+
+ )} + + {project.archive_in > 0 && ( + router.push(`/${workspaceSlug}/projects/${project?.id}/archived-issues/`)} + > +
+ + Archived Issues +
+
+ )} - projectStore.handleProjectLeaveModal({ - id: project?.id, - name: project?.name, - workspaceSlug: workspaceSlug as string, - }) - } + onClick={() => router.push(`/${workspaceSlug}/projects/${project?.id}/draft-issues`)} >
- - Leave Project + + Draft Issues +
+
+ router.push(`/${workspaceSlug}/projects/${project?.id}/settings`)} + > +
+ + Settings
- )} -
- )} -
- - - {navigation(workspaceSlug as string, project?.id).map((item) => { - if ( - (item.name === "Cycles" && !project.cycle_view) || - (item.name === "Modules" && !project.module_view) || - (item.name === "Views" && !project.issue_views_view) || - (item.name === "Pages" && !project.page_view) - ) - return; + {/* leave project */} + {isViewerOrGuest && ( + +
+ + Leave Project +
+
+ )} +
+ )} +
- return ( - - - - - - - - ); - })} - - - - )} -
+
+ + {!sidebarCollapse && item.name} +
+ + + + ); + })} + + + + )} + + ); }); diff --git a/web/components/project/sidebar-list.tsx b/web/components/project/sidebar-list.tsx index 6b672a41e..5bd0b38b5 100644 --- a/web/components/project/sidebar-list.tsx +++ b/web/components/project/sidebar-list.tsx @@ -9,7 +9,8 @@ import useToast from "hooks/use-toast"; import useUserAuth from "hooks/use-user-auth"; import useProjects from "hooks/use-projects"; // components -import { CreateProjectModal, DeleteProjectModal, ProjectSidebarListItem } from "components/project"; +import { CreateProjectModal, DeleteProjectModal, ProjectSidebarListItem, LeaveProjectModal } from "components/project"; +import { PublishProjectModal } from "components/project/publish-project/modal"; // services import projectService from "services/project.service"; // icons @@ -26,7 +27,7 @@ import { PROJECTS_LIST } from "constants/fetch-keys"; import { useMobxStore } from "lib/mobx/store-provider"; export const ProjectSidebarList: FC = observer(() => { - const { theme: themeStore, workspace: workspaceStore } = useMobxStore(); + const { theme: themeStore, workspace: workspaceStore, project: projectStore } = useMobxStore(); // router const router = useRouter(); const { workspaceSlug } = router.query; @@ -39,11 +40,8 @@ export const ProjectSidebarList: FC = observer(() => { const [isFavoriteProjectCreate, setIsFavoriteProjectCreate] = useState(false); const [isProjectModalOpen, setIsProjectModalOpen] = useState(false); const [deleteProjectModal, setDeleteProjectModal] = useState(false); - const [projectToDelete, setProjectToDelete] = useState(null); - const [projectToLeaveId, setProjectToLeaveId] = useState(null); - // router - const [isScrolled, setIsScrolled] = useState(false); + const [isScrolled, setIsScrolled] = useState(false); // scroll animation state const containerRef = useRef(null); @@ -53,9 +51,6 @@ export const ProjectSidebarList: FC = observer(() => { const joinedProjects = workspaceSlug && workspaceStore.workspaceJoinedProjects; const favoriteProjects = workspaceSlug && workspaceStore.workspaceFavoriteProjects; - console.log("workspaceJoinedProjects", workspaceStore.workspaceJoinedProjects); - console.log("workspaceFavoriteProjects", workspaceStore.workspaceFavoriteProjects); - const orderedJoinedProjects: IProject[] | undefined = joinedProjects ? orderArrayBy(joinedProjects, "sort_order", "ascending") : undefined; @@ -64,11 +59,6 @@ export const ProjectSidebarList: FC = observer(() => { ? orderArrayBy(favoriteProjects, "sort_order", "ascending") : undefined; - const handleDeleteProject = (project: IProject) => { - setProjectToDelete(project); - setDeleteProjectModal(true); - }; - const handleCopyText = (projectId: string) => { const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues`).then(() => { @@ -87,36 +77,11 @@ export const ProjectSidebarList: FC = observer(() => { if (source.index === destination.index) return; - const projectsList = - (destination.droppableId === "joined-projects" ? orderedJoinedProjects : orderedFavProjects) ?? []; + const updatedSortOrder = projectStore.orderProjectsWithSortOrder(source.index, destination.index, draggableId); - let updatedSortOrder = projectsList[source.index].sort_order; - - if (destination.index === 0) updatedSortOrder = (projectsList[0].sort_order as number) - 1000; - else if (destination.index === projectsList.length - 1) - updatedSortOrder = (projectsList[projectsList.length - 1].sort_order as number) + 1000; - else { - const destinationSortingOrder = projectsList[destination.index].sort_order as number; - const relativeDestinationSortingOrder = - source.index < destination.index - ? (projectsList[destination.index + 1].sort_order as number) - : (projectsList[destination.index - 1].sort_order as number); - - updatedSortOrder = (destinationSortingOrder + relativeDestinationSortingOrder) / 2; - } - - mutate( - PROJECTS_LIST(workspaceSlug as string, { is_favorite: "all" }), - (prevData) => { - if (!prevData) return prevData; - return prevData.map((p) => (p.id === draggableId ? { ...p, sort_order: updatedSortOrder } : p)); - }, - false - ); - - await projectService - .setProjectView(workspaceSlug as string, draggableId, { sort_order: updatedSortOrder }) - .catch(() => { + projectStore + .updateProjectView(workspaceSlug.toString(), draggableId, { sort_order: updatedSortOrder }) + .catch((error) => { setToastAlert({ type: "error", title: "Error!", @@ -125,20 +90,20 @@ export const ProjectSidebarList: FC = observer(() => { }); }; - const handleScroll = () => { - if (containerRef.current) { - const scrollTop = containerRef.current.scrollTop; - setIsScrolled(scrollTop > 0); - } - }; - + /** + * Implementing scroll animation styles based on the scroll length of the container + */ useEffect(() => { + const handleScroll = () => { + if (containerRef.current) { + const scrollTop = containerRef.current.scrollTop; + setIsScrolled(scrollTop > 0); + } + }; const currentContainerRef = containerRef.current; - if (currentContainerRef) { currentContainerRef.addEventListener("scroll", handleScroll); } - return () => { if (currentContainerRef) { currentContainerRef.removeEventListener("scroll", handleScroll); @@ -160,6 +125,10 @@ export const ProjectSidebarList: FC = observer(() => { data={projectToDelete} user={user} /> + {/* project leave modal */} + + {/* publish project modal */} +
= observer(({ toggleSidebar, setToggleSidebar }) => { - const store: any = useMobxStore(); - // theme - const { collapsed: sidebarCollapse } = useTheme(); + const { theme: themStore } = useMobxStore(); return (
@@ -39,10 +32,6 @@ const Sidebar: React.FC = observer(({ toggleSidebar, setToggleSide
- {/* publish project modal */} - - {/* project leave modal */} -
); }); diff --git a/web/store/project.ts b/web/store/project.ts index 03446d719..0c92970b7 100644 --- a/web/store/project.ts +++ b/web/store/project.ts @@ -15,9 +15,6 @@ export interface IProjectStore { loader: boolean; error: any | null; - projectLeaveModal: boolean; - projectLeaveDetails: IProject | any; - projectId: string | null; projects: { @@ -65,6 +62,9 @@ export interface IProjectStore { addProjectToFavorites: (workspaceSlug: string, projectSlug: string) => Promise; removeProjectFromFavorites: (workspaceSlug: string, projectSlug: string) => Promise; + orderProjectsWithSortOrder: (sourceIndex: number, destinationIndex: number, projectId: string) => number; + updateProjectView: (workspaceSlug: string, projectId: string, viewProps: any) => Promise; + handleProjectLeaveModal: (project: any | null) => void; leaveProject: (workspaceSlug: string, projectSlug: string, user: any) => Promise; @@ -150,6 +150,9 @@ class ProjectStore implements IProjectStore { addProjectToFavorites: action, removeProjectFromFavorites: action, + orderProjectsWithSortOrder: action, + updateProjectView: action, + handleProjectLeaveModal: action, leaveProject: action, }); @@ -421,6 +424,56 @@ class ProjectStore implements IProjectStore { } }; + orderProjectsWithSortOrder = (sortIndex: number, destinationIndex: number, projectId: string) => { + try { + const workspaceSlug = this.rootStore.workspace.workspaceSlug; + if (!workspaceSlug) return 0; + + const projectsList = this.rootStore.workspace.projects[workspaceSlug] || []; + let updatedSortOrder = projectsList[sortIndex].sort_order; + + if (destinationIndex === 0) updatedSortOrder = (projectsList[0].sort_order as number) - 1000; + else if (destinationIndex === projectsList.length - 1) + updatedSortOrder = (projectsList[projectsList.length - 1].sort_order as number) + 1000; + else { + const destinationSortingOrder = projectsList[destinationIndex].sort_order as number; + const relativeDestinationSortingOrder = + sortIndex < destinationIndex + ? (projectsList[destinationIndex + 1].sort_order as number) + : (projectsList[destinationIndex - 1].sort_order as number); + + updatedSortOrder = (destinationSortingOrder + relativeDestinationSortingOrder) / 2; + } + + const updatedProjectsList = projectsList.map((p) => + p.id === projectId ? { ...p, sort_order: updatedSortOrder } : p + ); + + runInAction(() => { + this.rootStore.workspace.projects = { + ...this.rootStore.workspace.projects, + [workspaceSlug]: updatedProjectsList, + }; + }); + + return updatedSortOrder; + } catch (error) { + console.log("failed to update sort order of the projects"); + return 0; + } + }; + + updateProjectView = async (workspaceSlug: string, projectId: string, viewProps: any) => { + try { + const response = await this.projectService.setProjectView(workspaceSlug, projectId, viewProps); + await this.rootStore.workspace.getWorkspaceProjects(workspaceSlug); + return response; + } catch (error) { + console.log("Failed to update sort order of the projects"); + throw error; + } + }; + handleProjectLeaveModal = (project: IProject | null = null) => { if (project && project?.id) { this.projectLeaveModal = !this.projectLeaveModal;