style: auth screens (#478)

* style: sign in page

* style: github and google sign

* style: sign with code and password

* style: not a member and not authorized for project setting

* style: join project icon

* chore: comment removed
This commit is contained in:
Anmol Singh Bhatia 2023-03-21 12:46:12 +05:30 committed by GitHub
parent 68150a9d2b
commit b96d40f106
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 178 additions and 85 deletions

View File

@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
// ui // ui
import { CheckCircleIcon } from "@heroicons/react/20/solid"; import { CheckCircleIcon } from "@heroicons/react/20/solid";
import { Input, SecondaryButton } from "components/ui"; import { Input, PrimaryButton, SecondaryButton } from "components/ui";
// services // services
import authenticationService from "services/authentication.service"; import authenticationService from "services/authentication.service";
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
@ -90,7 +90,7 @@ export const EmailCodeForm = ({ onSuccess }: any) => {
return ( return (
<> <>
<form className="mt-5 space-y-5"> <form className="space-y-5 py-5 px-5">
{(codeSent || codeResent) && ( {(codeSent || codeResent) && (
<div className="rounded-md bg-green-50 p-4"> <div className="rounded-md bg-green-50 p-4">
<div className="flex"> <div className="flex">
@ -121,7 +121,7 @@ export const EmailCodeForm = ({ onSuccess }: any) => {
) || "Email ID is not valid", ) || "Email ID is not valid",
}} }}
error={errors.email} error={errors.email}
placeholder="Enter your Email ID" placeholder="Enter you email Id"
/> />
</div> </div>
@ -169,18 +169,20 @@ export const EmailCodeForm = ({ onSuccess }: any) => {
)} )}
<div> <div>
{codeSent ? ( {codeSent ? (
<SecondaryButton <PrimaryButton
type="submit" type="submit"
className="w-full text-center" className="w-full text-center"
size="md"
onClick={handleSubmit(handleSignin)} onClick={handleSubmit(handleSignin)}
loading={isSubmitting || (!isValid && isDirty)} loading={isSubmitting || (!isValid && isDirty)}
> >
{isSubmitting ? "Signing in..." : "Sign in"} {isSubmitting ? "Signing in..." : "Sign in"}
</SecondaryButton> </PrimaryButton>
) : ( ) : (
<SecondaryButton <PrimaryButton
type="submit" type="submit"
className="w-full text-center" className="w-full text-center"
size="md"
onClick={() => { onClick={() => {
handleSubmit(onSubmit)().then(() => { handleSubmit(onSubmit)().then(() => {
setResendCodeTimer(30); setResendCodeTimer(30);
@ -189,7 +191,7 @@ export const EmailCodeForm = ({ onSuccess }: any) => {
loading={isSubmitting || (!isValid && isDirty)} loading={isSubmitting || (!isValid && isDirty)}
> >
{isSubmitting ? "Sending code..." : "Send code"} {isSubmitting ? "Sending code..." : "Send code"}
</SecondaryButton> </PrimaryButton>
)} )}
</div> </div>
</form> </form>

View File

@ -60,7 +60,7 @@ export const EmailPasswordForm = ({ onSuccess }: any) => {
}; };
return ( return (
<> <>
<form className="mt-5" onSubmit={handleSubmit(onSubmit)}> <form className="mt-5 py-5 px-5" onSubmit={handleSubmit(onSubmit)}>
<div> <div>
<Input <Input
id="email" id="email"

View File

@ -19,28 +19,6 @@ export const EmailSignInForm: FC<EmailSignInFormProps> = (props) => {
) : ( ) : (
<EmailPasswordForm onSuccess={handleSuccess} /> <EmailPasswordForm onSuccess={handleSuccess} />
)} )}
<div className="mt-6">
<div className="relative">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-300" />
</div>
<div className="relative flex justify-center text-sm">
<span className="bg-white px-2 text-gray-500">or</span>
</div>
</div>
{/* <div className="mt-6 flex w-full flex-col items-stretch gap-y-2">
<button
type="button"
className="flex w-full items-center rounded border border-gray-300 px-3 py-2 text-sm duration-300 hover:bg-gray-100"
onClick={() => setUseCode((prev) => !prev)}
>
<KeyIcon className="h-[25px] w-[25px]" />
<span className="w-full text-center font-medium">
{useCode ? "Continue with Password" : "Continue with Code"}
</span>
</button>
</div> */}
</div>
</> </>
); );
}; };

View File

@ -3,7 +3,7 @@ import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
// images // images
import githubImage from "/public/logos/github.png"; import githubImage from "/public/logos/github-black.png";
const { NEXT_PUBLIC_GITHUB_ID } = process.env; const { NEXT_PUBLIC_GITHUB_ID } = process.env;
@ -33,19 +33,15 @@ export const GithubLoginButton: FC<GithubLoginButtonProps> = (props) => {
}, []); }, []);
return ( return (
<div className="px-1 w-full">
<Link <Link
href={`https://github.com/login/oauth/authorize?client_id=${NEXT_PUBLIC_GITHUB_ID}&redirect_uri=${loginCallBackURL}&scope=read:user,user:email`} href={`https://github.com/login/oauth/authorize?client_id=${NEXT_PUBLIC_GITHUB_ID}&redirect_uri=${loginCallBackURL}&scope=read:user,user:email`}
> >
<button className="flex w-full items-center rounded bg-black px-3 py-2 text-sm text-white opacity-90 duration-300 hover:opacity-100"> <button className="flex w-full items-center justify-center gap-3 rounded-md border border-gray-200 p-2 text-sm font-medium text-gray-600 duration-300 hover:bg-gray-50">
<Image <Image src={githubImage} height={22} width={22} color="#000" alt="GitHub Logo" />
src={githubImage} <span>Sign In with Github</span>
height={25}
width={25}
className="flex-shrink-0"
alt="GitHub Logo"
/>
<span className="w-full text-center font-medium">Continue with GitHub</span>
</button> </button>
</Link> </Link>
</div>
); );
}; };

