added server auth and protected routes

This commit is contained in:
kurpfish 2021-08-04 13:04:05 +03:00
parent f42f7a9f71
commit e4ec5fd091
6 changed files with 181 additions and 113 deletions

View File

@ -1,60 +1,40 @@
import React, { Suspense, lazy } from 'react'; import React, { Suspense, lazy } from 'react'
import { HashRouter as Router, Route, Switch } from 'react-router-dom'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import { useSelector } from 'react-redux'; import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap/dist/css/bootstrap.min.css'; import './fonts/stylesheet.css'
import './fonts/stylesheet.css'; import { ProtectedRoute } from './components/ProtectedRoute/ProtectedRoute';
import { selectAuth } from './redux/outstaffingSlice';
const AuthPageForDevelopers = lazy(() => import('./pages/AuthPageForDevelopers')); const AuthPageForDevelopers = lazy(() =>
// const AuthPageForPartners = lazy(() => import('./pages/AuthPageForPartners')); import('./pages/AuthPageForDevelopers')
const HomePage = lazy(() => import('./pages/HomePage')); )
const CandidatePage = lazy(() => import('./pages/CandidatePage')); const AuthPageForPartners = lazy(() => import('./pages/AuthPageForPartners'))
const CalendarPage = lazy(() => import('./pages/CalendarPage')); const HomePage = lazy(() => import('./pages/HomePage'))
const ReportPage = lazy(() => import('./pages/ReportFormPage.js')); const CandidatePage = lazy(() => import('./pages/CandidatePage'))
const FormPage = lazy(() => import('./pages/FormPage.js')); const CalendarPage = lazy(() => import('./pages/CalendarPage'))
const ReportPage = lazy(() => import('./pages/ReportFormPage.js'))
const FormPage = lazy(() => import('./pages/FormPage.js'))
const App = () => { const App = () => {
const isAuth = useSelector(selectAuth);
// const [candidateForCalendar, setCandidateForCalendar] = useState([]);
// const getCandidateForCalendar = (candidate) => {
// console.log('candidate ', candidate);
// setCandidateForCalendar(candidate);
// };
return ( return (
<Router> <Router>
<Suspense fallback={<div>Loading...</div>}> <Suspense fallback={<div>Loading...</div>}>
{isAuth ? (
<Switch> <Switch>
<Route path="/" exact> <Route path='/auth' exact>
<HomePage />
</Route>
<Route path="/candidate/:id">
<CandidatePage />
</Route>
<Route path="/calendar">
<CalendarPage />
</Route>
<Route path="/form">
<FormPage />
</Route>
<Route path="/report">
<ReportPage />
</Route>
<Route>
<div>Not found page</div>
</Route>
</Switch>
) : (
<Route path="/" exact>
{/* <AuthPageForPartners /> */} {/* <AuthPageForPartners /> */}
<AuthPageForDevelopers /> <AuthPageForDevelopers />
</Route> </Route>
)} <ProtectedRoute path='/' exact component={HomePage} />
<ProtectedRoute path='/candidate/:id' component={CandidatePage} />
<ProtectedRoute path='/calendar' component={CalendarPage} />
<ProtectedRoute path='/form' component={FormPage} />
<ProtectedRoute path='/report' component={ReportPage} />
<Route>
<div>Page not found</div>
</Route>
</Switch>
</Suspense> </Suspense>
</Router> </Router>
); )
}; }
export default App; export default App

View File

