Implement Authentication with email + password (#343)

* Implement Login screen ui and add RequireNotAuth guard

* Perform login through auth/password-login flow
This commit is contained in:
Charles Bochet
2023-06-21 04:17:31 +02:00
committed by GitHub
parent e2d8c3a2ec
commit 8790369f72
18 changed files with 288 additions and 76 deletions

View File

@ -1,12 +0,0 @@
import styled from '@emotion/styled';
type OwnProps = {
label: string;
subLabel?: string;
};
const StyledContainer = styled.div``;
export function SubTitle({ label, subLabel }: OwnProps): JSX.Element {
return <StyledContainer>{label}</StyledContainer>;
}

View File

@ -0,0 +1,52 @@
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { keyframes } from '@emotion/react';
import styled from '@emotion/styled';
import { hasAccessToken } from '../services/AuthService';
const EmptyContainer = styled.div`
align-items: center;
display: flex;
height: 100%;
justify-content: center;
width: 100%;
`;
const fadeIn = keyframes`
from {
opacity: 0;
}
to {
opacity: 1;
}
`;
const FadeInStyle = styled.div`
animation: ${fadeIn} 1s forwards;
opacity: 0;
`;
export function RequireNotAuth({
children,
}: {
children: JSX.Element;
}): JSX.Element {
const navigate = useNavigate();
useEffect(() => {
if (hasAccessToken()) {
navigate('/');
}
}, [navigate]);
if (hasAccessToken())
return (
<EmptyContainer>
<FadeInStyle>
Please hold on a moment, we're directing you to the app...
</FadeInStyle>
</EmptyContainer>
);
return children;
}

View File

@ -1,11 +0,0 @@
import styled from '@emotion/styled';
type OwnProps = {
subTitle: string;
};
const StyledSubTitle = styled.div``;
export function SubTitle({ subTitle }: OwnProps): JSX.Element {
return <StyledSubTitle>{subTitle}</StyledSubTitle>;
}

View File

@ -0,0 +1,16 @@
import styled from '@emotion/styled';
type OwnProps = {
label: string;
subLabel?: string;
};
const StyledContainer = styled.div`
font-weight: ${({ theme }) => theme.fontWeightMedium};
margin-bottom: ${({ theme }) => theme.spacing(4)};
margin-top: ${({ theme }) => theme.spacing(4)};
`;
export function InputLabel({ label, subLabel }: OwnProps): JSX.Element {
return <StyledContainer>{label}</StyledContainer>;
}

View File

@ -13,7 +13,7 @@ const StyledLogo = styled.div`
export function Logo(): JSX.Element {
return (
<StyledLogo>
<img src="icons/android/android-launchericon-192-192.png" alt="logo" />
<img src="/icons/android/android-launchericon-192-192.png" alt="logo" />
</StyledLogo>
);
}

View File

@ -0,0 +1,15 @@
import React from 'react';
import styled from '@emotion/styled';
type OwnProps = {
children: React.ReactNode;
};
const StyledSubTitle = styled.div`
color: ${({ theme }) => theme.text60};
margin-top: ${({ theme }) => theme.spacing(2)};
`;
export function SubTitle({ children }: OwnProps): JSX.Element {
return <StyledSubTitle>{children}</StyledSubTitle>;
}

View File

@ -1,7 +1,8 @@
import React from 'react';
import styled from '@emotion/styled';
type OwnProps = {
title: string;
children: React.ReactNode;
};
const StyledTitle = styled.div`
@ -10,6 +11,6 @@ const StyledTitle = styled.div`
margin-top: ${({ theme }) => theme.spacing(10)};
`;
export function Title({ title }: OwnProps): JSX.Element {
return <StyledTitle>{title}</StyledTitle>;
export function Title({ children }: OwnProps): JSX.Element {
return <StyledTitle>{children}</StyledTitle>;
}

View File

@ -0,0 +1,6 @@
import { atom } from 'recoil';
export const authFlowUserEmailState = atom<string>({
key: 'authFlowUserEmailState',
default: '',
});

View File

@ -1,10 +1,11 @@
import { ChangeEvent, useState } from 'react';
import styled from '@emotion/styled';
type OwnProps = {
value: string;
type OwnProps = Omit<
React.InputHTMLAttributes<HTMLInputElement>,
'onChange'
> & {
onChange?: (text: string) => void;
placeholder?: string;
fullWidth?: boolean;
};
@ -32,8 +33,8 @@ const StyledInput = styled.input<{ fullWidth: boolean }>`
export function TextInput({
value,
onChange,
placeholder,
fullWidth,
...props
}: OwnProps): JSX.Element {
const [internalValue, setInternalValue] = useState(value);
@ -41,13 +42,13 @@ export function TextInput({
<StyledInput
fullWidth={fullWidth ?? false}
value={internalValue}
placeholder={placeholder}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
setInternalValue(event.target.value);
if (onChange) {
onChange(event.target.value);
}
}}
{...props}
/>
);
}