From 3947a86fa78dc04e77912235d3589bfb24b29657 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Sat, 8 Apr 2023 13:46:46 +0530 Subject: [PATCH] fix: new auth layer (#740) * chore: made workspace authorization wrapper component * chore: added todos * chore: workspace pages new layout * chore: project authorization wrapper * chore: new project authorization wrapper * fix: authorization for member roles * chore: new auth screens ui --------- Co-authored-by: Dakshesh Jain --- apps/app/components/auth-screens/index.ts | 3 + .../not-authorized-view.tsx | 21 +- .../components/auth-screens/project/index.ts | 1 + .../auth-screens/project/join-project.tsx | 64 ++++ .../auth-screens/workspace/index.ts | 1 + .../auth-screens/workspace/not-a-member.tsx | 46 +++ apps/app/components/core/index.ts | 1 - apps/app/components/core/issues-view.tsx | 10 +- .../components/issues/description-form.tsx | 15 +- apps/app/components/issues/sidebar.tsx | 30 +- .../app/components/issues/sub-issues-list.tsx | 11 +- apps/app/components/modules/sidebar.tsx | 26 +- .../project/create-project-modal.tsx | 1 - apps/app/components/project/index.ts | 1 - apps/app/components/project/join-project.tsx | 41 --- apps/app/contexts/project-member.context.tsx | 73 +++++ apps/app/layouts/app-layout/index.tsx | 22 +- apps/app/layouts/auth-layout/index.ts | 2 + .../project-authorization-wrapper.tsx | 141 ++++++++ .../workspace-authorization-wrapper.tsx | 158 +++++++++ apps/app/layouts/settings-navbar.tsx | 2 +- apps/app/pages/[workspaceSlug]/index.tsx | 35 +- .../pages/[workspaceSlug]/me/my-issues.tsx | 307 +++++++++--------- .../[workspaceSlug]/me/profile/activity.tsx | 35 +- .../[workspaceSlug]/me/profile/index.tsx | 32 +- .../projects/[projectId]/cycles/[cycleId].tsx | 44 +-- .../projects/[projectId]/cycles/index.tsx | 56 +--- .../projects/[projectId]/issues/[issueId].tsx | 57 +--- .../projects/[projectId]/issues/index.tsx | 45 +-- .../[projectId]/modules/[moduleId].tsx | 51 +-- .../projects/[projectId]/modules/index.tsx | 55 +--- .../projects/[projectId]/pages/[pageId].tsx | 44 +-- .../projects/[projectId]/pages/index.tsx | 46 +-- .../projects/[projectId]/settings/control.tsx | 45 +-- .../[projectId]/settings/estimates.tsx | 36 +- .../[projectId]/settings/features.tsx | 32 +- .../projects/[projectId]/settings/index.tsx | 34 +- .../[projectId]/settings/integrations.tsx | 34 +- .../projects/[projectId]/settings/labels.tsx | 28 +- .../projects/[projectId]/settings/members.tsx | 31 +- .../projects/[projectId]/settings/states.tsx | 33 +- .../projects/[projectId]/views/[viewId].tsx | 56 +--- .../projects/[projectId]/views/index.tsx | 56 +--- .../pages/[workspaceSlug]/projects/index.tsx | 34 +- .../[workspaceSlug]/settings/billing.tsx | 111 +++---- .../settings/import-export.tsx | 40 +-- .../pages/[workspaceSlug]/settings/index.tsx | 45 +-- .../[workspaceSlug]/settings/integrations.tsx | 101 ++---- .../[workspaceSlug]/settings/members.tsx | 39 +-- .../pages/installations/[provider]/index.tsx | 1 - apps/app/public/{ => auth}/join-project.svg | 0 .../project-not-authorized.svg} | 0 .../public/auth/workspace-not-authorized.svg | 44 +++ apps/app/services/project.service.ts | 2 +- apps/app/services/workspace.service.ts | 2 +- 55 files changed, 997 insertions(+), 1284 deletions(-) create mode 100644 apps/app/components/auth-screens/index.ts rename apps/app/components/{core => auth-screens}/not-authorized-view.tsx (73%) create mode 100644 apps/app/components/auth-screens/project/index.ts create mode 100644 apps/app/components/auth-screens/project/join-project.tsx create mode 100644 apps/app/components/auth-screens/workspace/index.ts create mode 100644 apps/app/components/auth-screens/workspace/not-a-member.tsx delete mode 100644 apps/app/components/project/join-project.tsx create mode 100644 apps/app/contexts/project-member.context.tsx create mode 100644 apps/app/layouts/auth-layout/index.ts create mode 100644 apps/app/layouts/auth-layout/project-authorization-wrapper.tsx create mode 100644 apps/app/layouts/auth-layout/workspace-authorization-wrapper.tsx rename apps/app/public/{ => auth}/join-project.svg (100%) rename apps/app/public/{project-setting.svg => auth/project-not-authorized.svg} (100%) create mode 100644 apps/app/public/auth/workspace-not-authorized.svg diff --git a/apps/app/components/auth-screens/index.ts b/apps/app/components/auth-screens/index.ts new file mode 100644 index 000000000..2a0bd4423 --- /dev/null +++ b/apps/app/components/auth-screens/index.ts @@ -0,0 +1,3 @@ +export * from "./project"; +export * from "./workspace"; +export * from "./not-authorized-view"; diff --git a/apps/app/components/core/not-authorized-view.tsx b/apps/app/components/auth-screens/not-authorized-view.tsx similarity index 73% rename from apps/app/components/core/not-authorized-view.tsx rename to apps/app/components/auth-screens/not-authorized-view.tsx index 97f3bddac..aaa59d6c6 100644 --- a/apps/app/components/core/not-authorized-view.tsx +++ b/apps/app/components/auth-screens/not-authorized-view.tsx @@ -7,16 +7,16 @@ import { useRouter } from "next/router"; import DefaultLayout from "layouts/default-layout"; // hooks import useUser from "hooks/use-user"; -// img -import ProjectSettingImg from "public/project-setting.svg"; +// images +import ProjectNotAuthorizedImg from "public/auth/project-not-authorized.svg"; +import WorkspaceNotAuthorizedImg from "public/auth/workspace-not-authorized.svg"; -type TNotAuthorizedViewProps = { +type Props = { actionButton?: React.ReactNode; + type: "project" | "workspace"; }; -export const NotAuthorizedView: React.FC = (props) => { - const { actionButton } = props; - +export const NotAuthorizedView: React.FC = ({ actionButton, type }) => { const { user } = useUser(); const { asPath: currentPath } = useRouter(); @@ -29,7 +29,12 @@ export const NotAuthorizedView: React.FC = (props) => { >
- ProjectSettingImg + ProjectSettingImg

Oops! You are not authorized to view this page @@ -38,7 +43,7 @@ export const NotAuthorizedView: React.FC = (props) => {
{user ? (

- You have signed in as {user.email}.{" "} + You have signed in as {user.email}.
Sign in {" "} diff --git a/apps/app/components/auth-screens/project/index.ts b/apps/app/components/auth-screens/project/index.ts new file mode 100644 index 000000000..1fb77e697 --- /dev/null +++ b/apps/app/components/auth-screens/project/index.ts @@ -0,0 +1 @@ +export * from "./join-project"; diff --git a/apps/app/components/auth-screens/project/join-project.tsx b/apps/app/components/auth-screens/project/join-project.tsx new file mode 100644 index 000000000..285fdc1bc --- /dev/null +++ b/apps/app/components/auth-screens/project/join-project.tsx @@ -0,0 +1,64 @@ +import { useState } from "react"; + +import Image from "next/image"; +import { useRouter } from "next/router"; + +import { mutate } from "swr"; + +// ui +import { PrimaryButton } from "components/ui"; +// icon +import { AssignmentClipboardIcon } from "components/icons"; +// img +import JoinProjectImg from "public/auth/project-not-authorized.svg"; +import projectService from "services/project.service"; +// fetch-keys +import { PROJECT_MEMBERS } from "constants/fetch-keys"; + +export const JoinProject: React.FC = () => { + const [isJoiningProject, setIsJoiningProject] = useState(false); + + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const handleJoin = () => { + setIsJoiningProject(true); + projectService + .joinProject(workspaceSlug as string, { + project_ids: [projectId as string], + }) + .then(() => { + setIsJoiningProject(false); + mutate(PROJECT_MEMBERS(projectId as string)); + }) + .catch((err) => { + console.error(err); + }); + }; + + return ( +

+
+ JoinProject +
+

You are not a member of this project

+ +
+

+ You are not a member of this project, but you can join this project by clicking the button + below. +

+
+
+ + + {isJoiningProject ? "Joining..." : "Click to join"} + +
+
+ ); +}; diff --git a/apps/app/components/auth-screens/workspace/index.ts b/apps/app/components/auth-screens/workspace/index.ts new file mode 100644 index 000000000..828324312 --- /dev/null +++ b/apps/app/components/auth-screens/workspace/index.ts @@ -0,0 +1 @@ +export * from "./not-a-member"; diff --git a/apps/app/components/auth-screens/workspace/not-a-member.tsx b/apps/app/components/auth-screens/workspace/not-a-member.tsx new file mode 100644 index 000000000..f630b484c --- /dev/null +++ b/apps/app/components/auth-screens/workspace/not-a-member.tsx @@ -0,0 +1,46 @@ +import Link from "next/link"; +import { useRouter } from "next/router"; + +// layouts +import DefaultLayout from "layouts/default-layout"; +// ui +import { PrimaryButton, SecondaryButton } from "components/ui"; + +export const NotAWorkspaceMember = () => { + const router = useRouter(); + + return ( + +
+
+
+

Not Authorized!

+

+ You{"'"}re not a member of this workspace. Please contact the workspace admin to get + an invitation or check your pending invitations. +

+
+ +
+
+
+ ); +}; diff --git a/apps/app/components/core/index.ts b/apps/app/components/core/index.ts index 93135aad1..41a71d965 100644 --- a/apps/app/components/core/index.ts +++ b/apps/app/components/core/index.ts @@ -8,7 +8,6 @@ export * from "./image-upload-modal"; export * from "./issues-view-filter"; export * from "./issues-view"; export * from "./link-modal"; -export * from "./not-authorized-view"; export * from "./image-picker-popover"; export * from "./filter-list"; export * from "./feeds"; diff --git a/apps/app/components/core/issues-view.tsx b/apps/app/components/core/issues-view.tsx index be78d6c0a..eb1e379c6 100644 --- a/apps/app/components/core/issues-view.tsx +++ b/apps/app/components/core/issues-view.tsx @@ -11,6 +11,8 @@ import issuesService from "services/issues.service"; import stateService from "services/state.service"; import modulesService from "services/modules.service"; import trackEventServices from "services/track-event.service"; +// contexts +import { useProjectMyMembership } from "contexts/project-member.context"; // hooks import useToast from "hooks/use-toast"; import useIssuesView from "hooks/use-issues-view"; @@ -49,14 +51,12 @@ type Props = { type?: "issue" | "cycle" | "module"; openIssuesListModal?: () => void; isCompleted?: boolean; - userAuth: UserAuth; }; export const IssuesView: React.FC = ({ type = "issue", openIssuesListModal, isCompleted = false, - userAuth, }) => { // create issue modal const [createIssueModal, setCreateIssueModal] = useState(false); @@ -84,6 +84,8 @@ export const IssuesView: React.FC = ({ const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; + const { memberRole } = useProjectMyMembership(); + const { setToastAlert } = useToast(); const { @@ -494,7 +496,7 @@ export const IssuesView: React.FC = ({ : null } isCompleted={isCompleted} - userAuth={userAuth} + userAuth={memberRole} /> ) : issueView === "kanban" ? ( = ({ : null } isCompleted={isCompleted} - userAuth={userAuth} + userAuth={memberRole} /> ) : ( diff --git a/apps/app/components/issues/description-form.tsx b/apps/app/components/issues/description-form.tsx index 666b30964..95962b929 100644 --- a/apps/app/components/issues/description-form.tsx +++ b/apps/app/components/issues/description-form.tsx @@ -4,6 +4,8 @@ import dynamic from "next/dynamic"; // react-hook-form import { Controller, useForm } from "react-hook-form"; +// contexts +import { useProjectMyMembership } from "contexts/project-member.context"; // components import { Loader, TextArea } from "components/ui"; const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor"), { @@ -15,7 +17,7 @@ const RemirrorRichTextEditor = dynamic(() => import("components/rich-text-editor ), }); // types -import { IIssue, UserAuth } from "types"; +import { IIssue } from "types"; export interface IssueDescriptionFormValues { name: string; @@ -26,17 +28,14 @@ export interface IssueDescriptionFormValues { export interface IssueDetailsProps { issue: IIssue; handleFormSubmit: (value: IssueDescriptionFormValues) => Promise; - userAuth: UserAuth; } -export const IssueDescriptionForm: FC = ({ - issue, - handleFormSubmit, - userAuth, -}) => { +export const IssueDescriptionForm: FC = ({ issue, handleFormSubmit }) => { const [isSubmitting, setIsSubmitting] = useState(false); const [characterLimit, setCharacterLimit] = useState(false); + const { memberRole } = useProjectMyMembership(); + const { handleSubmit, watch, @@ -86,7 +85,7 @@ export const IssueDescriptionForm: FC = ({ reset(issue); }, [issue, reset]); - const isNotAllowed = userAuth.isGuest || userAuth.isViewer; + const isNotAllowed = memberRole.isGuest || memberRole.isViewer; return (
diff --git a/apps/app/components/issues/sidebar.tsx b/apps/app/components/issues/sidebar.tsx index 5721b965d..a9c6149a6 100644 --- a/apps/app/components/issues/sidebar.tsx +++ b/apps/app/components/issues/sidebar.tsx @@ -15,6 +15,8 @@ import useToast from "hooks/use-toast"; // services import issuesService from "services/issues.service"; import modulesService from "services/modules.service"; +// contexts +import { useProjectMyMembership } from "contexts/project-member.context"; // components import { LinkModal, LinksList } from "components/core"; import { @@ -45,7 +47,7 @@ import { // helpers import { copyTextToClipboard } from "helpers/string.helper"; // types -import type { ICycle, IIssue, IIssueLabels, IIssueLink, IModule, UserAuth } from "types"; +import type { ICycle, IIssue, IIssueLabels, IIssueLink, IModule } from "types"; // fetch-keys import { PROJECT_ISSUE_LABELS, PROJECT_ISSUES_LIST, ISSUE_DETAILS } from "constants/fetch-keys"; @@ -54,7 +56,6 @@ type Props = { submitChanges: (formData: Partial) => void; issueDetail: IIssue | undefined; watch: UseFormWatch; - userAuth: UserAuth; }; const defaultValues: Partial = { @@ -67,7 +68,6 @@ export const IssueDetailsSidebar: React.FC = ({ submitChanges, issueDetail, watch: watchIssue, - userAuth, }) => { const [createLabelForm, setCreateLabelForm] = useState(false); const [deleteIssueModal, setDeleteIssueModal] = useState(false); @@ -76,6 +76,8 @@ export const IssueDetailsSidebar: React.FC = ({ const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; + const { memberRole } = useProjectMyMembership(); + const { setToastAlert } = useToast(); const { data: issues } = useSWR( @@ -213,7 +215,7 @@ export const IssueDetailsSidebar: React.FC = ({ reset(); }, [createLabelForm, reset]); - const isNotAllowed = userAuth.isGuest || userAuth.isViewer; + const isNotAllowed = memberRole.isGuest || memberRole.isViewer; return ( <> @@ -260,7 +262,7 @@ export const IssueDetailsSidebar: React.FC = ({ submitChanges({ state: val })} - userAuth={userAuth} + userAuth={memberRole} /> )} /> @@ -271,7 +273,7 @@ export const IssueDetailsSidebar: React.FC = ({ submitChanges({ assignees_list: val })} - userAuth={userAuth} + userAuth={memberRole} /> )} /> @@ -282,7 +284,7 @@ export const IssueDetailsSidebar: React.FC = ({ submitChanges({ priority: val })} - userAuth={userAuth} + userAuth={memberRole} /> )} /> @@ -293,7 +295,7 @@ export const IssueDetailsSidebar: React.FC = ({ submitChanges({ estimate_point: val })} - userAuth={userAuth} + userAuth={memberRole} /> )} /> @@ -327,19 +329,19 @@ export const IssueDetailsSidebar: React.FC = ({ ) } watch={watchIssue} - userAuth={userAuth} + userAuth={memberRole} /> i.id !== issueDetail?.id) ?? []} watch={watchIssue} - userAuth={userAuth} + userAuth={memberRole} /> i.id !== issueDetail?.id) ?? []} watch={watchIssue} - userAuth={userAuth} + userAuth={memberRole} />
@@ -369,12 +371,12 @@ export const IssueDetailsSidebar: React.FC = ({
@@ -637,7 +639,7 @@ export const IssueDetailsSidebar: React.FC = ({ ) : null}
diff --git a/apps/app/components/issues/sub-issues-list.tsx b/apps/app/components/issues/sub-issues-list.tsx index e7d769a43..0c9bd879e 100644 --- a/apps/app/components/issues/sub-issues-list.tsx +++ b/apps/app/components/issues/sub-issues-list.tsx @@ -9,6 +9,8 @@ import useSWR, { mutate } from "swr"; import { Disclosure, Transition } from "@headlessui/react"; // services import issuesService from "services/issues.service"; +// contexts +import { useProjectMyMembership } from "contexts/project-member.context"; // components import { ExistingIssuesListModal } from "components/core"; import { CreateUpdateIssueModal } from "components/issues"; @@ -19,16 +21,15 @@ import { ChevronRightIcon, PlusIcon, XMarkIcon } from "@heroicons/react/24/outli // helpers import { orderArrayBy } from "helpers/array.helper"; // types -import { IIssue, UserAuth } from "types"; +import { IIssue } from "types"; // fetch-keys import { PROJECT_ISSUES_LIST, SUB_ISSUES } from "constants/fetch-keys"; type Props = { parentIssue: IIssue; - userAuth: UserAuth; }; -export const SubIssuesList: FC = ({ parentIssue, userAuth }) => { +export const SubIssuesList: FC = ({ parentIssue }) => { // states const [createIssueModal, setCreateIssueModal] = useState(false); const [subIssuesListModal, setSubIssuesListModal] = useState(false); @@ -37,6 +38,8 @@ export const SubIssuesList: FC = ({ parentIssue, userAuth }) => { const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; + const { memberRole } = useProjectMyMembership(); + const { data: subIssues } = useSWR( workspaceSlug && projectId && issueId ? SUB_ISSUES(issueId as string) : null, workspaceSlug && projectId && issueId @@ -143,7 +146,7 @@ export const SubIssuesList: FC = ({ parentIssue, userAuth }) => { }); }; - const isNotAllowed = userAuth.isGuest || userAuth.isViewer; + const isNotAllowed = memberRole.isGuest || memberRole.isViewer; return ( <> diff --git a/apps/app/components/modules/sidebar.tsx b/apps/app/components/modules/sidebar.tsx index 4ecf8cdd2..f35d5ee18 100644 --- a/apps/app/components/modules/sidebar.tsx +++ b/apps/app/components/modules/sidebar.tsx @@ -21,6 +21,8 @@ import { Disclosure, Popover, Transition } from "@headlessui/react"; import DatePicker from "react-datepicker"; // services import modulesService from "services/modules.service"; +// contexts +import { useProjectMyMembership } from "contexts/project-member.context"; // hooks import useToast from "hooks/use-toast"; // components @@ -30,17 +32,16 @@ import ProgressChart from "components/core/sidebar/progress-chart"; import { CustomMenu, CustomSelect, Loader, ProgressBar } from "components/ui"; // icon import { ExclamationIcon } from "components/icons"; +import { LinkIcon } from "@heroicons/react/20/solid"; // helpers -import { isDateRangeValid, renderDateFormat, renderShortDate } from "helpers/date-time.helper"; +import { renderDateFormat, renderShortDate } from "helpers/date-time.helper"; import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper"; -import { groupBy } from "helpers/array.helper"; // types -import { IIssue, IModule, ModuleLink, UserAuth } from "types"; +import { IIssue, IModule, ModuleLink } from "types"; // fetch-keys import { MODULE_DETAILS } from "constants/fetch-keys"; // constant import { MODULE_STATUS } from "constants/module"; -import { LinkIcon } from "@heroicons/react/20/solid"; const defaultValues: Partial = { lead: "", @@ -55,22 +56,17 @@ type Props = { module?: IModule; isOpen: boolean; moduleIssues?: IIssue[]; - userAuth: UserAuth; }; -export const ModuleDetailsSidebar: React.FC = ({ - issues, - module, - isOpen, - moduleIssues, - userAuth, -}) => { +export const ModuleDetailsSidebar: React.FC = ({ issues, module, isOpen, moduleIssues }) => { const [moduleDeleteModal, setModuleDeleteModal] = useState(false); const [moduleLinkModal, setModuleLinkModal] = useState(false); const router = useRouter(); const { workspaceSlug, projectId, moduleId } = router.query; + const { memberRole } = useProjectMyMembership(); + const { setToastAlert } = useToast(); const { reset, watch, control } = useForm({ @@ -516,7 +512,7 @@ export const ModuleDetailsSidebar: React.FC = ({ completed: module.completed_issues, cancelled: module.cancelled_issues, }} - userAuth={userAuth} + userAuth={memberRole} module={module} />
@@ -542,11 +538,11 @@ export const ModuleDetailsSidebar: React.FC = ({

- {userAuth && module.link_module && module.link_module.length > 0 ? ( + {memberRole && module.link_module && module.link_module.length > 0 ? ( ) : null}
diff --git a/apps/app/components/project/create-project-modal.tsx b/apps/app/components/project/create-project-modal.tsx index 3ef18f5f9..1669032f7 100644 --- a/apps/app/components/project/create-project-modal.tsx +++ b/apps/app/components/project/create-project-modal.tsx @@ -147,7 +147,6 @@ export const CreateProjectModal: React.FC = (props) => { }); }; - // FIXME: remove this and authorize using getServerSideProps if (myWorkspaceMembership && isOpen) { if (myWorkspaceMembership.role <= 10) return ; } diff --git a/apps/app/components/project/index.ts b/apps/app/components/project/index.ts index 3e00dd34e..47d7a4b1c 100644 --- a/apps/app/components/project/index.ts +++ b/apps/app/components/project/index.ts @@ -1,6 +1,5 @@ export * from "./create-project-modal"; export * from "./delete-project-modal"; -export * from "./join-project"; export * from "./sidebar-list"; export * from "./single-integration-card"; export * from "./single-project-card"; diff --git a/apps/app/components/project/join-project.tsx b/apps/app/components/project/join-project.tsx deleted file mode 100644 index 6127dd78f..000000000 --- a/apps/app/components/project/join-project.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { FC } from "react"; -// next -import Image from "next/image"; - -// ui -import { PrimaryButton } from "components/ui"; -// icon -import { AssignmentClipboardIcon } from "components/icons"; -// img -import JoinProjectImg from "public/join-project.svg"; - -export interface JoinProjectProps { - isJoiningProject: boolean; - handleJoin: () => void; -} - -export const JoinProject: FC = ({ isJoiningProject, handleJoin }) => ( -
-
- JoinProject -
-

You are not a member of this project

- -
-

- You are not a member of this project, but you can join this project by clicking the button - below. -

-
-
- - - {isJoiningProject ? "Joining..." : "Click to join"} - -
-
-); diff --git a/apps/app/contexts/project-member.context.tsx b/apps/app/contexts/project-member.context.tsx new file mode 100644 index 000000000..c7e758a10 --- /dev/null +++ b/apps/app/contexts/project-member.context.tsx @@ -0,0 +1,73 @@ +import { createContext, useContext } from "react"; + +// next +import { useRouter } from "next/router"; + +// swr +import useSWR from "swr"; + +// services +import projectService from "services/project.service"; + +// keys +import { USER_PROJECT_VIEW } from "constants/fetch-keys"; + +// types +import { IProjectMember } from "types"; + +type ContextType = { + loading: boolean; + memberDetails?: IProjectMember; + error: any; +}; + +export const ProjectMemberContext = createContext({} as ContextType); + +type Props = { + children: React.ReactNode; +}; + +export const ProjectMemberProvider: React.FC = (props) => { + const { children } = props; + + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const { data: memberDetails, error } = useSWR( + workspaceSlug && projectId ? USER_PROJECT_VIEW(workspaceSlug.toString()) : null, + workspaceSlug && projectId + ? () => projectService.projectMemberMe(workspaceSlug.toString(), projectId.toString()) + : null, + { + onErrorRetry(err, _, __, ___, revalidateOpts) { + if (err.status === 401 || err.status === 403) return; + revalidateOpts.retryCount = 5; + }, + } + ); + + const loading = !memberDetails && !error; + + return ( + + {children} + + ); +}; + +export const useProjectMyMembership = () => { + const context = useContext(ProjectMemberContext); + + if (context === undefined) + throw new Error(`useProjectMember must be used within a ProjectMemberProvider.`); + + return { + ...context, + memberRole: { + isOwner: context.memberDetails?.role === 20, + isMember: context.memberDetails?.role === 15, + isViewer: context.memberDetails?.role === 10, + isGuest: context.memberDetails?.role === 5, + }, + }; +}; diff --git a/apps/app/layouts/app-layout/index.tsx b/apps/app/layouts/app-layout/index.tsx index 5de05c78f..9bf11fe9d 100644 --- a/apps/app/layouts/app-layout/index.tsx +++ b/apps/app/layouts/app-layout/index.tsx @@ -12,9 +12,8 @@ import { PrimaryButton, Spinner } from "components/ui"; // icon import { LayerDiagonalIcon } from "components/icons"; // components -import { NotAuthorizedView } from "components/core"; +import { NotAuthorizedView, JoinProject } from "components/auth-screens"; import { CommandPalette } from "components/command-palette"; -import { JoinProject } from "components/project"; // local components import Container from "layouts/container"; import AppSidebar from "layouts/app-layout/app-sidebar"; @@ -61,7 +60,6 @@ const AppLayout: FC = ({ }) => { // states const [toggleSidebar, setToggleSidebar] = useState(false); - const [isJoiningProject, setIsJoiningProject] = useState(false); const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -83,21 +81,6 @@ const AppLayout: FC = ({ memberType?.isViewer || memberType?.isGuest; - const handleJoin = () => { - setIsJoiningProject(true); - projectService - .joinProject(workspaceSlug as string, { - project_ids: [projectId as string], - }) - .then(() => { - setIsJoiningProject(false); - projectMembersMutate(); - }) - .catch((err) => { - console.error(err); - }); - }; - return ( @@ -123,6 +106,7 @@ const AppLayout: FC = ({ ) ) } + type="project" /> ) : (
@@ -170,7 +154,7 @@ const AppLayout: FC = ({ {children} ) : ( - + )}
)} diff --git a/apps/app/layouts/auth-layout/index.ts b/apps/app/layouts/auth-layout/index.ts new file mode 100644 index 000000000..6790a6b16 --- /dev/null +++ b/apps/app/layouts/auth-layout/index.ts @@ -0,0 +1,2 @@ +export * from "./project-authorization-wrapper"; +export * from "./workspace-authorization-wrapper"; diff --git a/apps/app/layouts/auth-layout/project-authorization-wrapper.tsx b/apps/app/layouts/auth-layout/project-authorization-wrapper.tsx new file mode 100644 index 000000000..31ccb0408 --- /dev/null +++ b/apps/app/layouts/auth-layout/project-authorization-wrapper.tsx @@ -0,0 +1,141 @@ +import { useState } from "react"; + +import Link from "next/link"; +import { useRouter } from "next/router"; + +// contexts +import { useProjectMyMembership, ProjectMemberProvider } from "contexts/project-member.context"; +// hooks +import useUser from "hooks/use-user"; +// layouts +import Container from "layouts/container"; +import AppHeader from "layouts/app-layout/app-header"; +import AppSidebar from "layouts/app-layout/app-sidebar"; +import SettingsNavbar from "layouts/settings-navbar"; +// components +import { NotAuthorizedView, JoinProject } from "components/auth-screens"; +import { CommandPalette } from "components/command-palette"; +// ui +import { PrimaryButton } from "components/ui"; +// icons +import { LayerDiagonalIcon } from "components/icons"; + +type Meta = { + title?: string | null; + description?: string | null; + image?: string | null; + url?: string | null; +}; + +type Props = { + meta?: Meta; + children: React.ReactNode; + noPadding?: boolean; + noHeader?: boolean; + bg?: "primary" | "secondary"; + breadcrumbs?: JSX.Element; + left?: JSX.Element; + right?: JSX.Element; +}; + +export const ProjectAuthorizationWrapper: React.FC = (props) => ( + + + +); + +const ProjectAuthorizationWrapped: React.FC = ({ + meta, + children, + noPadding = false, + noHeader = false, + bg = "primary", + breadcrumbs, + left, + right, +}) => { + const [toggleSidebar, setToggleSidebar] = useState(false); + + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const user = useUser(); + + const { loading, error, memberRole: memberType } = useProjectMyMembership(); + + const settingsLayout = router.pathname.includes("/settings"); + + return ( + + +
+ + {loading ? ( +
+

Loading...

+
+ ) : error?.status === 401 || error?.status === 403 ? ( + + ) : error?.status === 404 ? ( +
+
+

No such project exist. Create one?

+ { + const e = new KeyboardEvent("keydown", { key: "p" }); + document.dispatchEvent(e); + }} + > + Create project + +
+
+ ) : settingsLayout && (memberType?.isGuest || memberType?.isViewer) ? ( + + + + Go to issues + + + + } + type="project" + /> + ) : ( +
+ {!noHeader && ( + + )} +
+ {settingsLayout && ( +
+
+

Project Settings

+

+ This information will be displayed to every member of the project. +

+
+ +
+ )} + {children} +
+
+ )} +
+
+ ); +}; diff --git a/apps/app/layouts/auth-layout/workspace-authorization-wrapper.tsx b/apps/app/layouts/auth-layout/workspace-authorization-wrapper.tsx new file mode 100644 index 000000000..3a88733a6 --- /dev/null +++ b/apps/app/layouts/auth-layout/workspace-authorization-wrapper.tsx @@ -0,0 +1,158 @@ +import { useState } from "react"; + +import Link from "next/link"; +import { useRouter } from "next/router"; + +import useSWR from "swr"; + +// services +import workspaceServices from "services/workspace.service"; +// hooks +import useUser from "hooks/use-user"; +// layouts +import Container from "layouts/container"; +import AppSidebar from "layouts/app-layout/app-sidebar"; +import AppHeader from "layouts/app-layout/app-header"; +import SettingsNavbar from "layouts/settings-navbar"; +// components +import { NotAuthorizedView, NotAWorkspaceMember } from "components/auth-screens"; +import { CommandPalette } from "components/command-palette"; +// icons +import { PrimaryButton } from "components/ui"; +import { LayerDiagonalIcon } from "components/icons"; +// fetch-keys +import { WORKSPACE_MEMBERS_ME } from "constants/fetch-keys"; + +type Meta = { + title?: string | null; + description?: string | null; + image?: string | null; + url?: string | null; +}; + +type Props = { + meta?: Meta; + children: React.ReactNode; + noPadding?: boolean; + noHeader?: boolean; + bg?: "primary" | "secondary"; + breadcrumbs?: JSX.Element; + left?: JSX.Element; + right?: JSX.Element; + profilePage?: boolean; +}; + +export const WorkspaceAuthorizationLayout: React.FC = ({ + meta, + children, + noPadding = false, + noHeader = false, + bg = "primary", + breadcrumbs, + left, + right, + profilePage = false, +}) => { + const [toggleSidebar, setToggleSidebar] = useState(false); + + const router = useRouter(); + const { workspaceSlug } = router.query; + + const user = useUser(); + + const { data: workspaceMemberMe, error } = useSWR( + workspaceSlug ? WORKSPACE_MEMBERS_ME(workspaceSlug as string) : null, + workspaceSlug ? () => workspaceServices.workspaceMemberMe(workspaceSlug.toString()) : null, + { + onErrorRetry(err, key, config, revalidate, revalidateOpts) { + if (err.status === 401 || err.status === 403) return; + revalidateOpts.retryCount = 5; + }, + } + ); + + if (!workspaceMemberMe && !error) + // TODO: show good loading UI + return ( +
+

