Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: new auth layer #740

Merged
merged 7 commits into from
Apr 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/app/components/auth-screens/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./project";
export * from "./workspace";
export * from "./not-authorized-view";
Original file line number Diff line number Diff line change
Expand Up @@ -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<TNotAuthorizedViewProps> = (props) => {
const { actionButton } = props;

export const NotAuthorizedView: React.FC<Props> = ({ actionButton, type }) => {
const { user } = useUser();
const { asPath: currentPath } = useRouter();

Expand All @@ -29,7 +29,12 @@ export const NotAuthorizedView: React.FC<TNotAuthorizedViewProps> = (props) => {
>
<div className="flex h-full w-full flex-col items-center justify-center gap-y-5 text-center">
<div className="h-44 w-72">
<Image src={ProjectSettingImg} height="176" width="288" alt="ProjectSettingImg" />
<Image
src={type === "project" ? ProjectNotAuthorizedImg : WorkspaceNotAuthorizedImg}
height="176"
width="288"
alt="ProjectSettingImg"
/>
</div>
<h1 className="text-xl font-medium text-gray-900">
Oops! You are not authorized to view this page
Expand All @@ -38,7 +43,7 @@ export const NotAuthorizedView: React.FC<TNotAuthorizedViewProps> = (props) => {
<div className="w-full text-base text-gray-500 max-w-md ">
{user ? (
<p className="">
You have signed in as {user.email}.{" "}
You have signed in as {user.email}. <br />
<Link href={`/signin?next=${currentPath}`}>
<a className="text-gray-900 font-medium">Sign in</a>
</Link>{" "}
Expand Down
1 change: 1 addition & 0 deletions apps/app/components/auth-screens/project/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./join-project";
64 changes: 64 additions & 0 deletions apps/app/components/auth-screens/project/join-project.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="flex h-full w-full flex-col items-center justify-center gap-y-5 text-center">
<div className="h-44 w-72">
<Image src={JoinProjectImg} height="176" width="288" alt="JoinProject" />
</div>
<h1 className="text-xl font-medium text-gray-900">You are not a member of this project</h1>

<div className="w-full max-w-md text-base text-gray-500 ">
<p className="mx-auto w-full text-sm md:w-3/4">
You are not a member of this project, but you can join this project by clicking the button
below.
</p>
</div>
<div>
<PrimaryButton
className="flex items-center gap-1"
loading={isJoiningProject}
onClick={handleJoin}
>
<AssignmentClipboardIcon height={16} width={16} color="white" />
{isJoiningProject ? "Joining..." : "Click to join"}
</PrimaryButton>
</div>
</div>
);
};
1 change: 1 addition & 0 deletions apps/app/components/auth-screens/workspace/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./not-a-member";
46 changes: 46 additions & 0 deletions apps/app/components/auth-screens/workspace/not-a-member.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<DefaultLayout
meta={{
title: "Plane - Unauthorized User",
description: "Unauthorized user",
}}
>
<div className="grid h-full place-items-center p-4">
<div className="space-y-8 text-center">
<div className="space-y-2">
<h3 className="text-lg font-semibold">Not Authorized!</h3>
<p className="text-sm text-gray-500 w-1/2 mx-auto">
You{"'"}re not a member of this workspace. Please contact the workspace admin to get
an invitation or check your pending invitations.
</p>
</div>
<div className="flex items-center gap-2 justify-center">
<Link href="/invitations">
<a>
<SecondaryButton onClick={() => router.back()}>
Check pending invites
</SecondaryButton>
</a>
</Link>
<Link href="/create-workspace">
<a>
<PrimaryButton>Create new workspace</PrimaryButton>
</a>
</Link>
</div>
</div>
</div>
</DefaultLayout>
);
};
1 change: 0 additions & 1 deletion apps/app/components/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
10 changes: 6 additions & 4 deletions apps/app/components/core/issues-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -49,14 +51,12 @@ type Props = {
type?: "issue" | "cycle" | "module";
openIssuesListModal?: () => void;
isCompleted?: boolean;
userAuth: UserAuth;
};

export const IssuesView: React.FC<Props> = ({
type = "issue",
openIssuesListModal,
isCompleted = false,
userAuth,
}) => {
// create issue modal
const [createIssueModal, setCreateIssueModal] = useState(false);
Expand Down Expand Up @@ -84,6 +84,8 @@ export const IssuesView: React.FC<Props> = ({
const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;

const { memberRole } = useProjectMyMembership();

const { setToastAlert } = useToast();

const {
Expand Down Expand Up @@ -494,7 +496,7 @@ export const IssuesView: React.FC<Props> = ({
: null
}
isCompleted={isCompleted}
userAuth={userAuth}
userAuth={memberRole}
/>
) : issueView === "kanban" ? (
<AllBoards
Expand All @@ -514,7 +516,7 @@ export const IssuesView: React.FC<Props> = ({
: null
}
isCompleted={isCompleted}
userAuth={userAuth}
userAuth={memberRole}
/>
) : (
<CalendarView />
Expand Down
15 changes: 7 additions & 8 deletions apps/app/components/issues/description-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"), {
Expand All @@ -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;
Expand All @@ -26,17 +28,14 @@ export interface IssueDescriptionFormValues {
export interface IssueDetailsProps {
issue: IIssue;
handleFormSubmit: (value: IssueDescriptionFormValues) => Promise<void>;
userAuth: UserAuth;
}

export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
issue,
handleFormSubmit,
userAuth,
}) => {
export const IssueDescriptionForm: FC<IssueDetailsProps> = ({ issue, handleFormSubmit }) => {
const [isSubmitting, setIsSubmitting] = useState(false);
const [characterLimit, setCharacterLimit] = useState(false);

const { memberRole } = useProjectMyMembership();

const {
handleSubmit,
watch,
Expand Down Expand Up @@ -86,7 +85,7 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
reset(issue);
}, [issue, reset]);

const isNotAllowed = userAuth.isGuest || userAuth.isViewer;
const isNotAllowed = memberRole.isGuest || memberRole.isViewer;

return (
<div className="relative">
Expand Down
Loading