From 06722408b8992fb10f09add0beb5d4db4f8e6649 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia Date: Mon, 25 Sep 2023 15:00:35 +0530 Subject: [PATCH] chore: issue action added and code refactor --- .../views/spreadsheet-view/single-issue.tsx | 60 ++++- .../spreadsheet-view/spreadsheet-issues.tsx | 5 +- .../spreadsheet-view/spreadsheet-view.tsx | 1 + .../issues/sub-issues/properties.tsx | 2 + web/components/views/delete-view-modal.tsx | 3 +- web/components/views/single-view-item.tsx | 3 +- web/constants/fetch-keys.ts | 2 +- .../workspace-views/all-issues.tsx | 208 ++++++++++++----- .../workspace-views/assigned.tsx | 208 ++++++++++++----- .../workspace-views/created.tsx | 209 +++++++++++++----- .../[workspaceSlug]/workspace-views/index.tsx | 10 +- .../workspace-views/subscribed.tsx | 209 +++++++++++++----- web/services/workspace.service.ts | 14 +- web/types/views.d.ts | 6 + web/types/workspace-view.d.ts | 21 -- 15 files changed, 686 insertions(+), 275 deletions(-) delete mode 100644 web/types/workspace-view.d.ts diff --git a/web/components/core/views/spreadsheet-view/single-issue.tsx b/web/components/core/views/spreadsheet-view/single-issue.tsx index 32cb4ba77..ea8161c05 100644 --- a/web/components/core/views/spreadsheet-view/single-issue.tsx +++ b/web/components/core/views/spreadsheet-view/single-issue.tsx @@ -20,6 +20,7 @@ import { // hooks import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view"; import useToast from "hooks/use-toast"; +import useWorkspaceIssuesFilters from "hooks/use-worskpace-issue-filter"; // services import issuesService from "services/issues.service"; import trackEventServices from "services/track-event.service"; @@ -32,6 +33,7 @@ import { PROJECT_ISSUES_LIST_WITH_PARAMS, SUB_ISSUES, VIEW_ISSUES, + WORKSPACE_VIEW_ISSUES, } from "constants/fetch-keys"; // types import { @@ -82,12 +84,51 @@ export const SingleSpreadsheetIssue: React.FC = ({ const router = useRouter(); - const { workspaceSlug, cycleId, moduleId, viewId } = router.query; + const { workspaceSlug, cycleId, moduleId, viewId, workspaceViewId } = router.query; const { params } = useSpreadsheetIssuesView(); const { setToastAlert } = useToast(); + const workspaceIssuesPath = [ + { + params: { + sub_issue: false, + }, + path: "workspace-views/all-issues", + }, + { + params: { + assignees: user?.id ?? undefined, + sub_issue: false, + }, + path: "workspace-views/assigned", + }, + { + params: { + created_by: user?.id ?? undefined, + sub_issue: false, + }, + path: "workspace-views/created", + }, + { + params: { + subscriber: user?.id ?? undefined, + sub_issue: false, + }, + path: "workspace-views/subscribed", + }, + ]; + + const currentWorkspaceIssuePath = workspaceIssuesPath.find((path) => + router.pathname.includes(path.path) + ); + + const { params: workspaceViewParams } = useWorkspaceIssuesFilters( + workspaceSlug?.toString(), + workspaceViewId?.toString() + ); + const partialUpdateIssue = useCallback( (formData: Partial, issue: IIssue) => { if (!workspaceSlug || !projectId) return; @@ -98,6 +139,10 @@ export const SingleSpreadsheetIssue: React.FC = ({ ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params) : viewId ? VIEW_ISSUES(viewId.toString(), params) + : workspaceViewId + ? WORKSPACE_VIEW_ISSUES(workspaceSlug.toString(), workspaceViewParams) + : currentWorkspaceIssuePath + ? WORKSPACE_VIEW_ISSUES(workspaceSlug.toString(), currentWorkspaceIssuePath?.params) : PROJECT_ISSUES_LIST_WITH_PARAMS(projectId, params); if (issue.parent) @@ -153,7 +198,18 @@ export const SingleSpreadsheetIssue: React.FC = ({ console.log(error); }); }, - [workspaceSlug, projectId, cycleId, moduleId, viewId, params, user] + [ + workspaceSlug, + projectId, + cycleId, + moduleId, + viewId, + workspaceViewId, + currentWorkspaceIssuePath, + workspaceViewParams, + params, + user, + ] ); const openPeekOverview = () => { diff --git a/web/components/core/views/spreadsheet-view/spreadsheet-issues.tsx b/web/components/core/views/spreadsheet-view/spreadsheet-issues.tsx index ed63ed432..48eab1af8 100644 --- a/web/components/core/views/spreadsheet-view/spreadsheet-issues.tsx +++ b/web/components/core/views/spreadsheet-view/spreadsheet-issues.tsx @@ -9,6 +9,7 @@ import { ICurrentUserResponse, IIssue, Properties, UserAuth } from "types"; type Props = { issue: IIssue; + projectId: string; index: number; expandedIssues: string[]; setExpandedIssues: React.Dispatch>; @@ -24,6 +25,7 @@ type Props = { export const SpreadsheetIssues: React.FC = ({ index, issue, + projectId, expandedIssues, setExpandedIssues, gridTemplateColumns, @@ -55,7 +57,7 @@ export const SpreadsheetIssues: React.FC = ({
= ({ = ({ key={`${issue.id}_${index}`} index={index} issue={issue} + projectId={issue.project_detail.id} expandedIssues={expandedIssues} setExpandedIssues={setExpandedIssues} gridTemplateColumns={gridTemplateColumns} diff --git a/web/components/issues/sub-issues/properties.tsx b/web/components/issues/sub-issues/properties.tsx index 4f2dca43b..e2caefffa 100644 --- a/web/components/issues/sub-issues/properties.tsx +++ b/web/components/issues/sub-issues/properties.tsx @@ -161,6 +161,7 @@ export const IssueProperty: React.FC = ({
= ({
>; - data: IView | IWorkspaceView | null; + data: IView | null; user: ICurrentUserResponse | undefined; }; diff --git a/web/components/views/single-view-item.tsx b/web/components/views/single-view-item.tsx index 9d1ec0dc2..d27eb3cf1 100644 --- a/web/components/views/single-view-item.tsx +++ b/web/components/views/single-view-item.tsx @@ -12,7 +12,6 @@ import { CustomMenu } from "components/ui"; import viewsService from "services/views.service"; // types import { IView } from "types"; -import { IWorkspaceView } from "types/workspace-view"; // fetch keys import { VIEWS_LIST } from "constants/fetch-keys"; // hooks @@ -21,7 +20,7 @@ import useToast from "hooks/use-toast"; import { truncateText } from "helpers/string.helper"; type Props = { - view: IView | IWorkspaceView; + view: IView; viewType: "project" | "workspace"; handleEditView: () => void; handleDeleteView: () => void; diff --git a/web/constants/fetch-keys.ts b/web/constants/fetch-keys.ts index 6f138d735..75107a0bb 100644 --- a/web/constants/fetch-keys.ts +++ b/web/constants/fetch-keys.ts @@ -159,7 +159,7 @@ export const WORKSPACE_VIEWS_LIST = (workspaceSlug: string) => `WORKSPACE_VIEWS_LIST_${workspaceSlug.toUpperCase()}`; export const WORKSPACE_VIEW_DETAILS = (workspaceViewId: string) => `WORKSPACE_VIEW_DETAILS_${workspaceViewId.toUpperCase()}`; -export const WORKSPACE_VIEW_ISSUES = (workspaceViewId: string, params: any) => { +export const WORKSPACE_VIEW_ISSUES = (workspaceViewId: string, params?: any) => { if (!params) return `WORKSPACE_VIEW_ISSUES_${workspaceViewId.toUpperCase()}`; const paramsKey = paramsToKey(params); diff --git a/web/pages/[workspaceSlug]/workspace-views/all-issues.tsx b/web/pages/[workspaceSlug]/workspace-views/all-issues.tsx index dae32eb87..9c29b1805 100644 --- a/web/pages/[workspaceSlug]/workspace-views/all-issues.tsx +++ b/web/pages/[workspaceSlug]/workspace-views/all-issues.tsx @@ -1,3 +1,4 @@ +import { useCallback, useState } from "react"; import { useRouter } from "next/router"; import useSWR from "swr"; @@ -9,12 +10,12 @@ import useMyIssuesFilters from "hooks/my-issues/use-my-issues-filter"; import workspaceService from "services/workspace.service"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; -// contexts -import { IssueViewContextProvider } from "contexts/issue-view.context"; // components import { SpreadsheetView } from "components/core"; import { WorkspaceViewsNavigation } from "components/workspace/views/workpace-view-navigation"; import { WorkspaceIssuesViewOptions } from "components/issues/workspace-views/workspace-issue-view-option"; +import { CreateUpdateViewModal } from "components/views"; +import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues"; // ui import { EmptyState, PrimaryButton } from "components/ui"; // icons @@ -24,8 +25,28 @@ import { CheckCircle } from "lucide-react"; import emptyView from "public/empty-state/view.svg"; // fetch-keys import { WORKSPACE_VIEW_DETAILS, WORKSPACE_VIEW_ISSUES } from "constants/fetch-keys"; +// types +import { IIssue } from "types"; const WorkspaceViewAllIssue: React.FC = () => { + const [createViewModal, setCreateViewModal] = useState(null); + + // create issue modal + const [createIssueModal, setCreateIssueModal] = useState(false); + const [preloadedData, setPreloadedData] = useState< + (Partial & { actionType: "createIssue" | "edit" | "delete" }) | undefined + >(undefined); + + // update issue modal + const [editIssueModal, setEditIssueModal] = useState(false); + const [issueToEdit, setIssueToEdit] = useState< + (IIssue & { actionType: "edit" | "delete" }) | undefined + >(undefined); + + // delete issue modal + const [deleteIssueModal, setDeleteIssueModal] = useState(false); + const [issueToDelete, setIssueToDelete] = useState(null); + const router = useRouter(); const { workspaceSlug, workspaceViewId } = router.query; @@ -58,67 +79,138 @@ const WorkspaceViewAllIssue: React.FC = () => { workspaceSlug ? () => workspaceService.getViewIssues(workspaceSlug.toString(), params) : null ); + const makeIssueCopy = useCallback( + (issue: IIssue) => { + setCreateIssueModal(true); + + setPreloadedData({ ...issue, name: `${issue.name} (Copy)`, actionType: "createIssue" }); + }, + [setCreateIssueModal, setPreloadedData] + ); + + const handleEditIssue = useCallback( + (issue: IIssue) => { + setEditIssueModal(true); + setIssueToEdit({ + ...issue, + actionType: "edit", + cycle: issue.issue_cycle ? issue.issue_cycle.cycle : null, + module: issue.issue_module ? issue.issue_module.module : null, + }); + }, + [setEditIssueModal, setIssueToEdit] + ); + + const handleDeleteIssue = useCallback( + (issue: IIssue) => { + setDeleteIssueModal(true); + setIssueToDelete(issue); + }, + [setDeleteIssueModal, setIssueToDelete] + ); + + const handleIssueAction = useCallback( + (issue: IIssue, action: "copy" | "edit" | "delete" | "updateDraft") => { + if (action === "copy") makeIssueCopy(issue); + else if (action === "edit") handleEditIssue(issue); + else if (action === "delete") handleDeleteIssue(issue); + }, + [makeIssueCopy, handleEditIssue, handleDeleteIssue] + ); + return ( - - - - - {viewDetails ? `${viewDetails.name} Issues` : "Workspace Issues"} - -
- } - right={ -
- - { - const e = new KeyboardEvent("keydown", { key: "c" }); - document.dispatchEvent(e); + + + + {viewDetails ? `${viewDetails.name} Issues` : "Workspace Issues"} + +
+ } + right={ +
+ + { + const e = new KeyboardEvent("keydown", { key: "c" }); + document.dispatchEvent(e); + }} + > + + Add Issue + +
+ } + > + setCreateIssueModal(false)} + prePopulateData={{ + ...preloadedData, + }} + onSubmit={async () => { + mutateIssues(); + }} + /> + setEditIssueModal(false)} + data={issueToEdit} + onSubmit={async () => { + mutateIssues(); + }} + /> + setDeleteIssueModal(false)} + isOpen={deleteIssueModal} + data={issueToDelete} + user={user} + onSubmit={async () => { + mutateIssues(); + }} + /> + setCreateViewModal(null)} + viewType="workspace" + preLoadedData={createViewModal} + user={user} + /> +
+
+ setCreateViewModal(true)} /> + {error ? ( + router.push(`/${workspaceSlug}/workspace-views`), }} - > - - Add Issue - -
- } - > -
-
- - {error ? ( - router.push(`/${workspaceSlug}/workspace-views`), + /> + ) : ( +
+ - ) : ( -
- {}} - disableUserActions={false} - user={user} - userAuth={{ - isGuest: false, - isMember: false, - isOwner: false, - isViewer: false, - }} - /> -
- )} -
+
+ )}
- - +
+ ); }; diff --git a/web/pages/[workspaceSlug]/workspace-views/assigned.tsx b/web/pages/[workspaceSlug]/workspace-views/assigned.tsx index b67f8e033..c8195cc90 100644 --- a/web/pages/[workspaceSlug]/workspace-views/assigned.tsx +++ b/web/pages/[workspaceSlug]/workspace-views/assigned.tsx @@ -1,3 +1,4 @@ +import { useCallback, useState } from "react"; import { useRouter } from "next/router"; import useSWR from "swr"; @@ -9,12 +10,12 @@ import useMyIssuesFilters from "hooks/my-issues/use-my-issues-filter"; import workspaceService from "services/workspace.service"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; -// contexts -import { IssueViewContextProvider } from "contexts/issue-view.context"; // components import { SpreadsheetView } from "components/core"; import { WorkspaceViewsNavigation } from "components/workspace/views/workpace-view-navigation"; import { WorkspaceIssuesViewOptions } from "components/issues/workspace-views/workspace-issue-view-option"; +import { CreateUpdateViewModal } from "components/views"; +import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues"; // ui import { EmptyState, PrimaryButton } from "components/ui"; // icons @@ -24,8 +25,28 @@ import { CheckCircle } from "lucide-react"; import emptyView from "public/empty-state/view.svg"; // fetch-keys import { WORKSPACE_VIEW_DETAILS, WORKSPACE_VIEW_ISSUES } from "constants/fetch-keys"; +// types +import { IIssue } from "types"; const WorkspaceViewAssignedIssue: React.FC = () => { + const [createViewModal, setCreateViewModal] = useState(null); + + // create issue modal + const [createIssueModal, setCreateIssueModal] = useState(false); + const [preloadedData, setPreloadedData] = useState< + (Partial & { actionType: "createIssue" | "edit" | "delete" }) | undefined + >(undefined); + + // update issue modal + const [editIssueModal, setEditIssueModal] = useState(false); + const [issueToEdit, setIssueToEdit] = useState< + (IIssue & { actionType: "edit" | "delete" }) | undefined + >(undefined); + + // delete issue modal + const [deleteIssueModal, setDeleteIssueModal] = useState(false); + const [issueToDelete, setIssueToDelete] = useState(null); + const router = useRouter(); const { workspaceSlug, workspaceViewId } = router.query; @@ -58,67 +79,138 @@ const WorkspaceViewAssignedIssue: React.FC = () => { workspaceSlug ? () => workspaceService.getViewIssues(workspaceSlug.toString(), params) : null ); + const makeIssueCopy = useCallback( + (issue: IIssue) => { + setCreateIssueModal(true); + + setPreloadedData({ ...issue, name: `${issue.name} (Copy)`, actionType: "createIssue" }); + }, + [setCreateIssueModal, setPreloadedData] + ); + + const handleEditIssue = useCallback( + (issue: IIssue) => { + setEditIssueModal(true); + setIssueToEdit({ + ...issue, + actionType: "edit", + cycle: issue.issue_cycle ? issue.issue_cycle.cycle : null, + module: issue.issue_module ? issue.issue_module.module : null, + }); + }, + [setEditIssueModal, setIssueToEdit] + ); + + const handleDeleteIssue = useCallback( + (issue: IIssue) => { + setDeleteIssueModal(true); + setIssueToDelete(issue); + }, + [setDeleteIssueModal, setIssueToDelete] + ); + + const handleIssueAction = useCallback( + (issue: IIssue, action: "copy" | "edit" | "delete" | "updateDraft") => { + if (action === "copy") makeIssueCopy(issue); + else if (action === "edit") handleEditIssue(issue); + else if (action === "delete") handleDeleteIssue(issue); + }, + [makeIssueCopy, handleEditIssue, handleDeleteIssue] + ); + return ( - - - - - {viewDetails ? `${viewDetails.name} Issues` : "Workspace Issues"} - -
- } - right={ -
- - { - const e = new KeyboardEvent("keydown", { key: "c" }); - document.dispatchEvent(e); + + + + {viewDetails ? `${viewDetails.name} Issues` : "Workspace Issues"} + +
+ } + right={ +
+ + { + const e = new KeyboardEvent("keydown", { key: "c" }); + document.dispatchEvent(e); + }} + > + + Add Issue + +
+ } + > + setCreateIssueModal(false)} + prePopulateData={{ + ...preloadedData, + }} + onSubmit={async () => { + mutateIssues(); + }} + /> + setEditIssueModal(false)} + data={issueToEdit} + onSubmit={async () => { + mutateIssues(); + }} + /> + setDeleteIssueModal(false)} + isOpen={deleteIssueModal} + data={issueToDelete} + user={user} + onSubmit={async () => { + mutateIssues(); + }} + /> + setCreateViewModal(null)} + viewType="workspace" + preLoadedData={createViewModal} + user={user} + /> +
+
+ setCreateViewModal(true)} /> + {error ? ( + router.push(`/${workspaceSlug}/workspace-views`), }} - > - - Add Issue - -
- } - > -
-
- - {error ? ( - router.push(`/${workspaceSlug}/workspace-views`), + /> + ) : ( +
+ - ) : ( -
- {}} - disableUserActions={false} - user={user} - userAuth={{ - isGuest: false, - isMember: false, - isOwner: false, - isViewer: false, - }} - /> -
- )} -
+
+ )}
- - +
+ ); }; diff --git a/web/pages/[workspaceSlug]/workspace-views/created.tsx b/web/pages/[workspaceSlug]/workspace-views/created.tsx index 32fcec9ca..1b7b5c093 100644 --- a/web/pages/[workspaceSlug]/workspace-views/created.tsx +++ b/web/pages/[workspaceSlug]/workspace-views/created.tsx @@ -1,3 +1,5 @@ +import { useCallback, useState } from "react"; + import { useRouter } from "next/router"; import useSWR from "swr"; @@ -9,12 +11,12 @@ import useMyIssuesFilters from "hooks/my-issues/use-my-issues-filter"; import workspaceService from "services/workspace.service"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; -// contexts -import { IssueViewContextProvider } from "contexts/issue-view.context"; // components import { SpreadsheetView } from "components/core"; import { WorkspaceViewsNavigation } from "components/workspace/views/workpace-view-navigation"; import { WorkspaceIssuesViewOptions } from "components/issues/workspace-views/workspace-issue-view-option"; +import { CreateUpdateViewModal } from "components/views"; +import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues"; // ui import { EmptyState, PrimaryButton } from "components/ui"; // icons @@ -24,8 +26,28 @@ import { CheckCircle } from "lucide-react"; import emptyView from "public/empty-state/view.svg"; // fetch-keys import { WORKSPACE_VIEW_DETAILS, WORKSPACE_VIEW_ISSUES } from "constants/fetch-keys"; +// types +import { IIssue } from "types"; const WorkspaceViewCreatedIssue: React.FC = () => { + const [createViewModal, setCreateViewModal] = useState(null); + + // create issue modal + const [createIssueModal, setCreateIssueModal] = useState(false); + const [preloadedData, setPreloadedData] = useState< + (Partial & { actionType: "createIssue" | "edit" | "delete" }) | undefined + >(undefined); + + // update issue modal + const [editIssueModal, setEditIssueModal] = useState(false); + const [issueToEdit, setIssueToEdit] = useState< + (IIssue & { actionType: "edit" | "delete" }) | undefined + >(undefined); + + // delete issue modal + const [deleteIssueModal, setDeleteIssueModal] = useState(false); + const [issueToDelete, setIssueToDelete] = useState(null); + const router = useRouter(); const { workspaceSlug, workspaceViewId } = router.query; @@ -58,67 +80,138 @@ const WorkspaceViewCreatedIssue: React.FC = () => { workspaceSlug ? () => workspaceService.getViewIssues(workspaceSlug.toString(), params) : null ); + const makeIssueCopy = useCallback( + (issue: IIssue) => { + setCreateIssueModal(true); + + setPreloadedData({ ...issue, name: `${issue.name} (Copy)`, actionType: "createIssue" }); + }, + [setCreateIssueModal, setPreloadedData] + ); + + const handleEditIssue = useCallback( + (issue: IIssue) => { + setEditIssueModal(true); + setIssueToEdit({ + ...issue, + actionType: "edit", + cycle: issue.issue_cycle ? issue.issue_cycle.cycle : null, + module: issue.issue_module ? issue.issue_module.module : null, + }); + }, + [setEditIssueModal, setIssueToEdit] + ); + + const handleDeleteIssue = useCallback( + (issue: IIssue) => { + setDeleteIssueModal(true); + setIssueToDelete(issue); + }, + [setDeleteIssueModal, setIssueToDelete] + ); + + const handleIssueAction = useCallback( + (issue: IIssue, action: "copy" | "edit" | "delete" | "updateDraft") => { + if (action === "copy") makeIssueCopy(issue); + else if (action === "edit") handleEditIssue(issue); + else if (action === "delete") handleDeleteIssue(issue); + }, + [makeIssueCopy, handleEditIssue, handleDeleteIssue] + ); + return ( - - - - - {viewDetails ? `${viewDetails.name} Issues` : "Workspace Issues"} - -
- } - right={ -
- - { - const e = new KeyboardEvent("keydown", { key: "c" }); - document.dispatchEvent(e); + + + + {viewDetails ? `${viewDetails.name} Issues` : "Workspace Issues"} + +
+ } + right={ +
+ + { + const e = new KeyboardEvent("keydown", { key: "c" }); + document.dispatchEvent(e); + }} + > + + Add Issue + +
+ } + > + setCreateIssueModal(false)} + prePopulateData={{ + ...preloadedData, + }} + onSubmit={async () => { + mutateIssues(); + }} + /> + setEditIssueModal(false)} + data={issueToEdit} + onSubmit={async () => { + mutateIssues(); + }} + /> + setDeleteIssueModal(false)} + isOpen={deleteIssueModal} + data={issueToDelete} + user={user} + onSubmit={async () => { + mutateIssues(); + }} + /> + setCreateViewModal(null)} + viewType="workspace" + preLoadedData={createViewModal} + user={user} + /> +
+
+ setCreateViewModal(true)} /> + {error ? ( + router.push(`/${workspaceSlug}/workspace-views`), }} - > - - Add Issue - -
- } - > -
-
- - {error ? ( - router.push(`/${workspaceSlug}/workspace-views`), + /> + ) : ( +
+ - ) : ( -
- {}} - disableUserActions={false} - user={user} - userAuth={{ - isGuest: false, - isMember: false, - isOwner: false, - isViewer: false, - }} - /> -
- )} -
+
+ )}
- - +
+ ); }; diff --git a/web/pages/[workspaceSlug]/workspace-views/index.tsx b/web/pages/[workspaceSlug]/workspace-views/index.tsx index 115638799..13d01ebfd 100644 --- a/web/pages/[workspaceSlug]/workspace-views/index.tsx +++ b/web/pages/[workspaceSlug]/workspace-views/index.tsx @@ -25,7 +25,7 @@ import { PhotoFilterOutlined } from "@mui/icons-material"; import emptyView from "public/empty-state/view.svg"; // types import type { NextPage } from "next"; -import { IWorkspaceView } from "types/workspace-view"; +import { IView } from "types"; // constants import { WORKSPACE_VIEWS_LIST } from "constants/fetch-keys"; // helper @@ -33,17 +33,17 @@ import { truncateText } from "helpers/string.helper"; const WorkspaceViews: NextPage = () => { const [createUpdateViewModal, setCreateUpdateViewModal] = useState(false); - const [selectedViewToUpdate, setSelectedViewToUpdate] = useState(null); + const [selectedViewToUpdate, setSelectedViewToUpdate] = useState(null); const [deleteViewModal, setDeleteViewModal] = useState(false); - const [selectedViewToDelete, setSelectedViewToDelete] = useState(null); + const [selectedViewToDelete, setSelectedViewToDelete] = useState(null); - const handleEditView = (view: IWorkspaceView) => { + const handleEditView = (view: IView) => { setSelectedViewToUpdate(view); setCreateUpdateViewModal(true); }; - const handleDeleteView = (view: IWorkspaceView) => { + const handleDeleteView = (view: IView) => { setSelectedViewToDelete(view); setDeleteViewModal(true); }; diff --git a/web/pages/[workspaceSlug]/workspace-views/subscribed.tsx b/web/pages/[workspaceSlug]/workspace-views/subscribed.tsx index e970cf384..2f5c22e51 100644 --- a/web/pages/[workspaceSlug]/workspace-views/subscribed.tsx +++ b/web/pages/[workspaceSlug]/workspace-views/subscribed.tsx @@ -1,3 +1,5 @@ +import { useCallback, useState } from "react"; + import { useRouter } from "next/router"; import useSWR from "swr"; @@ -9,12 +11,12 @@ import useMyIssuesFilters from "hooks/my-issues/use-my-issues-filter"; import workspaceService from "services/workspace.service"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; -// contexts -import { IssueViewContextProvider } from "contexts/issue-view.context"; // components import { SpreadsheetView } from "components/core"; import { WorkspaceViewsNavigation } from "components/workspace/views/workpace-view-navigation"; import { WorkspaceIssuesViewOptions } from "components/issues/workspace-views/workspace-issue-view-option"; +import { CreateUpdateViewModal } from "components/views"; +import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues"; // ui import { EmptyState, PrimaryButton } from "components/ui"; // icons @@ -24,8 +26,28 @@ import { CheckCircle } from "lucide-react"; import emptyView from "public/empty-state/view.svg"; // fetch-keys import { WORKSPACE_VIEW_DETAILS, WORKSPACE_VIEW_ISSUES } from "constants/fetch-keys"; +// types +import { IIssue } from "types"; const WorkspaceViewSubscribedIssue: React.FC = () => { + const [createViewModal, setCreateViewModal] = useState(null); + + // create issue modal + const [createIssueModal, setCreateIssueModal] = useState(false); + const [preloadedData, setPreloadedData] = useState< + (Partial & { actionType: "createIssue" | "edit" | "delete" }) | undefined + >(undefined); + + // update issue modal + const [editIssueModal, setEditIssueModal] = useState(false); + const [issueToEdit, setIssueToEdit] = useState< + (IIssue & { actionType: "edit" | "delete" }) | undefined + >(undefined); + + // delete issue modal + const [deleteIssueModal, setDeleteIssueModal] = useState(false); + const [issueToDelete, setIssueToDelete] = useState(null); + const router = useRouter(); const { workspaceSlug, workspaceViewId } = router.query; @@ -58,67 +80,138 @@ const WorkspaceViewSubscribedIssue: React.FC = () => { workspaceSlug ? () => workspaceService.getViewIssues(workspaceSlug.toString(), params) : null ); + const makeIssueCopy = useCallback( + (issue: IIssue) => { + setCreateIssueModal(true); + + setPreloadedData({ ...issue, name: `${issue.name} (Copy)`, actionType: "createIssue" }); + }, + [setCreateIssueModal, setPreloadedData] + ); + + const handleEditIssue = useCallback( + (issue: IIssue) => { + setEditIssueModal(true); + setIssueToEdit({ + ...issue, + actionType: "edit", + cycle: issue.issue_cycle ? issue.issue_cycle.cycle : null, + module: issue.issue_module ? issue.issue_module.module : null, + }); + }, + [setEditIssueModal, setIssueToEdit] + ); + + const handleDeleteIssue = useCallback( + (issue: IIssue) => { + setDeleteIssueModal(true); + setIssueToDelete(issue); + }, + [setDeleteIssueModal, setIssueToDelete] + ); + + const handleIssueAction = useCallback( + (issue: IIssue, action: "copy" | "edit" | "delete" | "updateDraft") => { + if (action === "copy") makeIssueCopy(issue); + else if (action === "edit") handleEditIssue(issue); + else if (action === "delete") handleDeleteIssue(issue); + }, + [makeIssueCopy, handleEditIssue, handleDeleteIssue] + ); + return ( - - - - - {viewDetails ? `${viewDetails.name} Issues` : "Workspace Issues"} - - - } - right={ -
- - { - const e = new KeyboardEvent("keydown", { key: "c" }); - document.dispatchEvent(e); + + + + {viewDetails ? `${viewDetails.name} Issues` : "Workspace Issues"} + +
+ } + right={ +
+ + { + const e = new KeyboardEvent("keydown", { key: "c" }); + document.dispatchEvent(e); + }} + > + + Add Issue + +
+ } + > + setCreateIssueModal(false)} + prePopulateData={{ + ...preloadedData, + }} + onSubmit={async () => { + mutateIssues(); + }} + /> + setEditIssueModal(false)} + data={issueToEdit} + onSubmit={async () => { + mutateIssues(); + }} + /> + setDeleteIssueModal(false)} + isOpen={deleteIssueModal} + data={issueToDelete} + user={user} + onSubmit={async () => { + mutateIssues(); + }} + /> + setCreateViewModal(null)} + viewType="workspace" + preLoadedData={createViewModal} + user={user} + /> +
+
+ setCreateViewModal(true)} /> + {error ? ( + router.push(`/${workspaceSlug}/workspace-views`), }} - > - - Add Issue - -
- } - > -
-
- - {error ? ( - router.push(`/${workspaceSlug}/workspace-views`), + /> + ) : ( +
+ - ) : ( -
- {}} - disableUserActions={false} - user={user} - userAuth={{ - isGuest: false, - isMember: false, - isOwner: false, - isViewer: false, - }} - /> -
- )} -
+
+ )}
- - +
+
); }; diff --git a/web/services/workspace.service.ts b/web/services/workspace.service.ts index 00dd79c48..a3aa56507 100644 --- a/web/services/workspace.service.ts +++ b/web/services/workspace.service.ts @@ -14,9 +14,9 @@ import { ICurrentUserResponse, IWorkspaceBulkInviteFormData, IWorkspaceViewProps, + IView, IIssueFilterOptions, } from "types"; -import { IWorkspaceView } from "types/workspace-view"; class WorkspaceService extends APIService { constructor() { @@ -264,7 +264,7 @@ class WorkspaceService extends APIService { }); } - async createView(workspaceSlug: string, data: IWorkspaceView): Promise { + async createView(workspaceSlug: string, data: IView): Promise { return this.post(`/api/workspaces/${workspaceSlug}/views/`, data) .then((response) => response?.data) .catch((error) => { @@ -272,11 +272,7 @@ class WorkspaceService extends APIService { }); } - async updateView( - workspaceSlug: string, - viewId: string, - data: Partial - ): Promise { + async updateView(workspaceSlug: string, viewId: string, data: Partial): Promise { return this.patch(`/api/workspaces/${workspaceSlug}/views/${viewId}/`, data) .then((response) => response?.data) .catch((error) => { @@ -292,7 +288,7 @@ class WorkspaceService extends APIService { }); } - async getAllViews(workspaceSlug: string): Promise { + async getAllViews(workspaceSlug: string): Promise { return this.get(`/api/workspaces/${workspaceSlug}/views/`) .then((response) => response?.data) .catch((error) => { @@ -300,7 +296,7 @@ class WorkspaceService extends APIService { }); } - async getViewDetails(workspaceSlug: string, viewId: string): Promise { + async getViewDetails(workspaceSlug: string, viewId: string): Promise { return this.get(`/api/workspaces/${workspaceSlug}/views/${viewId}/`) .then((response) => response?.data) .catch((error) => { diff --git a/web/types/views.d.ts b/web/types/views.d.ts index 527e90833..94a90c1e0 100644 --- a/web/types/views.d.ts +++ b/web/types/views.d.ts @@ -14,6 +14,11 @@ export interface IView { query_data: IIssueFilterOptions; project: string; workspace: string; + workspace_detail: { + id: string; + name: string; + slug: string; + }; } export interface IQuery { @@ -25,4 +30,5 @@ export interface IQuery { start_date: string[] | null; target_date: string[] | null; type: "active" | "backlog" | null; + projects: string[] | null; } diff --git a/web/types/workspace-view.d.ts b/web/types/workspace-view.d.ts deleted file mode 100644 index bb1b3a45f..000000000 --- a/web/types/workspace-view.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { IIssueFilterOptions } from "./view-props"; - -export interface IWorkspaceView { - access: string; - created_at: Date; - created_by: string; - description: string; - id: string; - name: string; - query: IIssueFilterOptions; - query_data: IIssueFilterOptions; - updated_at: Date; - updated_by: string; - is_favorite: boolean; - workspace: string; - workspace_detail: { - id: string; - name: string; - slug: string; - }; -}