Loading...

+
+ ); + + if (error?.status === 401 || error?.status === 403) return ; + + // FIXME: show 404 for workspace not workspace member + if (error?.status === 404) { + return ( +
+

No such workspace exist. Create one?

+
+ ); + } + + const settingsLayout = router.pathname.includes("/settings"); + const memberType = { + isOwner: workspaceMemberMe?.role === 20, + isMember: workspaceMemberMe?.role === 15, + isViewer: workspaceMemberMe?.role === 10, + isGuest: workspaceMemberMe?.role === 5, + }; + + return ( + + +
+ + {settingsLayout && (memberType?.isGuest || memberType?.isViewer) ? ( + + + + Go to workspace + + + + } + type="workspace" + /> + ) : ( +
+ {!noHeader && ( + + )} +
+ {(settingsLayout || profilePage) && ( +
+
+

+ {profilePage ? "Profile" : "Workspace"} Settings +

+

+ {profilePage + ? "This information will be visible to only you." + : "This information will be displayed to every member of the workspace."} +

+
+ +
+ )} + {children} +
+
+ )} +
+
+ ); +}; diff --git a/apps/app/layouts/settings-navbar.tsx b/apps/app/layouts/settings-navbar.tsx index f7b7fbccc..169690aff 100644 --- a/apps/app/layouts/settings-navbar.tsx +++ b/apps/app/layouts/settings-navbar.tsx @@ -2,7 +2,7 @@ import Link from "next/link"; import { useRouter } from "next/router"; type Props = { - profilePage: boolean; + profilePage?: boolean; }; const SettingsNavbar: React.FC = ({ profilePage = false }) => { diff --git a/apps/app/pages/[workspaceSlug]/index.tsx b/apps/app/pages/[workspaceSlug]/index.tsx index e92ca7a61..cb7cb8405 100644 --- a/apps/app/pages/[workspaceSlug]/index.tsx +++ b/apps/app/pages/[workspaceSlug]/index.tsx @@ -4,10 +4,8 @@ import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; -// lib -import { requiredAuth } from "lib/auth"; // layouts -import AppLayout from "layouts/app-layout"; +import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // services import userService from "services/user.service"; // components @@ -18,7 +16,7 @@ import { IssuesStats, } from "components/workspace"; // types -import type { NextPage, GetServerSidePropsContext } from "next"; +import type { NextPage } from "next"; // fetch-keys import { USER_WORKSPACE_DASHBOARD } from "constants/fetch-keys"; @@ -38,14 +36,16 @@ const WorkspacePage: NextPage = () => { }, [month, workspaceSlug]); return ( - +
-

Plane is a open source application, to support us you can star us on GitHub!

+

+ Plane is a open source application, to support us you can star us on GitHub! +

- + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - return { - props: { - user, - }, - }; -}; - export default WorkspacePage; diff --git a/apps/app/pages/[workspaceSlug]/me/my-issues.tsx b/apps/app/pages/[workspaceSlug]/me/my-issues.tsx index 0c961f778..fb0b7266a 100644 --- a/apps/app/pages/[workspaceSlug]/me/my-issues.tsx +++ b/apps/app/pages/[workspaceSlug]/me/my-issues.tsx @@ -1,4 +1,5 @@ import React from "react"; + import { useRouter } from "next/router"; // headless ui @@ -6,7 +7,7 @@ import { Disclosure, Popover, Transition } from "@headlessui/react"; // icons import { ChevronDownIcon, PlusIcon, RectangleStackIcon } from "@heroicons/react/24/outline"; // layouts -import AppLayout from "layouts/app-layout"; +import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // hooks import useIssues from "hooks/use-issues"; // ui @@ -36,166 +37,164 @@ const MyIssuesPage: NextPage = () => { ); return ( - <> - - - - } - right={ -
- {myIssues && myIssues.length > 0 && ( - - {({ open }) => ( - <> - - View - + + + + } + right={ +
+ {myIssues && myIssues.length > 0 && ( + + {({ open }) => ( + <> + + View + - - -
-
-

Properties

-
- {Object.keys(properties).map((key) => ( - - ))} -
+ + +
+
+

Properties

+
+ {Object.keys(properties).map((key) => ( + + ))}
- - - - )} - - )} - { - const e = new KeyboardEvent("keydown", { key: "c" }); - document.dispatchEvent(e); - }} - > - - Add Issue - -
- } - > -
- {myIssues ? ( - <> - {myIssues.length > 0 ? ( -
- - {({ open }) => ( -
-
- -
- - - -

My Issues

- - {myIssues.length} - -
-
-
- - - {myIssues.map((issue: IIssue) => ( - - ))} - -
- )} -
-
- ) : ( -
- - - Use
C
shortcut - to create a new issue - - } - Icon={PlusIcon} - action={() => { - const e = new KeyboardEvent("keydown", { - key: "c", - }); - document.dispatchEvent(e); - }} - /> -
-
+ + + )} - - ) : ( -
- -
+ )} + { + const e = new KeyboardEvent("keydown", { key: "c" }); + document.dispatchEvent(e); + }} + > + + Add Issue +
- - + } + > +
+ {myIssues ? ( + <> + {myIssues.length > 0 ? ( +
+ + {({ open }) => ( +
+
+ +
+ + + +

My Issues

+ + {myIssues.length} + +
+
+
+ + + {myIssues.map((issue: IIssue) => ( + + ))} + + +
+ )} +
+
+ ) : ( +
+ + + Use
C
shortcut + to create a new issue + + } + Icon={PlusIcon} + action={() => { + const e = new KeyboardEvent("keydown", { + key: "c", + }); + document.dispatchEvent(e); + }} + /> +
+
+ )} + + ) : ( +
+ +
+ )} +
+ ); }; diff --git a/apps/app/pages/[workspaceSlug]/me/profile/activity.tsx b/apps/app/pages/[workspaceSlug]/me/profile/activity.tsx index cfd74d16a..fc0c70d51 100644 --- a/apps/app/pages/[workspaceSlug]/me/profile/activity.tsx +++ b/apps/app/pages/[workspaceSlug]/me/profile/activity.tsx @@ -1,17 +1,14 @@ -import { GetServerSidePropsContext } from "next"; - import useSWR from "swr"; // services import userService from "services/user.service"; -// lib -import { requiredAuth } from "lib/auth"; // layouts -import AppLayout from "layouts/app-layout"; +import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; +// components +import { Feeds } from "components/core"; // ui import { Loader } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; -import { Feeds } from "components/core"; // fetch-keys import { USER_ACTIVITY } from "constants/fetch-keys"; @@ -19,7 +16,7 @@ const ProfileActivity = () => { const { data: userActivity } = useSWR(USER_ACTIVITY, () => userService.getUserActivity()); return ( - { } - settingsLayout profilePage > {userActivity ? ( @@ -43,29 +39,8 @@ const ProfileActivity = () => { )} - + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - return { - props: { - user, - }, - }; -}; - export default ProfileActivity; diff --git a/apps/app/pages/[workspaceSlug]/me/profile/index.tsx b/apps/app/pages/[workspaceSlug]/me/profile/index.tsx index 25e8f23ba..4f36c5c3e 100644 --- a/apps/app/pages/[workspaceSlug]/me/profile/index.tsx +++ b/apps/app/pages/[workspaceSlug]/me/profile/index.tsx @@ -4,8 +4,6 @@ import Image from "next/image"; // react-hook-form import { Controller, useForm } from "react-hook-form"; -// lib -import { requiredAuth } from "lib/auth"; // services import fileService from "services/file.service"; import userService from "services/user.service"; @@ -13,7 +11,7 @@ import userService from "services/user.service"; import useUser from "hooks/use-user"; import useToast from "hooks/use-toast"; // layouts -import AppLayout from "layouts/app-layout"; +import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // components import { ImageUploadModal } from "components/core"; // ui @@ -22,7 +20,7 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons import { UserIcon } from "@heroicons/react/24/outline"; // types -import type { NextPage, GetServerSidePropsContext } from "next"; +import type { NextPage } from "next"; import type { IUser } from "types"; // constants import { USER_ROLES } from "constants/workspace"; @@ -123,7 +121,7 @@ const Profile: NextPage = () => { }; return ( - { } - settingsLayout profilePage > {
)} - + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - return { - props: { - user, - }, - }; -}; - export default Profile; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx index de5c5cfaa..b96dc7945 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx @@ -3,14 +3,11 @@ import React, { useState } from "react"; import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; -import { GetServerSidePropsContext } from "next"; // icons import { ArrowLeftIcon } from "@heroicons/react/24/outline"; import { CyclesIcon } from "components/icons"; -// lib -import { requiredAdmin, requiredAuth } from "lib/auth"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // contexts import { IssueViewContextProvider } from "contexts/issue-view.context"; // components @@ -28,8 +25,6 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // helpers import { truncateText } from "helpers/string.helper"; import { getDateRangeStatus } from "helpers/date-time.helper"; -// types -import { UserAuth } from "types"; // fetch-keys import { CYCLE_ISSUES, @@ -39,7 +34,7 @@ import { PROJECT_ISSUES_LIST, } from "constants/fetch-keys"; -const SingleCycle: React.FC = (props) => { +const SingleCycle: React.FC = () => { const [cycleIssuesListModal, setCycleIssuesListModal] = useState(false); const [cycleSidebar, setCycleSidebar] = useState(true); @@ -117,8 +112,7 @@ const SingleCycle: React.FC = (props) => { issues={issues?.filter((i) => !i.cycle_id) ?? []} handleOnSubmit={handleAddIssuesToCycle} /> - = (props) => {
@@ -180,38 +173,9 @@ const SingleCycle: React.FC = (props) => { isOpen={cycleSidebar} isCompleted={cycleStatus === "completed" ?? false} /> - + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default SingleCycle; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx index 0f6dbbf21..bfc8ef002 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx @@ -5,27 +5,24 @@ import dynamic from "next/dynamic"; import useSWR from "swr"; -import { PlusIcon } from "@heroicons/react/24/outline"; +// headless ui import { Tab } from "@headlessui/react"; -// lib -import { requiredAdmin, requiredAuth } from "lib/auth"; - // services import cycleService from "services/cycles.service"; import projectService from "services/project.service"; - // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // components import { CompletedCyclesListProps, CreateUpdateCycleModal, CyclesList } from "components/cycles"; // ui import { Loader, PrimaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons +import { PlusIcon } from "@heroicons/react/24/outline"; // types -import { SelectCycleType, UserAuth } from "types"; -import type { NextPage, GetServerSidePropsContext } from "next"; -// fetching keys +import { SelectCycleType } from "types"; +import type { NextPage } from "next"; +// fetch-keys import { CYCLE_CURRENT_AND_UPCOMING_LIST, CYCLE_DRAFT_LIST, @@ -44,13 +41,12 @@ const CompletedCyclesList = dynamic( } ); -const ProjectCycles: NextPage = (props) => { +const ProjectCycles: NextPage = () => { const [selectedCycle, setSelectedCycle] = useState(); const [createUpdateCycleModal, setCreateUpdateCycleModal] = useState(false); - const { - query: { workspaceSlug, projectId }, - } = useRouter(); + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; const { data: activeProject } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, @@ -82,11 +78,10 @@ const ProjectCycles: NextPage = (props) => { }, [createUpdateCycleModal]); return ( - @@ -195,37 +190,8 @@ const ProjectCycles: NextPage = (props) => {
- + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default ProjectCycles; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx index cf582439a..281057f81 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/[issueId].tsx @@ -9,10 +9,8 @@ import useSWR, { mutate } from "swr"; import { useForm } from "react-hook-form"; // services import issuesService from "services/issues.service"; -// lib -import { requiredAdmin, requiredAuth } from "lib/auth"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // components import { IssueDescriptionForm, @@ -27,8 +25,8 @@ import { import { Loader, CustomMenu } from "components/ui"; import { Breadcrumbs } from "components/breadcrumbs"; // types -import { IIssue, UserAuth } from "types"; -import type { GetServerSidePropsContext, NextPage } from "next"; +import { IIssue } from "types"; +import type { NextPage } from "next"; // fetch-keys import { PROJECT_ISSUES_ACTIVITY, ISSUE_DETAILS, SUB_ISSUES } from "constants/fetch-keys"; @@ -47,7 +45,7 @@ const defaultValues = { labels_list: [], }; -const IssueDetailsPage: NextPage = (props) => { +const IssueDetailsPage: NextPage = () => { const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; @@ -122,8 +120,7 @@ const IssueDetailsPage: NextPage = (props) => { }, [issueDetails, reset, issueId]); return ( - = (props) => {
) : null} - +
- +

