Skip to content

Commit

Permalink
add check on inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
ZiyedB committed Feb 16, 2021
1 parent 34f5931 commit e116fc7
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 49 deletions.
44 changes: 44 additions & 0 deletions package-lock.json

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

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@hookform/resolvers": "^1.3.4",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
Expand All @@ -13,13 +14,15 @@
"node-sass": "^4.14.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-hook-form": "^6.15.1",
"react-icons": "^4.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.1",
"semantic-ui-css": "^2.4.1",
"semantic-ui-react": "^2.0.3",
"typescript": "^4.1.3",
"web-vitals": "^0.2.4"
"web-vitals": "^0.2.4",
"yup": "^0.32.8"
},
"scripts": {
"start": "react-scripts start",
Expand Down
5 changes: 2 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import { ProtectedRoute } from './shared/ProtectedRoute';

function App(): JSX.Element {
// Handle user state
// Ask if we should have this instead directly in a utils instead
const [isLoggedIn, setLoggedIn] = useState(false);
const accessToken = localStorage.getItem(storageNames.user) || '';
const [isLoggedIn, setLoggedIn] = useState(!!accessToken);

// Handle user login by setting the storage and state
const login = (token: string): void => {
Expand All @@ -26,7 +26,6 @@ function App(): JSX.Element {
localStorage.removeItem(storageNames.user);
};

// TODO: still need to handle the first time getting to site ( if token still valid, present etc. )
return (
<UserContext.Provider value={{ isLoggedIn, login, logout }}>
<Router>
Expand Down
2 changes: 1 addition & 1 deletion src/components/layouts/NavigationBar/NavigationBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const NavigationBar = (): JSX.Element => {
{userContext.isLoggedIn ? (
<div className="navigation-bar__user">
{/* TODO: Need to have this as a small menu showing up */}
<a className="navigation-bar__link navigation-bar__user-link" onClick={logout} href="/">
<a className="navigation-bar__link navigation-bar__user-link" onClick={logout} href="/login">
<FaUserCircle />
</a>
</div>
Expand Down
11 changes: 11 additions & 0 deletions src/pages/Login/Login.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
$elevation-card: 0 0 1px 0 rgba(8, 11, 14, 0.6), 0 16px 16px -1px rgba(8, 11, 14, 0.1);
$color-secondary: #e1e4e8;
$error-color: red;

.login {
&__card {
Expand Down Expand Up @@ -34,6 +35,16 @@ $color-secondary: #e1e4e8;
width: 100%;
outline: none;
padding: 0 15px;

&--error {
border-color: $error-color;
}
}

&__input-error-msg {
font-size: 12px;
margin-left: 15px;
color: $error-color;
}

&__input-icon {
Expand Down
109 changes: 66 additions & 43 deletions src/pages/Login/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { yupResolver } from '@hookform/resolvers/yup';
import React, { useContext } from 'react';
import { useForm } from 'react-hook-form';
import { FaEnvelope, FaEye, FaEyeSlash } from 'react-icons/fa';
import { Redirect, RouteComponentProps } from 'react-router-dom';
import * as yup from 'yup';
import UserContext from '../../hooks/UserContext';
import paralinkApi from '../../services/interceptor';
import './Login.scss';
Expand All @@ -9,24 +12,36 @@ interface LoginProps {
from: string;
}

type LoginFormData = {
email: string;
password: string;
};

const loginSchema = yup.object().shape({
email: yup.string().email().required(),
password: yup.string().required(), // We could define rules here for password if there are
});

const Login = (props: RouteComponentProps<{}, {}, LoginProps>): JSX.Element => {
const userContext = useContext(UserContext);
const { register, handleSubmit, errors } = useForm<LoginFormData>({ resolver: yupResolver(loginSchema) });

const [state, setState] = React.useState({
email: '',
password: '',
// email: '',
// password: '',
seePassword: false,
});

const { from } = props.location.state || { from: { pathname: '/' } };

const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
const { id, value } = e.target;
setState((prevState) => ({
...prevState,
[id]: value,
}));
};
// const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
// const { id, value } = e.target;
// setState((prevState) => ({
// ...prevState,
// [id]: value,
// }));
// console.log('errors', errors);
// };

const togglePassword = (): void => {
setState((prevState) => ({
Expand All @@ -35,11 +50,14 @@ const Login = (props: RouteComponentProps<{}, {}, LoginProps>): JSX.Element => {
}));
};

const login = async (): Promise<any> => {
const login = async (data: LoginFormData): Promise<any> => {
// Avoid the page to refresh from submitting the form
// event.preventDefault();
// TODO: put like a loading icon on the login button

// TODO: do like a safe check on the email & password here

console.log('data', data);
// Just to check
await paralinkApi
// For now this is going to be the placeholder
Expand All @@ -66,41 +84,46 @@ const Login = (props: RouteComponentProps<{}, {}, LoginProps>): JSX.Element => {
return (
<div className="login__card">
<div className="login__title">Login into your account</div>
<div className="login__input-container">
<input
type="email"
className="login__email login__input"
id="email"
aria-describedby="emailHelp"
placeholder="[email protected]"
value={state.email}
onChange={handleChange}
/>
<div className="login__input-icon">
<FaEnvelope className="login__email-icon" />
<form onSubmit={handleSubmit(login)}>
<div className="login__input-container">
<input
type="email"
className={`login__email login__input ${errors.email?.message ? 'login__input--error' : ''}`}
ref={register({ required: true })}
id="email"
aria-describedby="emailHelp"
placeholder="[email protected]"
name="email"
/>
<div className="login__input-icon">
<FaEnvelope className="login__email-icon" />
</div>
</div>
{errors.email?.message ? <span className="login__input-error-msg">{errors.email?.message}</span> : ''}

<div className="login__input-container">
<input
type={state.seePassword ? 'text' : 'password'}
className={`login__password login__input ${errors.email?.message ? 'login__input--error' : ''}`}
ref={register({ required: true })}
id="password"
placeholder="Password"
name="password"
/>

<button className="login__input-icon" type="button" onClick={togglePassword}>
{state.seePassword ? (
<FaEyeSlash className="login__password-icon" />
) : (
<FaEye className="login__password-icon" />
)}
</button>
</div>
</div>
<div className="login__input-container">
<input
type={state.seePassword ? 'text' : 'password'}
className="login__password login__input"
id="password"
placeholder="Password"
value={state.password}
onChange={handleChange}
/>

<button className="login__input-icon" type="button" onClick={togglePassword}>
{state.seePassword ? (
<FaEyeSlash className="login__password-icon" />
) : (
<FaEye className="login__password-icon" />
)}
{errors.password?.message ? <span className="login__input-error-msg">{errors.password?.message}</span> : ''}
<button className="login__button" type="submit">
Login
</button>
</div>
<button className="login__button" type="submit" onClick={login}>
Login
</button>
</form>
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/services/interceptor/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const paralinkApi = axios.create({

paralinkApi.interceptors.request.use(
(config: any) => {
// Check for user token
// Check for user token, we can't use hooks from here
const accessToken = localStorage.getItem(storageNames.user);

// If user not logged we just pass it through, the backend should not accept it
Expand Down

0 comments on commit e116fc7

Please sign in to comment.