View File

@ -27,7 +27,7 @@ export const GoogleLoginButton: FC<IGoogleLoginButton> = (props) => {
theme: "outline", theme: "outline",
size: "large", size: "large",
logo_alignment: "center", logo_alignment: "center",
width: document.getElementById("googleSignInButton")?.offsetWidth, width: "410",
text: "continue_with", text: "continue_with",
} as GsiButtonConfiguration // customization attributes } as GsiButtonConfiguration // customization attributes
); );
@ -47,7 +47,7 @@ export const GoogleLoginButton: FC<IGoogleLoginButton> = (props) => {
return ( return (
<> <>
<Script src="https://accounts.google.com/gsi/client" async defer onLoad={loadScript} /> <Script src="https://accounts.google.com/gsi/client" async defer onLoad={loadScript} />
<div className="w-full" id="googleSignInButton" ref={googleSignInButton} /> <div className="h-12" id="googleSignInButton" ref={googleSignInButton} />
</> </>
); );
}; };

View File

@ -1,13 +1,14 @@
import React from "react"; import React from "react";
// next // next
import Link from "next/link"; import Link from "next/link";
import Image from "next/image";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
// layouts // layouts
import DefaultLayout from "layouts/default-layout"; import DefaultLayout from "layouts/default-layout";
// hooks // hooks
import useUser from "hooks/use-user"; import useUser from "hooks/use-user";
// icons // img
import { LockIcon } from "components/icons"; import ProjectSettingImg from "public/project-setting.svg";
type TNotAuthorizedViewProps = { type TNotAuthorizedViewProps = {
actionButton?: React.ReactNode; actionButton?: React.ReactNode;
@ -27,25 +28,27 @@ 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="flex h-full w-full flex-col items-center justify-center gap-y-5 text-center">
<LockIcon className="h-16 w-16 text-gray-400" /> <div className="h-44 w-72">
<Image src={ProjectSettingImg} height="176" width="288" alt="ProjectSettingImg" />
</div>
<h1 className="text-xl font-medium text-gray-900"> <h1 className="text-xl font-medium text-gray-900">
Oops! You are not authorized to view this page Oops! You are not authorized to view this page
</h1> </h1>
<div className="w-full md:w-1/3"> <div className="w-full text-base text-gray-500 max-w-md ">
{user ? ( {user ? (
<p className="text-base font-light"> <p className="">
You have signed in as <span className="font-medium">{user.email}</span>.{" "} You have signed in as {user.email}.{" "}
<Link href={`/signin?next=${currentPath}`}> <Link href={`/signin?next=${currentPath}`}>
<a className="font-medium">Sign in</a> <a className="text-gray-900 font-medium">Sign in</a>
</Link>{" "} </Link>{" "}
with different account that has access to this page. with different account that has access to this page.
</p> </p>
) : ( ) : (
<p className="text-base font-light"> <p className="">
You need to{" "} You need to{" "}
<Link href={`/signin?next=${currentPath}`}> <Link href={`/signin?next=${currentPath}`}>
<a className="font-medium">Sign in</a> <a className="text-gray-900 font-medium">Sign in</a>
</Link>{" "} </Link>{" "}
with an account that has access to this page. with an account that has access to this page.
</p> </p>

View File

@ -1,7 +1,13 @@
import { FC } from "react"; import { FC } from "react";
// next
import Image from "next/image";
// ui // ui
import { SecondaryButton } from "components/ui"; import { PrimaryButton } from "components/ui";
// icon
import { AssignmentClipboardIcon } from "components/icons";
// img
import JoinProjectImg from "public/join-project.svg";
export interface JoinProjectProps { export interface JoinProjectProps {
isJoiningProject: boolean; isJoiningProject: boolean;
@ -9,18 +15,27 @@ export interface JoinProjectProps {
} }
export const JoinProject: FC<JoinProjectProps> = ({ isJoiningProject, handleJoin }) => ( export const JoinProject: FC<JoinProjectProps> = ({ isJoiningProject, handleJoin }) => (
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full flex-col items-center justify-center gap-y-5 text-center">
<div className="space-y-4 text-center"> <div className="h-44 w-72">
<h1 className="text-2xl font-bold">You are not a member of this project</h1> <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"> <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 You are not a member of this project, but you can join this project by clicking the button
below. below.
</p> </p>
<div>
<SecondaryButton loading={isJoiningProject} onClick={handleJoin}>
{isJoiningProject ? "Joining..." : "Click to join"}
</SecondaryButton>
</div> </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>
</div> </div>
); );

View File

@ -10,7 +10,9 @@ import projectService from "services/project.service";
// hooks // hooks
import useUser from "hooks/use-user"; import useUser from "hooks/use-user";
// ui // ui
import { SecondaryButton, Spinner } from "components/ui"; import { PrimaryButton, Spinner } from "components/ui";
// icon
import { LayerDiagonalIcon } from "components/icons";
// components // components
import { NotAuthorizedView } from "components/core"; import { NotAuthorizedView } from "components/core";
import { CommandPalette } from "components/command-palette"; import { CommandPalette } from "components/command-palette";
@ -103,13 +105,17 @@ const AppLayout: FC<AppLayoutProps> = ({
actionButton={ actionButton={
(memberType?.isViewer || memberType?.isGuest) && projectId ? ( (memberType?.isViewer || memberType?.isGuest) && projectId ? (
<Link href={`/${workspaceSlug}/projects/${projectId}/issues`}> <Link href={`/${workspaceSlug}/projects/${projectId}/issues`}>
<SecondaryButton>Go to Issues</SecondaryButton> <PrimaryButton className="flex items-center gap-1">
<LayerDiagonalIcon height={16} width={16} color="white" /> Go to Issues
</PrimaryButton>
</Link> </Link>
) : ( ) : (
(memberType?.isViewer || memberType?.isGuest) && (memberType?.isViewer || memberType?.isGuest) &&
workspaceSlug && ( workspaceSlug && (
<Link href={`/${workspaceSlug}`}> <Link href={`/${workspaceSlug}`}>
<SecondaryButton>Go to workspace</SecondaryButton> <PrimaryButton className="flex items-center gap-1">
<LayerDiagonalIcon height={16} width={16} color="white" /> Go to workspace
</PrimaryButton>
</Link> </Link>
) )
) )

View File

@ -20,7 +20,7 @@ import {
// ui // ui
import { Spinner } from "components/ui"; import { Spinner } from "components/ui";
// icons // icons
import Logo from "public/logo-with-text.png"; import Logo from "public/logo.png";
// types // types
import type { NextPage } from "next"; import type { NextPage } from "next";
@ -105,31 +105,28 @@ const SignInPage: NextPage = () => {
)} )}
<div className="flex h-screen w-full items-center justify-center overflow-auto bg-gray-50"> <div className="flex h-screen w-full items-center justify-center overflow-auto bg-gray-50">
<div className="flex min-h-full w-full flex-col justify-center py-12 px-6 lg:px-8"> <div className="flex min-h-full w-full flex-col justify-center py-12 px-6 lg:px-8">
<div className="sm:mx-auto sm:w-full sm:max-w-md"> <div className="flex flex-col gap-10 sm:mx-auto sm:w-full sm:max-w-md">
<div className="text-center"> <div className="flex flex-col items-center justify-center gap-10">
<Image src={Logo} height={40} width={179} alt="Plane Web Logo" /> <Image src={Logo} height={80} width={80} alt="Plane Web Logo" />
</div> <h2 className="text-center text-xl font-medium text-black">
<h2 className="mt-3 text-center text-3xl font-bold text-gray-900"> Sign In to your Plane Account
Sign in to your account
</h2> </h2>
<div className="mt-16 bg-white py-8 px-4 sm:rounded-lg sm:px-10"> </div>
<div className="flex flex-col rounded-[10px] bg-white shadow-md">
{parseInt(process.env.NEXT_PUBLIC_ENABLE_OAUTH || "0") ? ( {parseInt(process.env.NEXT_PUBLIC_ENABLE_OAUTH || "0") ? (
<> <>
<div className="mb-4">
<EmailSignInForm handleSuccess={onSignInSuccess} /> <EmailSignInForm handleSuccess={onSignInSuccess} />
</div>
<div className="mb-4"> <div className="flex flex-col gap-3 py-5 px-5 border-t items-center justify-center border-gray-300 ">
<GoogleLoginButton handleSignIn={handleGoogleSignIn} /> <GoogleLoginButton handleSignIn={handleGoogleSignIn} />
</div>
<div className="mb-4">
<GithubLoginButton handleSignIn={handleGithubSignIn} /> <GithubLoginButton handleSignIn={handleGithubSignIn} />
</div> </div>
</> </>
) : ( ) : (
<> <>
<div className="mb-4">
<EmailPasswordForm onSuccess={onSignInSuccess} /> <EmailPasswordForm onSuccess={onSignInSuccess} />
</div>
</> </>
)} )}
</div> </div>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 33 KiB