Attachments

- - + +
@@ -219,7 +212,6 @@ const IssueDetailsPage: NextPage = (props) => { issueDetail={issueDetails} submitChanges={submitChanges} watch={watch} - userAuth={props} />
@@ -239,37 +231,8 @@ const IssueDetailsPage: NextPage = (props) => { )} -
+ ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default IssueDetailsPage; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/index.tsx index 951ffce4c..8533f2c5c 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/issues/index.tsx @@ -2,12 +2,10 @@ import { useRouter } from "next/router"; import useSWR from "swr"; -// lib -import { requiredAdmin, requiredAuth } from "lib/auth"; // services import projectService from "services/project.service"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // contexts import { IssueViewContextProvider } from "contexts/issue-view.context"; // components @@ -18,12 +16,11 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons import { PlusIcon } from "@heroicons/react/24/outline"; // types -import type { UserAuth } from "types"; -import type { GetServerSidePropsContext, NextPage } from "next"; +import type { NextPage } from "next"; // fetch-keys import { PROJECT_DETAILS } from "constants/fetch-keys"; -const ProjectIssues: NextPage = (props) => { +const ProjectIssues: NextPage = () => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -36,8 +33,7 @@ const ProjectIssues: NextPage = (props) => { return ( - @@ -60,39 +56,10 @@ const ProjectIssues: NextPage = (props) => { } > - - + + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default ProjectIssues; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx index 061214c09..172b049b3 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/[moduleId].tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import { useRouter } from "next/router"; -import { GetServerSidePropsContext } from "next"; + import useSWR, { mutate } from "swr"; // icons @@ -12,15 +12,13 @@ import { RectangleGroupIcon, RectangleStackIcon, } from "@heroicons/react/24/outline"; -// lib -import { requiredAdmin, requiredAuth } from "lib/auth"; // services import modulesService from "services/modules.service"; import issuesService from "services/issues.service"; // hooks import useToast from "hooks/use-toast"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // contexts import { IssueViewContextProvider } from "contexts/issue-view.context"; // components @@ -32,7 +30,7 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // helpers import { truncateText } from "helpers/string.helper"; // types -import { IModule, UserAuth } from "types"; +import { IModule } from "types"; // fetch-keys import { @@ -42,7 +40,7 @@ import { PROJECT_ISSUES_LIST, } from "constants/fetch-keys"; -const SingleModule: React.FC = (props) => { +const SingleModule: React.FC = () => { const [moduleIssuesListModal, setModuleIssuesListModal] = useState(false); const [moduleSidebar, setModuleSidebar] = useState(true); @@ -121,8 +119,7 @@ const SingleModule: React.FC = (props) => { issues={issues?.filter((i) => !i.module_id) ?? []} handleOnSubmit={handleAddIssuesToModule} /> - = (props) => { {moduleIssues ? ( moduleIssues.length > 0 ? (
- +
) : (
= (props) => { module={moduleDetails} isOpen={moduleSidebar} moduleIssues={moduleIssues} - userAuth={props} /> - + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default SingleModule; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx index 1806c68dd..087230226 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/modules/index.tsx @@ -1,15 +1,11 @@ import React, { useEffect, useState } from "react"; import { useRouter } from "next/router"; + import useSWR from "swr"; -import { PlusIcon } from "@heroicons/react/24/outline"; -// image -import emptyModule from "public/empty-state/empty-module.svg"; // layouts -import AppLayout from "layouts/app-layout"; -// lib -import { requiredAdmin, requiredAuth } from "lib/auth"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // services import projectService from "services/project.service"; import modulesService from "services/modules.service"; @@ -19,19 +15,22 @@ import { CreateUpdateModuleModal, SingleModuleCard } from "components/modules"; import { EmptyState, Loader, PrimaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons +import { PlusIcon } from "@heroicons/react/24/outline"; +// images +import emptyModule from "public/empty-state/empty-module.svg"; // types import { IModule, SelectModuleType } from "types/modules"; -import { UserAuth } from "types"; -import type { NextPage, GetServerSidePropsContext } from "next"; +import type { NextPage } from "next"; // fetch-keys import { MODULE_LIST, PROJECT_DETAILS } from "constants/fetch-keys"; -const ProjectModules: NextPage = (props) => { - const router = useRouter(); - const { workspaceSlug, projectId } = router.query; +const ProjectModules: NextPage = () => { const [selectedModule, setSelectedModule] = useState(); const [createUpdateModule, setCreateUpdateModule] = useState(false); + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + const { data: activeProject } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, workspaceSlug && projectId @@ -60,11 +59,10 @@ const ProjectModules: NextPage = (props) => { }, [createUpdateModule]); return ( - @@ -124,37 +122,8 @@ const ProjectModules: NextPage = (props) => { )} - + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default ProjectModules; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx index c840b40d1..6cecbba77 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx @@ -13,8 +13,6 @@ import { TwitterPicker } from "react-color"; // react-beautiful-dnd import { DragDropContext, DropResult } from "react-beautiful-dnd"; import StrictModeDroppable from "components/dnd/StrictModeDroppable"; -// lib -import { requiredAdmin, requiredAuth } from "lib/auth"; // services import projectService from "services/project.service"; import pagesService from "services/pages.service"; @@ -22,7 +20,7 @@ import issuesService from "services/issues.service"; // hooks import useToast from "hooks/use-toast"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // components import { CreateUpdateBlockInline, SinglePageBlock } from "components/pages"; // ui @@ -43,8 +41,8 @@ import { renderShortTime } from "helpers/date-time.helper"; import { copyTextToClipboard } from "helpers/string.helper"; import { orderArrayBy } from "helpers/array.helper"; // types -import type { NextPage, GetServerSidePropsContext } from "next"; -import { IIssueLabels, IPage, IPageBlock, UserAuth } from "types"; +import type { NextPage } from "next"; +import { IIssueLabels, IPage, IPageBlock } from "types"; // fetch-keys import { PAGE_BLOCKS_LIST, @@ -53,7 +51,7 @@ import { PROJECT_ISSUE_LABELS, } from "constants/fetch-keys"; -const SinglePage: NextPage = (props) => { +const SinglePage: NextPage = () => { const [createBlockForm, setCreateBlockForm] = useState(false); const scrollToRef = useRef(null); @@ -272,11 +270,10 @@ const SinglePage: NextPage = (props) => { }, [reset, pageDetails]); return ( - @@ -506,37 +503,8 @@ const SinglePage: NextPage = (props) => { )} - + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default SinglePage; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx index b70ad37a3..8ffeabec5 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx @@ -1,15 +1,12 @@ import { useState } from "react"; import { useRouter } from "next/router"; -import type { GetServerSidePropsContext, NextPage } from "next"; import dynamic from "next/dynamic"; import useSWR, { mutate } from "swr"; // react-hook-form import { useForm } from "react-hook-form"; -// lib -import { requiredAdmin, requiredAuth } from "lib/auth"; // headless ui import { Tab } from "@headlessui/react"; // services @@ -20,16 +17,17 @@ import useToast from "hooks/use-toast"; // icons import { PlusIcon } from "components/icons"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // components import { RecentPagesList, CreateUpdatePageModal, TPagesListProps } from "components/pages"; // ui import { Input, PrimaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons -import { ListBulletIcon, RectangleGroupIcon, Squares2X2Icon } from "@heroicons/react/20/solid"; +import { ListBulletIcon, Squares2X2Icon } from "@heroicons/react/20/solid"; // types -import { IPage, TPageViewProps, UserAuth } from "types"; +import { IPage, TPageViewProps } from "types"; +import type { NextPage } from "next"; // fetch-keys import { ALL_PAGES_LIST, @@ -66,7 +64,7 @@ const OtherPagesList = dynamic( } ); -const ProjectPages: NextPage = (props) => { +const ProjectPages: NextPage = () => { const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false); const [viewType, setViewType] = useState("list"); @@ -153,11 +151,10 @@ const ProjectPages: NextPage = (props) => { isOpen={createUpdatePageModal} handleClose={() => setCreateUpdatePageModal(false)} /> - @@ -266,38 +263,9 @@ const ProjectPages: NextPage = (props) => {
-
+ ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default ProjectPages; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/control.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/control.tsx index 7491e09f0..2548e4bac 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/control.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/control.tsx @@ -6,10 +6,8 @@ import Image from "next/image"; import useSWR, { mutate } from "swr"; import { Controller, useForm } from "react-hook-form"; -// lib -import { requiredAdmin } from "lib/auth"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // services import projectService from "services/project.service"; // hooks @@ -19,30 +17,20 @@ import { CustomSelect, Loader, SecondaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // types import { IProject, IWorkspace } from "types"; -import type { NextPage, GetServerSidePropsContext } from "next"; +import type { NextPage } from "next"; // fetch-keys import { PROJECTS_LIST, PROJECT_DETAILS, PROJECT_MEMBERS } from "constants/fetch-keys"; -type TControlSettingsProps = { - isMember: boolean; - isOwner: boolean; - isViewer: boolean; - isGuest: boolean; -}; - const defaultValues: Partial = { project_lead: null, default_assignee: null, }; -const ControlSettings: NextPage = (props) => { - const { isMember, isOwner, isViewer, isGuest } = props; - +const ControlSettings: NextPage = () => { const { setToastAlert } = useToast(); - const { - query: { workspaceSlug, projectId }, - } = useRouter(); + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; const { data: projectDetails } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, @@ -102,9 +90,9 @@ const ControlSettings: NextPage = (props) => { console.log(err); }); }; + return ( - = (props) => { } - settingsLayout >
@@ -245,24 +232,8 @@ const ControlSettings: NextPage = (props) => {
-
+ ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default ControlSettings; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx index a249c5acc..7d1bd500d 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx @@ -8,29 +8,25 @@ import useSWR, { mutate } from "swr"; import estimatesService from "services/estimates.service"; import projectService from "services/project.service"; -// lib -import { requiredAdmin } from "lib/auth"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // components import { CreateUpdateEstimateModal, SingleEstimate } from "components/estimates"; //hooks import useToast from "hooks/use-toast"; // ui -import { Loader, PrimaryButton } from "components/ui"; +import { Loader } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons import { PlusIcon } from "@heroicons/react/24/outline"; // types -import { IEstimate, UserAuth, IProject } from "types"; -import type { GetServerSidePropsContext, NextPage } from "next"; +import { IEstimate, IProject } from "types"; +import type { NextPage } from "next"; // fetch-keys import { ESTIMATES_LIST, PROJECT_DETAILS } from "constants/fetch-keys"; -const EstimatesSettings: NextPage = (props) => { - const { isMember, isOwner, isViewer, isGuest } = props; - +const EstimatesSettings: NextPage = () => { const [estimateFormOpen, setEstimateFormOpen] = useState(false); const [isUpdating, setIsUpdating] = useState(false); @@ -87,8 +83,7 @@ const EstimatesSettings: NextPage = (props) => { return ( <> - = (props) => { } - settingsLayout > = (props) => { )} - + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default EstimatesSettings; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx index f9c5c6971..17588784c 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx @@ -7,10 +7,8 @@ import useSWR, { mutate } from "swr"; // services import projectService from "services/project.service"; import trackEventServices from "services/track-event.service"; -// lib -import { requiredAdmin } from "lib/auth"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // hooks import useToast from "hooks/use-toast"; // ui @@ -20,12 +18,12 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; import { ContrastIcon, PeopleGroupIcon, ViewListIcon } from "components/icons"; import { DocumentTextIcon } from "@heroicons/react/24/outline"; // types -import { IProject, UserAuth } from "types"; -import type { NextPage, GetServerSidePropsContext } from "next"; +import { IProject } from "types"; +import type { NextPage } from "next"; // fetch-keys import { PROJECTS_LIST, PROJECT_DETAILS } from "constants/fetch-keys"; -const FeaturesSettings: NextPage = (props) => { +const FeaturesSettings: NextPage = () => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -79,8 +77,7 @@ const FeaturesSettings: NextPage = (props) => { }; return ( - = (props) => { } - settingsLayout >

Features

@@ -269,24 +265,8 @@ const FeaturesSettings: NextPage = (props) => {
- + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default FeaturesSettings; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx index b353d1914..2db852714 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/index.tsx @@ -7,11 +7,8 @@ import useSWR, { mutate } from "swr"; // react-hook-form import { Controller, useForm } from "react-hook-form"; -import { IProject, IWorkspace, UserAuth } from "types"; -// lib -import { requiredAdmin } from "lib/auth"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // services import projectService from "services/project.service"; // components @@ -31,7 +28,8 @@ import { } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // types -import type { NextPage, GetServerSidePropsContext } from "next"; +import { IProject, IWorkspace } from "types"; +import type { NextPage } from "next"; // fetch-keys import { PROJECTS_LIST, PROJECT_DETAILS } from "constants/fetch-keys"; // constants @@ -44,10 +42,8 @@ const defaultValues: Partial = { network: 0, }; -const GeneralSettings: NextPage = ({ isMember, isOwner, isViewer, isGuest }) => { +const GeneralSettings: NextPage = () => { const [selectProject, setSelectedProject] = useState(null); - const [isImageUploading, setIsImageUploading] = useState(false); - const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false); const { setToastAlert } = useToast(); @@ -136,8 +132,7 @@ const GeneralSettings: NextPage = ({ isMember, isOwner, isViewer, isGu }; return ( - = ({ isMember, isOwner, isViewer, isGu } - settingsLayout > = ({ isMember, isOwner, isViewer, isGu - + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default GeneralSettings; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx index e955dbc7b..101044f5c 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx @@ -4,10 +4,8 @@ import { useRouter } from "next/router"; import useSWR from "swr"; -// lib -import { requiredAdmin } from "lib/auth"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // services import IntegrationService from "services/integration"; import projectService from "services/project.service"; @@ -19,14 +17,12 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons import { PlusIcon, PuzzlePieceIcon } from "@heroicons/react/24/outline"; // types -import { IProject, UserAuth } from "types"; -import type { NextPageContext, NextPage } from "next"; +import { IProject } from "types"; +import type { NextPage } from "next"; // fetch-keys import { PROJECT_DETAILS, WORKSPACE_INTEGRATIONS } from "constants/fetch-keys"; -const ProjectIntegrations: NextPage = (props) => { - const { isMember, isOwner, isViewer, isGuest } = props; - +const ProjectIntegrations: NextPage = () => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -46,8 +42,7 @@ const ProjectIntegrations: NextPage = (props) => { ); return ( - = (props) => { } - settingsLayout > {workspaceIntegrations ? ( workspaceIntegrations.length > 0 ? ( @@ -97,24 +91,8 @@ const ProjectIntegrations: NextPage = (props) => { )} - + ); }; -export const getServerSideProps = async (ctx: NextPageContext) => { - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default ProjectIntegrations; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx index 013f74a38..d1f2e37e6 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx @@ -10,7 +10,7 @@ import issuesService from "services/issues.service"; // lib import { requiredAdmin } from "lib/auth"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // components import { CreateUpdateLabelInline, @@ -29,9 +29,7 @@ import type { GetServerSidePropsContext, NextPage } from "next"; // fetch-keys import { PROJECT_DETAILS, PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; -const LabelsSettings: NextPage = (props) => { - const { isMember, isOwner, isViewer, isGuest } = props; - +const LabelsSettings: NextPage = () => { // create/edit label form const [labelForm, setLabelForm] = useState(false); @@ -99,8 +97,7 @@ const LabelsSettings: NextPage = (props) => { handleClose={() => setLabelsListModal(false)} parent={parentLabel} /> - = (props) => { } - settingsLayout >
@@ -182,25 +178,9 @@ const LabelsSettings: NextPage = (props) => {
-
+ ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default LabelsSettings; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx index c090b9b6c..8ead3550c 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/members.tsx @@ -8,12 +8,10 @@ import useSWR from "swr"; // services import projectService from "services/project.service"; import workspaceService from "services/workspace.service"; -// lib -import { requiredAdmin } from "lib/auth"; // hooks import useToast from "hooks/use-toast"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // components import ConfirmProjectMemberRemove from "components/project/confirm-project-member-remove"; import SendProjectInvitationModal from "components/project/send-project-invitation-modal"; @@ -23,8 +21,7 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons import { PlusIcon, XMarkIcon } from "@heroicons/react/24/outline"; // types -import type { NextPage, GetServerSidePropsContext } from "next"; -import { UserAuth } from "types"; +import type { NextPage } from "next"; // fetch-keys import { PROJECT_DETAILS, @@ -35,7 +32,7 @@ import { // constants import { ROLE } from "constants/workspace"; -const MembersSettings: NextPage = ({ isMember, isOwner, isViewer, isGuest }) => { +const MembersSettings: NextPage = () => { const [inviteModal, setInviteModal] = useState(false); const [selectedRemoveMember, setSelectedRemoveMember] = useState(null); const [selectedInviteRemoveMember, setSelectedInviteRemoveMember] = useState(null); @@ -148,8 +145,7 @@ const MembersSettings: NextPage = ({ isMember, isOwner, isViewer, isGu setIsOpen={setInviteModal} members={members} /> - = ({ isMember, isOwner, isViewer, isGu } - settingsLayout >
@@ -274,25 +269,9 @@ const MembersSettings: NextPage = ({ isMember, isOwner, isViewer, isGu
)}
-
+ ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default MembersSettings; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx index 2f7184313..d4439d05c 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx @@ -4,13 +4,11 @@ import { useRouter } from "next/router"; import useSWR from "swr"; -// lib -import { requiredAdmin } from "lib/auth"; // services import stateService from "services/state.service"; import projectService from "services/project.service"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // components import { CreateUpdateStateInline, @@ -26,14 +24,11 @@ import { PlusIcon } from "@heroicons/react/24/outline"; // helpers import { getStatesList, orderStateGroups } from "helpers/state.helper"; // types -import { UserAuth } from "types"; -import type { NextPage, GetServerSidePropsContext } from "next"; +import type { NextPage } from "next"; // fetch-keys import { PROJECT_DETAILS, STATE_LIST } from "constants/fetch-keys"; -const StatesSettings: NextPage = (props) => { - const { isMember, isOwner, isViewer, isGuest } = props; - +const StatesSettings: NextPage = () => { const [activeGroup, setActiveGroup] = useState(null); const [selectedState, setSelectedState] = useState(null); const [selectDeleteState, setSelectDeleteState] = useState(null); @@ -64,8 +59,7 @@ const StatesSettings: NextPage = (props) => { data={statesList?.find((s) => s.id === selectDeleteState) ?? null} onClose={() => setSelectDeleteState(null)} /> - = (props) => { } - settingsLayout >
@@ -149,25 +142,9 @@ const StatesSettings: NextPage = (props) => { )}
-
+ ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default StatesSettings; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/[viewId].tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/[viewId].tsx index f9302e0fd..bdde38aa3 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/[viewId].tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/[viewId].tsx @@ -1,30 +1,28 @@ import { useRouter } from "next/router"; -import { GetServerSidePropsContext } from "next"; import useSWR from "swr"; -// lib -import { requiredAdmin, requiredAuth } from "lib/auth"; // services import projectService from "services/project.service"; import viewsService from "services/views.service"; // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // contexts import { IssueViewContextProvider } from "contexts/issue-view.context"; +// components +import { IssuesFilterView, IssuesView } from "components/core"; // ui import { CustomMenu, PrimaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; -// types -import { UserAuth } from "types"; +// icons +import { PlusIcon } from "@heroicons/react/24/outline"; +import { StackedLayersIcon } from "components/icons"; +// helpers +import { truncateText } from "helpers/string.helper"; // fetch-keys import { PROJECT_DETAILS, VIEWS_LIST, VIEW_DETAILS } from "constants/fetch-keys"; -import { IssuesFilterView, IssuesView } from "components/core"; -import { PlusIcon } from "@heroicons/react/24/outline"; -import { truncateText } from "helpers/string.helper"; -import { StackedLayersIcon } from "components/icons"; -const SingleView: React.FC = (props) => { +const SingleView: React.FC = () => { const router = useRouter(); const { workspaceSlug, projectId, viewId } = router.query; @@ -56,8 +54,7 @@ const SingleView: React.FC = (props) => { return ( - = (props) => { } > - - + + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default SingleView; diff --git a/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx b/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx index 3c1b0e398..af4d57ff3 100644 --- a/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/[projectId]/views/index.tsx @@ -4,40 +4,32 @@ import { useRouter } from "next/router"; import useSWR from "swr"; -// lib -import { requiredAdmin, requiredAuth } from "lib/auth"; - // services import viewsService from "services/views.service"; import projectService from "services/project.service"; - // layouts -import AppLayout from "layouts/app-layout"; +import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // ui import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; - //icons import { PlusIcon } from "components/icons"; - -// image +// images import emptyView from "public/empty-state/empty-view.svg"; // fetching keys import { PROJECT_DETAILS, VIEWS_LIST } from "constants/fetch-keys"; // components import { PrimaryButton, Loader, EmptyState } from "components/ui"; import { DeleteViewModal, CreateUpdateViewModal, SingleViewItem } from "components/views"; - // types -import { IView, UserAuth } from "types"; -import type { NextPage, GetServerSidePropsContext } from "next"; +import { IView } from "types"; +import type { NextPage } from "next"; -const ProjectViews: NextPage = (props) => { +const ProjectViews: NextPage = () => { const [isCreateViewModalOpen, setIsCreateViewModalOpen] = useState(false); const [selectedView, setSelectedView] = useState(null); - const { - query: { workspaceSlug, projectId }, - } = useRouter(); + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; const { data: activeProject } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, @@ -54,11 +46,10 @@ const ProjectViews: NextPage = (props) => { ); return ( - @@ -116,37 +107,8 @@ const ProjectViews: NextPage = (props) => { )} - + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - const projectId = ctx.query.projectId as string; - const workspaceSlug = ctx.query.workspaceSlug as string; - - const memberDetail = await requiredAdmin(workspaceSlug, projectId, ctx.req?.headers.cookie); - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default ProjectViews; diff --git a/apps/app/pages/[workspaceSlug]/projects/index.tsx b/apps/app/pages/[workspaceSlug]/projects/index.tsx index 93d318def..4cac912f3 100644 --- a/apps/app/pages/[workspaceSlug]/projects/index.tsx +++ b/apps/app/pages/[workspaceSlug]/projects/index.tsx @@ -1,15 +1,16 @@ import React, { useState } from "react"; + import { useRouter } from "next/router"; + import { mutate } from "swr"; -// lib -import { requiredAuth } from "lib/auth"; + // services import projectService from "services/project.service"; // hooks import useProjects from "hooks/use-projects"; import useWorkspaces from "hooks/use-workspaces"; // layouts -import AppLayout from "layouts/app-layout"; +import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // components import { JoinProjectModal } from "components/project/join-project-modal"; import { DeleteProjectModal, SingleProjectCard } from "components/project"; @@ -19,7 +20,7 @@ import { Breadcrumbs, BreadcrumbItem } from "components/breadcrumbs"; // icons import { PlusIcon } from "@heroicons/react/24/outline"; // types -import type { GetServerSidePropsContext, NextPage } from "next"; +import type { NextPage } from "next"; // fetch-keys import { PROJECT_MEMBERS } from "constants/fetch-keys"; // image @@ -37,7 +38,7 @@ const ProjectsPage: NextPage = () => { const [selectedProjectToJoin, setSelectedProjectToJoin] = useState(null); return ( - @@ -113,29 +114,8 @@ const ProjectsPage: NextPage = () => { )} - + ); }; -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const user = await requiredAuth(ctx.req?.headers.cookie); - - const redirectAfterSignIn = ctx.resolvedUrl; - - if (!user) { - return { - redirect: { - destination: `/signin?next=${redirectAfterSignIn}`, - permanent: false, - }, - }; - } - - return { - props: { - user, - }, - }; -}; - export default ProjectsPage; diff --git a/apps/app/pages/[workspaceSlug]/settings/billing.tsx b/apps/app/pages/[workspaceSlug]/settings/billing.tsx index b695913f9..6dacb382e 100644 --- a/apps/app/pages/[workspaceSlug]/settings/billing.tsx +++ b/apps/app/pages/[workspaceSlug]/settings/billing.tsx @@ -4,28 +4,19 @@ import { useRouter } from "next/router"; import useSWR from "swr"; -// lib -import { requiredWorkspaceAdmin } from "lib/auth"; // services import workspaceService from "services/workspace.service"; // layouts -import AppLayout from "layouts/app-layout"; +import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // ui import { SecondaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // types -import type { NextPage, GetServerSideProps } from "next"; +import type { NextPage } from "next"; // fetch-keys import { WORKSPACE_DETAILS } from "constants/fetch-keys"; -type TBillingSettingsProps = { - isOwner: boolean; - isMember: boolean; - isViewer: boolean; - isGuest: boolean; -}; - -const BillingSettings: NextPage = (props) => { +const BillingSettings: NextPage = () => { const { query: { workspaceSlug }, } = useRouter(); @@ -36,72 +27,44 @@ const BillingSettings: NextPage = (props) => { ); return ( - <> - - - - - } - settingsLayout - > -
+ + + + + } + > +
+
+

Billing & Plans

+

[Free launch preview] plan Pro

+
+
-

Billing & Plans

-

[Free launch preview] plan Pro

-
-
-
-
-

Payment due

-

--

-
-
-
-

Current plan

-

You are currently using the free plan

- - View Plans and Upgrade - -
-
-

Billing history

-

There are no invoices to display

+
+

Payment due

+

--

-
- - +
+

Current plan

+

You are currently using the free plan

+ + View Plans and Upgrade + +
+
+

Billing history

+

There are no invoices to display

+
+ +
+ ); }; -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const workspaceSlug = ctx.params?.workspaceSlug as string; - - const memberDetail = await requiredWorkspaceAdmin(workspaceSlug, ctx.req.headers.cookie); - - if (memberDetail === null) { - return { - redirect: { - destination: "/", - permanent: false, - }, - }; - } - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default BillingSettings; diff --git a/apps/app/pages/[workspaceSlug]/settings/import-export.tsx b/apps/app/pages/[workspaceSlug]/settings/import-export.tsx index 5b458dd72..41ef3177b 100644 --- a/apps/app/pages/[workspaceSlug]/settings/import-export.tsx +++ b/apps/app/pages/[workspaceSlug]/settings/import-export.tsx @@ -1,58 +1,30 @@ import { useRouter } from "next/router"; -// lib -import { requiredWorkspaceAdmin } from "lib/auth"; // layouts -import AppLayout from "layouts/app-layout"; +import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; +// components import IntegrationGuide from "components/integration/guide"; // ui import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // types -import { UserAuth } from "types"; -import type { GetServerSideProps, NextPage } from "next"; +import type { NextPage } from "next"; -const ImportExport: NextPage = (props) => { +const ImportExport: NextPage = () => { const router = useRouter(); const { workspaceSlug } = router.query; return ( - } - settingsLayout > - + ); }; -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const workspaceSlug = ctx.params?.workspaceSlug as string; - - const memberDetail = await requiredWorkspaceAdmin(workspaceSlug, ctx.req.headers.cookie); - - if (memberDetail === null) { - return { - redirect: { - destination: "/", - permanent: false, - }, - }; - } - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default ImportExport; diff --git a/apps/app/pages/[workspaceSlug]/settings/index.tsx b/apps/app/pages/[workspaceSlug]/settings/index.tsx index 28c5faa9c..1966f765b 100644 --- a/apps/app/pages/[workspaceSlug]/settings/index.tsx +++ b/apps/app/pages/[workspaceSlug]/settings/index.tsx @@ -7,29 +7,26 @@ import useSWR, { mutate } from "swr"; // react-hook-form import { Controller, useForm } from "react-hook-form"; - -// icons -import { LinkIcon } from "@heroicons/react/24/outline"; -// lib -import { requiredWorkspaceAdmin } from "lib/auth"; // services import workspaceService from "services/workspace.service"; import fileService from "services/file.service"; // hooks import useToast from "hooks/use-toast"; // layouts -import AppLayout from "layouts/app-layout"; +import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // components import { ImageUploadModal } from "components/core"; import { DeleteWorkspaceModal } from "components/workspace"; // ui import { Spinner, Input, CustomSelect, OutlineButton, SecondaryButton } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; +// icons +import { LinkIcon } from "@heroicons/react/24/outline"; // helpers import { copyTextToClipboard } from "helpers/string.helper"; // types -import type { IWorkspace, UserAuth } from "types"; -import type { GetServerSideProps, NextPage } from "next"; +import type { IWorkspace } from "types"; +import type { NextPage } from "next"; // fetch-keys import { WORKSPACE_DETAILS, USER_WORKSPACES } from "constants/fetch-keys"; // constants @@ -42,7 +39,7 @@ const defaultValues: Partial = { logo: null, }; -const WorkspaceSettings: NextPage = (props) => { +const WorkspaceSettings: NextPage = () => { const [isOpen, setIsOpen] = useState(false); const [isImageUploading, setIsImageUploading] = useState(false); const [isImageUploadModalOpen, setIsImageUploadModalOpen] = useState(false); @@ -107,8 +104,7 @@ const WorkspaceSettings: NextPage = (props) => { }; return ( - = (props) => { } - settingsLayout > = (props) => { )} - + ); }; -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const workspaceSlug = ctx.params?.workspaceSlug as string; - - const memberDetail = await requiredWorkspaceAdmin(workspaceSlug, ctx.req.headers.cookie); - - if (memberDetail === null) { - return { - redirect: { - destination: "/", - permanent: false, - }, - }; - } - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default WorkspaceSettings; diff --git a/apps/app/pages/[workspaceSlug]/settings/integrations.tsx b/apps/app/pages/[workspaceSlug]/settings/integrations.tsx index e4dfd916f..71908bc5d 100644 --- a/apps/app/pages/[workspaceSlug]/settings/integrations.tsx +++ b/apps/app/pages/[workspaceSlug]/settings/integrations.tsx @@ -7,22 +7,19 @@ import useSWR from "swr"; // services import workspaceService from "services/workspace.service"; import IntegrationService from "services/integration"; -// lib -import { requiredWorkspaceAdmin } from "lib/auth"; // layouts -import AppLayout from "layouts/app-layout"; -// componentss +import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; +// components import OAuthPopUp from "components/popup"; // ui import { Loader } from "components/ui"; import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // types -import type { NextPage, GetServerSideProps } from "next"; -import { UserAuth } from "types"; +import type { NextPage } from "next"; // fetch-keys import { WORKSPACE_DETAILS, APP_INTEGRATIONS } from "constants/fetch-keys"; -const WorkspaceIntegrations: NextPage = (props) => { +const WorkspaceIntegrations: NextPage = () => { const router = useRouter(); const { workspaceSlug } = router.query; @@ -36,66 +33,38 @@ const WorkspaceIntegrations: NextPage = (props) => { ); return ( - <> - - - - - } - settingsLayout - > -
-

Integrations

-
- {appIntegrations ? ( - appIntegrations.map((integration) => ( - - )) - ) : ( - - - - - )} -
-
-
- + + + + + } + > +
+

