Skip to content

Commit

Permalink
Merge pull request #1078 from The-Commit-Company/redesign-login-page
Browse files Browse the repository at this point in the history
fix: redesign login page
  • Loading branch information
nikkothari22 authored Oct 10, 2024
2 parents 7e2f44d + b5e5ef5 commit 4b39eb7
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 98 deletions.
14 changes: 6 additions & 8 deletions frontend/src/components/layout/AuthContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PropsWithChildren, useContext } from 'react'
import { Box, Flex, Text } from '@radix-ui/themes';
import { Box, Flex, Heading, Text } from '@radix-ui/themes';
import { FullPageLoader } from "./Loaders";
import { Link } from 'react-router-dom';
import { UserContext } from '@/utils/auth/UserProvider';
Expand All @@ -10,20 +10,18 @@ const AuthContainer = ({ children, ...props }: PropsWithChildren) => {

return (
<Box className={'min-h-screen'}>
<Flex justify='center' align='center' className={'h-screen w-full'}>
<Flex justify='center' align='center' className={'h-screen w-full dark:bg-[#191919]'}>
{
isLoading ? <FullPageLoader /> :
<Box className={'w-full max-w-lg'}>
<Flex direction='column' gap='6' className={'w-full bg-white rounded-lg shadow dark:border dark:bg-gray-900 dark:border-gray-700 p-8'}>
<Box className={'w-full max-w-md p-8'}>
<Flex direction='column' gap='6' className={'w-full'}>

<Link to="/" tabIndex={-1}>
<Flex justify="center">
<Text as='span' size='9' className='cal-sans'>raven</Text>
<Flex>
<Heading size='9' className='cal-sans leading-normal tracking-normal w-fit'>raven</Heading>
</Flex>
</Link>

{children}

</Flex>
</Box>
}
Expand Down
15 changes: 12 additions & 3 deletions frontend/src/pages/auth/ForgotPassword.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ import { SuccessCallout } from "@/components/common/Callouts/SuccessCallout";
import { isEmailValid } from "@/utils/validations";
import { ForgotPasswordInput } from "@/types/Auth/Login";
import AuthContainer from "@/components/layout/AuthContainer";
import { useTheme } from "@/ThemeProvider";


export const Component = () => {

const { appearance } = useTheme()
const {
register,
handleSubmit,
Expand Down Expand Up @@ -60,7 +63,7 @@ export const Component = () => {
<form onSubmit={handleSubmit(resetPassword)}>
<Flex direction="column" gap="4">
<Flex direction="column" gap="2">
<Label htmlFor="user" isRequired>
<Label htmlFor="user" isRequired size='3'>
Email
</Label>
<TextField.Root {...register("user", {
Expand All @@ -71,21 +74,27 @@ export const Component = () => {
})}
name="user"
type="email"
size='3'
placeholder="jane@example.com"
color="gray"
variant={appearance === 'dark' ? "soft" : undefined}
tabIndex={0}
autoFocus />
{errors?.user && (
<ErrorText>{errors?.user?.message}</ErrorText>
)}
</Flex>
<Flex direction="column" gap="2">
<Button type="submit" disabled={isSubmitting}>
<Flex direction="column" gap="2" mt='2'>
<Button type="submit" disabled={isSubmitting}
size='3'
className="not-cal font-medium">
{isSubmitting ? <Loader /> : "Reset Password"}
</Button>
</Flex>
<Flex direction="column" gap="1" align="center">
<LinkButton
size="2"
color='gray'
asChild
>
<Link to='/login'>
Expand Down
186 changes: 114 additions & 72 deletions frontend/src/pages/auth/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
import { useState } from "react";
import { useForm } from "react-hook-form";
import { BiShow, BiHide, BiLogoGithub, BiLogoGoogle, BiLogoFacebookCircle, BiMailSend } from "react-icons/bi";
import { BiShow, BiHide, BiLogoGithub, BiLogoFacebookCircle, BiMailSend } from "react-icons/bi";
import { Link } from "react-router-dom";
import { Box, Button, Flex, IconButton, Text, TextField, Separator, Link as LinkButton } from "@radix-ui/themes";
import { Box, Button, Flex, IconButton, Text, TextField, Link as LinkButton } from "@radix-ui/themes";
import { FrappeError, useFrappeGetCall, useFrappeAuth, AuthResponse } from "frappe-react-sdk";
import { Loader } from "@/components/common/Loader";
import { ErrorText, Label } from "@/components/common/Form";
import { LoginInputs, LoginContext } from "@/types/Auth/Login";
import AuthContainer from "@/components/layout/AuthContainer";
import { TwoFactor } from "@/pages/auth/TwoFactor";
import { ErrorBanner } from "@/components/layout/AlertBanner";
import { DateSeparator } from "@/components/layout/Divider/DateSeparator";
import { FcGoogle } from "react-icons/fc";
import { useTheme } from "@/ThemeProvider";
import { Stack } from "@/components/layout/Stack";

const SocialProviderIcons = {
"github": <BiLogoGithub size="18" />,
"google": <BiLogoGoogle size="18" />,
"facebook": <BiLogoFacebookCircle size="18" />
export const SocialProviderIcons = {
"github": <BiLogoGithub size="24" />,
"google": <FcGoogle size="24" />,
"facebook": <BiLogoFacebookCircle size="24" color="#316FF6" />
}

interface SocialProvider {
export interface SocialProvider {
name: 'github' | 'google' | 'facebook'
provider_name: string,
auth_url: string,
Expand All @@ -30,14 +34,10 @@ interface SocialProvider {

export const Component = () => {

// GET call for Login Context (settings for social logins, email link etc)
const { data: loginContext, mutate } = useFrappeGetCall<LoginContext>('raven.api.login.get_context', {
"redirect-to": "/raven"
}, 'raven.api.login.get_context', {
revalidateOnMount: true,
revalidateOnReconnect: false,
revalidateOnFocus: false
})

const { appearance } = useTheme()

const { data: loginContext, mutate } = useLoginContext()
const [error, setError] = useState<FrappeError | null>(null)

const { login } = useFrappeAuth()
Expand Down Expand Up @@ -82,21 +82,24 @@ export const Component = () => {
<Flex direction='column' gap='4'>

<Flex direction='column' gap='2'>
<Label htmlFor='email' isRequired>{loginContext?.message?.login_label}</Label>
<Label htmlFor='email' isRequired size='3'>{loginContext?.message?.login_label}</Label>
<TextField.Root {...register("email",
{
required: `${loginContext?.message?.login_label} is required.`
})}
name="email"
type="text"
required
size='3'
color="gray"
variant={appearance === 'dark' ? "soft" : undefined}
placeholder="jane@example.com"
tabIndex={0} />
{errors?.email && <ErrorText>{errors?.email.message}</ErrorText>}
</Flex>

<Flex direction='column' gap='2'>
<Label htmlFor='password' isRequired>Password</Label>
<Label htmlFor='password' isRequired size='3'>Password</Label>
<TextField.Root {...register("password",
{
required: "Password is required.",
Expand All @@ -105,7 +108,10 @@ export const Component = () => {
type={isPasswordOpen ? "text" : "password"}
autoComplete="current-password"
required
placeholder="***********" >
size='3'
variant={appearance === 'dark' ? "soft" : undefined}
placeholder="***********"
color="gray" >
<TextField.Slot side='right'>
<IconButton
type='button'
Expand All @@ -119,72 +125,39 @@ export const Component = () => {
</TextField.Slot>
</TextField.Root>
{errors?.password && <ErrorText>{errors.password?.message}</ErrorText>}

<Flex direction='column' gap='2' align="end">
<LinkButton
asChild
color='gray'
size="2"
>
<Link to="/forgot-password">
Forgot Password?
</Link>
</LinkButton>
</Flex>
</Flex>

<Flex direction='column' gap='2' >
<Button type='submit' disabled={isSubmitting} >
<Flex direction='column' gap='2'>
<Button type='submit' disabled={isSubmitting}
size='3'
className="not-cal font-medium">
{isSubmitting ? <Loader /> : 'Login'}
</Button>
</Flex>
<Flex direction='column' gap='2' align="end">
<LinkButton
asChild
size="2"
>
<Link to="/forgot-password">
Forgot Password?
</Link>
</LinkButton>
</Flex>

</Flex>
</Flex>
</form>
{/* Show Separator only when either Email Link or Social Logins are enabled */}
{
loginContext?.message?.login_with_email_link || loginContext?.message?.social_login ?
<Flex justify='center' className="mt-8 mb-8">
<Separator className="w-full" />
</Flex> : null
}
{/* Map all social oauth providers */}
{
loginContext?.message?.social_login ? loginContext?.message?.provider_logins.map((soc: SocialProvider, i: number) => {
return (
<Flex direction='column' key={i} className="mb-4" >
<Button variant="soft" highContrast className="cursor-default" disabled={isSubmitting} asChild>
<Link to={soc.auth_url} className="flex items-center">
{SocialProviderIcons[soc.name] ? SocialProviderIcons[soc.name] : <img src={soc.icon.src} alt={soc.icon.alt} ></img>}
Login with {soc.provider_name}
</Link>
</Button>
</Flex>
)
}) : null
}

{
loginContext?.message?.login_with_email_link ?
<Flex direction='column' >
<Button type="button"
asChild
variant="soft"
highContrast
disabled={isSubmitting}
className="cursor-default"
>
<Link to="/login-with-email">
<BiMailSend size="18" />
<Text>Login with Email Link</Text>
</Link>
</Button>
</Flex> : null
}

</Box>
}
<OtherLoginMethods isSubmitting={isSubmitting} />
{
loginContext?.message?.disable_signup === 0 ?
<Flex gap="1" justify="center" className="mt-4">
<Text size="2" color="gray">Don't have account?</Text>
<Flex gap="1" justify="center">
<Text size="2" color="gray">Don't have an account yet?</Text>
<LinkButton
size="2"
asChild
Expand All @@ -200,4 +173,73 @@ export const Component = () => {
)
}

const useLoginContext = () => {
// GET call for Login Context (settings for social logins, email link etc)
return useFrappeGetCall<LoginContext>('raven.api.login.get_context', {
"redirect-to": "/raven"
}, 'raven.api.login.get_context', {
revalidateOnMount: true,
revalidateOnReconnect: false,
revalidateOnFocus: false
})
}

export const OtherLoginMethods = ({ isSubmitting }: { isSubmitting: boolean }) => {

const { data: loginContext } = useLoginContext()

return <Stack gap='3'>
{/* Show Separator only when either Email Link or Social Logins are enabled */}
{
loginContext?.message?.login_with_email_link || loginContext?.message?.social_login ?
<Flex justify='center' className="mt-1 mb-5 w-full">
<DateSeparator className="w-full">
<Text size='2' color='gray' className="uppercase">or</Text>
</DateSeparator>
</Flex> : null
}
{/* Map all social oauth providers */}
{
loginContext?.message?.social_login ? loginContext?.message?.provider_logins.map((soc: SocialProvider, i: number) => {
return (
<Flex direction='column' key={i} >
<Button
size='3'
color='gray'
variant="outline"
className="not-cal font-medium text-gray-12 dark:text-white"
disabled={isSubmitting}
asChild>
<Link to={soc.auth_url} className="flex items-center">
{SocialProviderIcons[soc.name] ? SocialProviderIcons[soc.name] : <img src={soc.icon.src} alt={soc.icon.alt} style={{ width: '20px', height: '20px' }} ></img>}
Continue with {soc.provider_name}
</Link>
</Button>
</Flex>
)
}) : null
}

{
loginContext?.message?.login_with_email_link ?
<Flex direction='column' >
<Button type="button"
asChild
size='3'
color='gray'
variant="outline"
className="not-cal font-medium text-gray-12 dark:text-white"
disabled={isSubmitting}
>
<Link to="/login-with-email">
<BiMailSend size="24" />
<Text>Login with Email Link</Text>
</Link>
</Button>
</Flex> : null
}
</Stack>

}

Component.displayName = "LoginPage";
Loading

0 comments on commit 4b39eb7

Please sign in to comment.