Skip to content

Commit

Permalink
[#72] login register validations (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
asiaziola authored Mar 29, 2021
1 parent 2f3bc20 commit 376bf67
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 77 deletions.
5 changes: 5 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"axios": "^0.21.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-hook-form": "^6.15.5",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.2",
"react-typed": "^1.2.0",
Expand Down
229 changes: 168 additions & 61 deletions client/src/components/Form/Form.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
import { Checkbox, FormControlLabel, Icon, Theme } from '@material-ui/core';
import { Checkbox, FormControlLabel, Icon, Theme, TextField } from '@material-ui/core';
import {
StyledButtonGoogle,
StyledForm,
StyledTextField,
StyledLink,
StyledButton,
orParagraph,
StyledFormControlLabel
StyledParagraph,
StyledFormControlLabel,
StyledError
} from './styles';
import React, { FormEvent } from 'react';
import React, { FormEvent, useEffect } from 'react';
import { css } from '@emotion/react';
import { Grid } from './styles';
import { Search } from '@trejgun/material-ui-icons-google';
import { Container } from '@material-ui/core';
import { useForm, Controller } from 'react-hook-form';

interface FormProps {
isregister?: boolean;
onUsernameChange?: (e: string) => void;
onEmailChange: (e: string) => void;
onPasswordChange: (e: string) => void;
onSubmit: (e: FormEvent<HTMLFormElement>) => void;
error?: any;
}

interface IFormInput {
usernameInput: string;
emailInput: string;
passwordInput: string;
termsInput: string;
}

const handleGoogleRedirect = () => {
Expand All @@ -38,7 +48,32 @@ const handleGoogleRedirect = () => {
});
};

const Form = ({ isregister, onUsernameChange, onEmailChange, onPasswordChange, onSubmit }: FormProps) => {
const Form = ({ error, isregister, onUsernameChange, onEmailChange, onPasswordChange, onSubmit }: FormProps) => {
const { handleSubmit, control, errors, watch } = useForm<IFormInput>();
const emailWatch: string = watch(`emailInput`);
const usernameWatch: string = watch(`usernameInput`);
const passwordWatch: string = watch(`passwordInput`);

const passwordMatching = (value: string) => {
if (isregister) {
return value.match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,1024}$/) || '';
} else {
return true;
}
};

useEffect(() => {
onEmailChange(emailWatch);
}, [emailWatch]);

useEffect(() => {
onPasswordChange(passwordWatch);
}, [passwordWatch]);

useEffect(() => {
if (onUsernameChange) onUsernameChange(usernameWatch);
}, [usernameWatch]);