Integrations

+
+ {appIntegrations ? ( + appIntegrations.map((integration) => ( + + )) + ) : ( + + + + + )} +
+
+
); }; -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const workspaceSlug = ctx.params?.workspaceSlug as string; - - const memberDetail = await requiredWorkspaceAdmin(workspaceSlug, ctx.req.headers.cookie); - - if (memberDetail === null) { - return { - redirect: { - destination: "/", - permanent: false, - }, - }; - } - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default WorkspaceIntegrations; diff --git a/apps/app/pages/[workspaceSlug]/settings/members.tsx b/apps/app/pages/[workspaceSlug]/settings/members.tsx index fe3f9ee98..a85c00cf3 100644 --- a/apps/app/pages/[workspaceSlug]/settings/members.tsx +++ b/apps/app/pages/[workspaceSlug]/settings/members.tsx @@ -5,14 +5,12 @@ import { useRouter } from "next/router"; import useSWR from "swr"; -// lib -import { requiredWorkspaceAdmin } from "lib/auth"; // hooks import useToast from "hooks/use-toast"; // services import workspaceService from "services/workspace.service"; // layouts -import AppLayout from "layouts/app-layout"; +import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // components import ConfirmWorkspaceMemberRemove from "components/workspace/confirm-workspace-member-remove"; import SendWorkspaceInvitationModal from "components/workspace/send-workspace-invitation-modal"; @@ -22,14 +20,13 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; // icons import { PlusIcon } from "@heroicons/react/24/outline"; // types -import type { GetServerSideProps, NextPage } from "next"; -import { UserAuth } from "types"; +import type { NextPage } from "next"; // fetch-keys import { WORKSPACE_DETAILS, WORKSPACE_INVITATIONS, WORKSPACE_MEMBERS } from "constants/fetch-keys"; // constants import { ROLE } from "constants/workspace"; -const MembersSettings: NextPage = (props) => { +const MembersSettings: NextPage = () => { const [selectedRemoveMember, setSelectedRemoveMember] = useState(null); const [selectedInviteRemoveMember, setSelectedInviteRemoveMember] = useState(null); const [inviteModal, setInviteModal] = useState(false); @@ -129,8 +126,7 @@ const MembersSettings: NextPage = (props) => { workspace_slug={workspaceSlug as string} members={members} /> - = (props) => { } - settingsLayout >
@@ -254,33 +249,9 @@ const MembersSettings: NextPage = (props) => {
)}
-
+ ); }; -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const workspaceSlug = ctx.params?.workspaceSlug as string; - - const memberDetail = await requiredWorkspaceAdmin(workspaceSlug, ctx.req.headers.cookie); - - if (memberDetail === null) { - return { - redirect: { - destination: "/", - permanent: false, - }, - }; - } - - return { - props: { - isOwner: memberDetail?.role === 20, - isMember: memberDetail?.role === 15, - isViewer: memberDetail?.role === 10, - isGuest: memberDetail?.role === 5, - }, - }; -}; - export default MembersSettings; diff --git a/apps/app/pages/installations/[provider]/index.tsx b/apps/app/pages/installations/[provider]/index.tsx index 478bb0a23..130011a86 100644 --- a/apps/app/pages/installations/[provider]/index.tsx +++ b/apps/app/pages/installations/[provider]/index.tsx @@ -42,7 +42,6 @@ const AppPostInstallation = ({ }; export async function getServerSideProps(context: any) { - console.log(context.query); return { props: context.query, }; diff --git a/apps/app/public/join-project.svg b/apps/app/public/auth/join-project.svg similarity index 100% rename from apps/app/public/join-project.svg rename to apps/app/public/auth/join-project.svg diff --git a/apps/app/public/project-setting.svg b/apps/app/public/auth/project-not-authorized.svg similarity index 100% rename from apps/app/public/project-setting.svg rename to apps/app/public/auth/project-not-authorized.svg diff --git a/apps/app/public/auth/workspace-not-authorized.svg b/apps/app/public/auth/workspace-not-authorized.svg new file mode 100644 index 000000000..dad2b0c05 --- /dev/null +++ b/apps/app/public/auth/workspace-not-authorized.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/app/services/project.service.ts b/apps/app/services/project.service.ts index 02a3b46ac..f1740152b 100644 --- a/apps/app/services/project.service.ts +++ b/apps/app/services/project.service.ts @@ -136,7 +136,7 @@ class ProjectServices extends APIService { return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/project-members/me/`) .then((response) => response?.data) .catch((error) => { - throw error?.response?.data; + throw error?.response; }); } diff --git a/apps/app/services/workspace.service.ts b/apps/app/services/workspace.service.ts index 8010b66c7..6a67a1a7a 100644 --- a/apps/app/services/workspace.service.ts +++ b/apps/app/services/workspace.service.ts @@ -137,7 +137,7 @@ class WorkspaceService extends APIService { return this.get(`/api/workspaces/${workspaceSlug}/workspace-members/me/`) .then((response) => response?.data) .catch((error) => { - throw error?.response?.data; + throw error?.response; }); }