Auth route and login form. Client error handler

This commit is contained in:
Paweł Malak
2021-10-19 16:41:30 +02:00
parent 4da15ff105
commit 63bed57c28
10 changed files with 148 additions and 3 deletions

View File

@@ -0,0 +1,88 @@
import { ChangeEvent, FormEvent, useState, useContext, Fragment } from 'react';
import { AuthContext } from '../../store';
import { Button } from '../UI';
export const AuthForm = (): JSX.Element => {
const [isInLogin, setIsInLogin] = useState(true);
const [formData, setFormData] = useState({ email: '', password: '' });
const { login } = useContext(AuthContext);
const inputHandler = (e: ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData({
...formData,
[name]: value
});
};
const formHandler = (e: FormEvent) => {
e.preventDefault();
if (isInLogin) {
login(formData);
} else {
// register
}
};
return (
<Fragment>
<h5 className='card-title'>{isInLogin ? 'Login' : 'Register'}</h5>
<p className=''>
{isInLogin ? "Don't have an account yet?" : 'Already a user?'}
<span
onClick={() => setIsInLogin(!isInLogin)}
className='text-success cursor-pointer'
>
{isInLogin ? ' Sign Up' : ' Login'}
</span>
</p>
<hr />
<form onSubmit={e => formHandler(e)}>
<div className='mb-3'>
<label htmlFor='email' className='form-label'>
Email
</label>
<input
type='email'
className='form-control'
id='email'
name='email'
placeholder='john@doe.com'
required
autoComplete='email'
value={formData.email}
onChange={e => inputHandler(e)}
/>
</div>
<div className='mb-3'>
<label htmlFor='password' className='form-label'>
Password
</label>
<input
type='password'
className='form-control'
id='password'
name='password'
placeholder='••••••'
required
autoComplete='current-password'
value={formData.password}
onChange={e => inputHandler(e)}
/>
</div>
<hr />
<div className='d-grid gap-2'>
<Button
text={isInLogin ? 'Login' : 'Register'}
color='secondary'
type='submit'
outline
/>
</div>
</form>
</Fragment>
);
};

View File

@@ -0,0 +1 @@
export * from './AuthForm';

View File

@@ -14,6 +14,11 @@
"name": "Editor", "name": "Editor",
"dest": "/editor", "dest": "/editor",
"isPublic": false "isPublic": false
},
{
"name": "Auth",
"dest": "/auth",
"isPublic": true
} }
] ]
} }

View File

@@ -0,0 +1,14 @@
import { AuthForm } from '../components/Auth';
import { Card, Layout } from '../components/UI';
export const Auth = (): JSX.Element => {
return (
<Layout>
<div className='col-12 col-md-6 mx-auto'>
<Card>
<AuthForm />
</Card>
</div>
</Layout>
);
};

View File

@@ -2,3 +2,4 @@ export * from './Home';
export * from './Snippet'; export * from './Snippet';
export * from './Snippets'; export * from './Snippets';
export * from './Editor'; export * from './Editor';
export * from './Auth';

View File

@@ -1,6 +1,8 @@
import { useState, createContext, ReactNode } from 'react'; import axios from 'axios';
import { createContext, ReactNode } from 'react';
import { AuthContext as Context } from '../typescript/interfaces'; import { AuthContext as Context, Response } from '../typescript/interfaces';
import { errorHandler } from '../utils';
export const AuthContext = createContext<Context>({ export const AuthContext = createContext<Context>({
isAuthenticated: false, isAuthenticated: false,
@@ -13,7 +15,19 @@ interface Props {
export const AuthContextProvider = (props: Props): JSX.Element => { export const AuthContextProvider = (props: Props): JSX.Element => {
const login = async (formData: { email: string; password: string }) => { const login = async (formData: { email: string; password: string }) => {
console.table(formData); try {
const res = await axios.post<Response<{ token: string }>>(
'/api/auth/login',
formData
);
localStorage.setItem('token', res.data.data.token);
// get profile
// redirect to snippets? / home?
} catch (err) {
errorHandler(err);
}
}; };
const context: Context = { const context: Context = {

View File

@@ -0,0 +1,5 @@
import { Model } from '.';
export interface User extends Model {
email: string;
}

View File

@@ -5,3 +5,4 @@ export * from './Response';
export * from './Context'; export * from './Context';
export * from './Statistics'; export * from './Statistics';
export * from './SearchQuery'; export * from './SearchQuery';
export * from './User';

View File

@@ -0,0 +1,15 @@
import { AxiosError } from 'axios';
export const errorHandler = (err: any) => {
const error = err as AxiosError<{ error: string }>;
let msg: string;
if (error.response) {
msg = error.response.data.error;
} else {
msg = 'Something went wrong';
}
console.log(msg);
};

View File

@@ -3,3 +3,4 @@ export * from './badgeColor';
export * from './findLanguage'; export * from './findLanguage';
export * from './searchParser'; export * from './searchParser';
export * from './ProtectedRoute'; export * from './ProtectedRoute';
export * from './errorHandler';