return (
<>
<Container maxWidth="sm">
Expand All @@ -51,63 +86,135 @@ const Form = ({ isregister, onUsernameChange, onEmailChange, onPasswordChange, o
spacing={1}
mt={4}
>
<Grid item xs={12}>
<StyledButtonGoogle onClick={() => handleGoogleRedirect()} variant="outlined">
<Search
css={css`
margin-right: 10px;
`}
/>
Kontynuuj przez Google
</StyledButtonGoogle>
<p css={orParagraph}>LUB</p>
<StyledForm onSubmit={(e) => onSubmit(e)} noValidate autoComplete="off">
<StyledTextField
isdisplay={isregister?.toString()}
className="test"
size="small"
id="outlined-basic"
variant="outlined"
required
placeholder="Nazwa użytkownika/użytkowniczki *"
autoFocus
onChange={(e) => onUsernameChange && onUsernameChange(e.target.value)}
/>
<StyledTextField
size="small"
id="outlined-basic"
variant="outlined"
required
placeholder="Email *"
onChange={(e) => onEmailChange(e.target.value)}
/>
<StyledTextField
size="small"
id="outlined-basic"
variant="outlined"
required
placeholder="Hasło *"
onChange={(e) => onPasswordChange(e.target.value)}
/>
<StyledFormControlLabel
isdisplay={isregister?.toString()}
control={
<Checkbox
style={{
color: ' #2f2e41'
}}
/>
<StyledButtonGoogle onClick={() => handleGoogleRedirect()} variant="outlined">
<Search
css={css`
margin-right: 10px;
`}
/>
Kontynuuj przez Google
</StyledButtonGoogle>
<p css={StyledParagraph}>LUB</p>
<StyledForm onSubmit={handleSubmit(onSubmit)} noValidate autoComplete="off">
<Controller
render={(props) => (
<StyledTextField
{...props}
isdisplay={isregister?.toString()}
className="test"
size="small"
id="outlined-basic"
variant="outlined"
placeholder="Nazwa użytkownika/użytkowniczki *"
/>
)}
name="usernameInput"
control={control}
defaultValue=""
rules={{
required: {
value: isregister || false,
message: 'Nazwa użytkownika/czki jest wymagana'
},
minLength: {
value: 2,
message: 'Nazwa użytkownika/czki jest za krótka'
},
maxLength: {
value: 30,
message: 'Nazwa użytkownika/czki jest za długa'
}
}}
/>
{errors.usernameInput && <StyledError>{errors.usernameInput.message}</StyledError>}
<Controller
render={(props) => (
<StyledTextField
{...props}
size="small"
placeholder="Email *"
id="outlined-basic"
variant="outlined"
/>
)}
control={control}
name="emailInput"
defaultValue=""
rules={{
required: {
value: true,
message: 'Email jest wymagany'
},
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,
message: 'Wprowadzony email jest niepoprawny'
}
label="Akceptuję warunki korzystania i politykę prywatności FiszQI"
/>
<StyledButton type="submit" variant="contained">
{isregister ? `ZAREJESTRUJ` : 'ZALOGUJ SIĘ'}
</StyledButton>
</StyledForm>
<StyledLink to={isregister ? '/login' : '/register'}>
{isregister ? `Masz już konto? Zaloguj się` : `Nie masz konta? Zarejestruj się`}
</StyledLink>
</Grid>
}}
/>
{errors.emailInput && <StyledError>{errors.emailInput.message}</StyledError>}
<Controller
render={(props) => (
<StyledTextField
{...props}
size="small"
id="outlined-basic"
variant="outlined"
placeholder="Hasło *"
type="password"
/>
)}
name="passwordInput"
control={control}
rules={{
required: {
value: true,
message: 'Hasło jest wymagane'
},
validate: passwordMatching
}}
defaultValue=""
/>
{errors.passwordInput && <StyledError>{errors.passwordInput.message}</StyledError>}
{errors.passwordInput && errors.passwordInput.type === 'validate' && (
<StyledError>
Hasło powinno składać się z min. 8 znaków zawierać duże i małe litery, liczbę oraz znak
specjalny
</StyledError>
)}
<StyledFormControlLabel
control={
<Controller
defaultValue={false}
name="termsInput"
control={control}
rules={{
required: {
value: isregister || false,
message: 'Akceptacja warunków jest wymagana'
}
}}
render={(props) => (
<Checkbox
{...props}
style={{
color: ' #2f2e41'
}}
/>
)}
/>
}
isdisplay={isregister?.toString()}
label="Akceptuję warunki korzystania i politykę prywatności FiszQI"
/>
{errors.termsInput && <StyledError>{errors.termsInput.message}</StyledError>}
{error?.server && <StyledError>{error?.server.message}</StyledError>}
<StyledButton type="submit" variant="contained">
{isregister ? `ZAREJESTRUJ` : 'ZALOGUJ SIĘ'}
</StyledButton>
</StyledForm>
<StyledLink to={isregister ? '/login' : '/register'}>
{isregister ? `Masz już konto? Zaloguj się` : `Nie masz konta? Zarejestruj się`}
</StyledLink>
</Grid>
</Container>
</>
Expand Down
10 changes: 8 additions & 2 deletions client/src/components/Form/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ interface FormStylesProps {
isdisplay?: string;
}

export const StyledError = styled.div`
width: 90%;
margin-left: 5%;
color: red;
`;

export const StyledTextField = styled(TextField)`
&& {
width: 90%;
Expand All @@ -29,7 +35,7 @@ export const StyledTextField = styled(TextField)`
export const StyledFormControlLabel = styled(FormControlLabel)`
&& {
${(props: FormStylesProps) => (props.isdisplay === 'true' ? '' : 'display: none')};
width: 80%;
width: 90%;
text-align: center;
padding: 5px;
}
Expand Down Expand Up @@ -86,7 +92,7 @@ export const StyledButtonGoogle = styled(Button)`
}
`;

export const orParagraph = css`
export const StyledParagraph = css`
text-transform: uppercase;
margin: 2vh;
font-weight: 700;
Expand Down
20 changes: 15 additions & 5 deletions client/src/views/Login/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import React, { useState } from 'react';
import Form from '../../components/Form/Form';
import axios from 'axios';
import { useForm } from 'react-hook-form';

const Login = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();

const { errors, setError } = useForm();
const handleSubmit = () => {
const user = {
email: email,
password: password
};

axios('/api/register', {
axios('/api/login', {
method: 'POST',
headers: {
'content-type': 'application/json'
Expand All @@ -22,13 +22,23 @@ const Login = () => {
})
.then((response) => (window.location.href = `/`))
.catch((error) => {
setError('server', {
type: 'server',
message: error.response.data.message
});
throw error;
});
};

return (
<>
<Form isregister={false} onEmailChange={setEmail} onPasswordChange={setPassword} onSubmit={handleSubmit} />
<Form
isregister={false}
onEmailChange={setEmail}
onPasswordChange={setPassword}
onSubmit={handleSubmit}
error={errors}
/>
</>
);
};
Expand Down
Loading

0 comments on commit 376bf67

Please sign in to comment.