added server auth and protected routes
This commit is contained in:
parent
f42f7a9f71
commit
e4ec5fd091
74
src/App.js
74
src/App.js
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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}>
|
||||||
|
23
src/components/ProtectedRoute/ProtectedRoute.js
Normal file
23
src/components/ProtectedRoute/ProtectedRoute.js
Normal 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' />
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -6,7 +6,7 @@ const initialState = {
|
|||||||
filteredCandidates: [],
|
filteredCandidates: [],
|
||||||
selectedItems: [],
|
selectedItems: [],
|
||||||
currentCandidate: {},
|
currentCandidate: {},
|
||||||
auth: true,
|
auth: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const outstaffingSlice = createSlice({
|
export const outstaffingSlice = createSlice({
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user