@ -1,56 +1,83 @@
import React from 'react'; import React, { useState } from 'react'
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux'
import { auth } from '../../redux/outstaffingSlice'; import { auth } from '../../redux/outstaffingSlice'
import style from './AuthForDevelopers.module.css'; import style from './AuthForDevelopers.module.css'
import ellipse from '../../images/ellipse.png'; import ellipse from '../../images/ellipse.png'
import arrow from '../../images/arrow__login_page.png'; import arrow from '../../images/arrow__login_page.png'
import authImg from '../../images/auth_img.png'; import authImg from '../../images/auth_img.png'
import cross from '../../images/cross.png'; import cross from '../../images/cross.png'
import text from '../../images/Body_Text.png'; import text from '../../images/Body_Text.png'
import align from '../../images/align-left.png'; import align from '../../images/align-left.png'
import phone from '../../images/phone.png'; import phone from '../../images/phone.png'
import telegram from '../../images/telegram.png'; import telegram from '../../images/telegram.png'
import vector from '../../images/Vector_Smart_Object.png'; import vector from '../../images/Vector_Smart_Object.png'
import vectorBlack from '../../images/Vector_Smart_Object_black.png'; import vectorBlack from '../../images/Vector_Smart_Object_black.png'
import { fetchAuth } from '../../server/server'
const AuthForDevelopers = () => { const AuthForDevelopers = () => {
const dispatch = useDispatch(); const dispatch = useDispatch()
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
return ( return (
<section className={style.developers}> <section className={style.developers}>
<div className={style.developers__background}> <div className={style.developers__background}>
<img className={style.vector} src={vector} alt="" /> <img className={style.vector} src={vector} alt='' />
<img className={style.vectorBlack} src={vectorBlack} alt="" /> <img className={style.vectorBlack} src={vectorBlack} alt='' />
<div className="container"> <div className='container'>
<div className="row"> <div className='row'>
<div className="col-12 col-xl-6"> <div className='col-12 col-xl-6'>
<div className={style.developers__box}> <div className={style.developers__box}>
<h2 className={style.developers__title}> <h2 className={style.developers__title}>
Войти в <span>систему</span> Войти в <span>систему</span>
</h2> </h2>
<div className={style.developers__partners}> <div className={style.developers__partners}>
<img src={ellipse} alt="" /> <img src={ellipse} alt='' />
<span>Для разработчиков</span> <span>Для разработчиков</span>
</div> </div>
<form className={style.developers__form}> <form className={style.developers__form}>
<label htmlFor="login">Ваш логин:</label> <label htmlFor='login'>Ваш логин:</label>
<input id="login" type="text" placeholder="Логин" /> <input
id='login'
type='text'
placeholder='Логин'
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<label htmlFor="password">Пароль:</label> <label htmlFor='password'>Пароль:</label>
<input id="password" type="password" placeholder="Пароль" /> <input
id='password'
type='password'
placeholder='Пароль'
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button className={style.form__btn} type="submit" onClick={() => dispatch(auth(true))}> <button
className={style.form__btn}
type='submit'
onClick={() =>
fetchAuth({
username,
password,
dispatch: ()=> dispatch(auth(true))
})
}
>
Войти Войти
</button> </button>
</form> </form>
</div> </div>
</div> </div>
<div className="col-xl-2"> <div className='col-xl-2'>
<img className={style.developers__arrow} src={arrow} alt="" /> <img className={style.developers__arrow} src={arrow} alt='' />
</div> </div>
<div className="col-12 col-xl-4"> <div className='col-12 col-xl-4'>
<div className={style.developers__info}> <div className={style.developers__info}>
<div className={style.developers__info__box}> <div className={style.developers__info__box}>
<img src={authImg} alt="" /> <img src={authImg} alt='' />
<h3> <h3>
Управление Управление
<br /> командой <br /> командой
@ -60,7 +87,7 @@ const AuthForDevelopers = () => {
<div className={style.developers__info__container}> <div className={style.developers__info__container}>
<div className={style.developers__info__img}> <div className={style.developers__info__img}>
<div> <div>
<img className="cross" src={cross} alt="" /> <img className='cross' src={cross} alt='' />
</div> </div>
<div> <div>
{/* <img className={style.specialists} src={specialists} alt="" /> */} {/* <img className={style.specialists} src={specialists} alt="" /> */}
@ -69,39 +96,44 @@ const AuthForDevelopers = () => {
</div> </div>
<ul className={style.info__list}> <ul className={style.info__list}>
<li className={style.info__list__item}>Рабочее пространство</li> <li className={style.info__list__item}>
<li className={style.info__list__item}>Управление задачами</li> Рабочее пространство
</li>
<li className={style.info__list__item}>
Управление задачами
</li>
</ul> </ul>
</div> </div>
<img className={style.img__text} src={text} alt="" /> <img className={style.img__text} src={text} alt='' />
</div> </div>
</div> </div>
</div> </div>
<div className="row"> <div className='row'>
<div className="col-12 col-xl-7"> <div className='col-12 col-xl-7'>
<div className={style.developers__footer__left}> <div className={style.developers__footer__left}>
<div className={style.footer__left__img}> <div className={style.footer__left__img}>
<img src={align} alt="" /> <img src={align} alt='' />
</div> </div>
<div className={style.footer__left__sp}> <div className={style.footer__left__sp}>
<span> <span>
© Адвего биржа контента 1. Копирайтинг, рерайтинг, переводы, работа на дому: поставщик © Адвего биржа контента 1. Копирайтинг, рерайтинг,
уникального контента. 2021{' '} переводы, работа на дому: поставщик уникального контента.
2021{' '}
</span> </span>
</div> </div>
</div> </div>
</div> </div>
<div className="col-4 col-xl-2"> <div className='col-4 col-xl-2'>
<div className={style.developers__footer__icon}> <div className={style.developers__footer__icon}>
<img src={phone} alt="" /> <img src={phone} alt='' />
<img src={telegram} alt="" /> <img src={telegram} alt='' />
</div> </div>
</div> </div>
<div className="col-8 col-xl-3"> <div className='col-8 col-xl-3'>
<div className={style.developers__footer__right}> <div className={style.developers__footer__right}>
<p className={style.phone}>+7 495 156 78 98</p> <p className={style.phone}>+7 495 156 78 98</p>
<p className={style.workingHours}>Будни с 9:00 до 21:00</p> <p className={style.workingHours}>Будни с 9:00 до 21:00</p>
@ -111,7 +143,7 @@ const AuthForDevelopers = () => {
</div> </div>
</div> </div>
</section> </section>
); )
}; }
export default AuthForDevelopers; export default AuthForDevelopers

View File

@ -19,7 +19,7 @@ const Calendar = () => {
const { name, skillsName } = candidateForCalendar; const { name, skillsName } = candidateForCalendar;
const abbreviatedName = name.substring(0, name.lastIndexOf(' ')); const abbreviatedName = name && name.substring(0, name.lastIndexOf(' '));
return ( return (
<section className={style.calendar}> <section className={style.calendar}>

View File

@ -0,0 +1,23 @@
import React from 'react';
import { useSelector } from 'react-redux'
import { Route, Redirect } from 'react-router-dom';
import { selectAuth } from '../../redux/outstaffingSlice';
export const ProtectedRoute = ({ component: Component, ...rest }) => {
const isAuth = useSelector(selectAuth)
const existingToken = localStorage.getItem('auth_token')
const expiresAt = localStorage.getItem('access_token_expired_at')
const isTokenAlive = (existingToken && expiresAt && new Date(expiresAt).getTime() > (new Date()).getTime());
return (
<Route
{...rest}
render={props =>
( isAuth || isTokenAlive) ? (
<Component {...props} />
) : <Redirect to='/auth' />
}
/>
);
}

View File

@ -6,7 +6,7 @@ const initialState = {
filteredCandidates: [], filteredCandidates: [],
selectedItems: [], selectedItems: [],
currentCandidate: {}, currentCandidate: {},
auth: true, auth: false,
}; };
export const outstaffingSlice = createSlice({ export const outstaffingSlice = createSlice({

View File

@ -1,40 +1,73 @@
export const fetchProfile = async (link, index) => { export const fetchProfile = async (link, index) => {
try { try {
const response = await fetch(`${link}${index}`); const response = await fetch(`${link}${index}`)
let data = await response.json(); let data = await response.json()
return data; return data
} catch (error) {} } catch (error) {}
}; }
export const fetchSkills = async (link) => { export const fetchSkills = async (link) => {
try { try {
const response = await fetch(link); const response = await fetch(link)
let data = await response.json(); let data = await response.json()
return data; return data
} catch (error) {} } catch (error) {}
}; }
export const fetchItemsForId = async (link, id) => { export const fetchItemsForId = async (link, id) => {
try { try {
const response = await fetch(`${link}${id}`); const response = await fetch(`${link}${id}`)
let data = await response.json(); let data = await response.json()
return data; return data
} catch (error) {} } catch (error) {}
}; }
export const fetchForm = async (link, info) => { export const fetchForm = async (link, info) => {
try { try {
const response = await fetch(link, { const response = await fetch(link, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'multipart/form-data', 'Content-Type': 'multipart/form-data'
}, },
body: info, body: info
}); })
return response; return response
} catch (error) {} } catch (error) {}
}; }
export const fetchAuth = async ({ username, password, dispatch }) => {
try {
const response = await fetch(
'https://guild.craft-group.xyz/api/user/login',
{
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username,
password
})
}
)
if(!response.ok) {
return response.statusText;
}
response
.json()
.then((resJSON) => {
localStorage.setItem('auth_token', resJSON.access_token)
localStorage.setItem('access_token_expired_at', resJSON.access_token_expired_at)
dispatch();
})
} catch (error) {
console.error('Error occured: ', error)
}
}