Merge pull request #33 from apuc/authentication

logout fixes with role redirect
This commit is contained in:
kavalar 2021-08-20 18:02:54 +03:00 committed by GitHub
commit 5b0c1a17f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 89 additions and 29 deletions

View File

@ -14,6 +14,7 @@ import { fetchAuth } from '../../server/server'
import { selectAuth } from '../../redux/outstaffingSlice'; import { selectAuth } from '../../redux/outstaffingSlice';
import { selectIsLoading } from '../../redux/loaderSlice'; import { selectIsLoading } from '../../redux/loaderSlice';
import { setRole } from '../../redux/roleSlice';
import { Redirect, Link } from 'react-router-dom'; import { Redirect, Link } from 'react-router-dom';
import { Loader } from '../Loader/Loader' import { Loader } from '../Loader/Loader'
@ -71,8 +72,6 @@ const AuthForDevelopers = () => {
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
/> />
{ error && <div className={style.form__error}> { error && <div className={style.form__error}>
<SweetAlert <SweetAlert
show={!!error} show={!!error}
@ -94,6 +93,7 @@ const AuthForDevelopers = () => {
dispatch: ()=> { dispatch: ()=> {
dispatch(auth(true)) dispatch(auth(true))
dispatch(loading(false)) dispatch(loading(false))
dispatch(setRole('ROLE_DEV'))
}, },
catchError: () => { catchError: () => {
setError('Некорректные данные для входа') setError('Некорректные данные для входа')

View File

@ -18,6 +18,7 @@ import { fetchAuth } from '../../server/server'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
import { selectAuth } from '../../redux/outstaffingSlice'; import { selectAuth } from '../../redux/outstaffingSlice';
import { selectIsLoading } from '../../redux/loaderSlice'; import { selectIsLoading } from '../../redux/loaderSlice';
import { setRole } from '../../redux/roleSlice';
import { Redirect, Link } from 'react-router-dom'; import { Redirect, Link } from 'react-router-dom';
import { Loader } from '../Loader/Loader' import { Loader } from '../Loader/Loader'
@ -90,6 +91,7 @@ const AuthForPartners = () => {
dispatch: ()=> { dispatch: ()=> {
dispatch(auth(true)) dispatch(auth(true))
dispatch(loading(false)) dispatch(loading(false))
dispatch(setRole('ROLE_PARTNER'))
}, },
catchError: () => { catchError: () => {
setError('Некорректные данные для входа') setError('Некорректные данные для входа')

View File

@ -13,18 +13,20 @@ import { fetchItemsForId } from '../../server/server';
import { Footer } from '../Footer/Footer'; import { Footer } from '../Footer/Footer';
import './candidate.css'; import './candidate.css';
import { getRole } from '../../redux/roleSlice';
const Candidate = () => { const Candidate = () => {
const history = useHistory(); const history = useHistory();
const { id: candidateId } = useParams(); const { id: candidateId } = useParams();
const dispatch = useDispatch(); const dispatch = useDispatch();
const role = useSelector(getRole);
useEffect(() => { useEffect(() => {
window.scrollTo(0, 0) window.scrollTo(0, 0)
}, []) }, [])
useEffect(() => { useEffect(() => {
fetchItemsForId(`${process.env.REACT_APP_API_URL}/api/profile/`, Number(candidateId)).then((el) => fetchItemsForId({ link: `${process.env.REACT_APP_API_URL}/api/profile/`, index:Number(candidateId), history, role }).then((el) =>
dispatch(currentCandidate(el)) dispatch(currentCandidate(el))
); );
}, [dispatch, candidateId]); }, [dispatch, candidateId]);

View File

@ -2,21 +2,24 @@ import React, { useEffect, useState } from 'react';
import style from './Description.module.css'; import style from './Description.module.css';
import male from '../../images/medium_male.png'; import male from '../../images/medium_male.png';
import rectangle from '../../images/rectangle_secondPage.png'; import rectangle from '../../images/rectangle_secondPage.png';
import { Link } from 'react-router-dom'; import { Link, useHistory } from 'react-router-dom';
import { LEVELS, SKILLS } from '../constants/constants'; import { LEVELS, SKILLS } from '../constants/constants';
import { selectProfiles, selectFilteredCandidates, selectItems } from '../../redux/outstaffingSlice'; import { selectProfiles, selectFilteredCandidates, selectItems } from '../../redux/outstaffingSlice';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { fetchProfile } from '../../server/server'; import { fetchProfile } from '../../server/server';
import { Loader } from '../Loader/Loader'; import { Loader } from '../Loader/Loader';
import { getRole } from '../../redux/roleSlice';
const Description = ({ onLoadMore, isLoadingMore }) => { const Description = ({ onLoadMore, isLoadingMore }) => {
const history = useHistory();
const role = useSelector(getRole)
const candidatesListArr = useSelector(selectProfiles); const candidatesListArr = useSelector(selectProfiles);
const itemsArr = useSelector(selectItems); const itemsArr = useSelector(selectItems);
const filteredListArr = useSelector(selectFilteredCandidates); const filteredListArr = useSelector(selectFilteredCandidates);
const [allCandidates, getAllCandidates] = useState([]); const [allCandidates, getAllCandidates] = useState([]);
useEffect(() => { useEffect(() => {
fetchProfile(`${process.env.REACT_APP_API_URL}/api/profile?limit=`, 1000).then((p) => getAllCandidates(p)); fetchProfile({ link: `${process.env.REACT_APP_API_URL}/api/profile?limit=`, index: 1000, history, role }).then((p) => getAllCandidates(p));
}, []); }, []);
if(!filteredListArr) { if(!filteredListArr) {

View File

@ -8,10 +8,14 @@ import './form.css';
import { withSwalInstance } from 'sweetalert2-react'; import { withSwalInstance } from 'sweetalert2-react';
import swal from 'sweetalert2'; import swal from 'sweetalert2';
import { useSelector } from 'react-redux';
import { getRole } from '../../redux/roleSlice';
const SweetAlert = withSwalInstance(swal); const SweetAlert = withSwalInstance(swal);
const Form = () => { const Form = () => {
const history = useHistory();
const role = useSelector(getRole);
const urlParams = useParams(); const urlParams = useParams();
const [status, setStatus] = useState(null); const [status, setStatus] = useState(null);
const [data, setData] = useState({ const [data, setData] = useState({
@ -20,8 +24,6 @@ const Form = () => {
comment: '', comment: '',
}); });
const history = useHistory();
const handleChange = (e) => { const handleChange = (e) => {
const { id, value } = e.target; const { id, value } = e.target;
@ -40,10 +42,10 @@ const Form = () => {
formData.append('phone', data.phone); formData.append('phone', data.phone);
formData.append('comment', data.comment); formData.append('comment', data.comment);
fetchForm(`${process.env.REACT_APP_API_URL}/api/profile/add-to-interview`, { fetchForm({ link: `${process.env.REACT_APP_API_URL}/api/profile/add-to-interview`, index: {
profile_id: urlParams.id, profile_id: urlParams.id,
...data, ...data,
}).then( (res)=> res.json() }, history, role }).then( (res)=> res.json()
.then( resJSON => setStatus(resJSON)) .then( resJSON => setStatus(resJSON))
) )
}; };

View File

@ -1,25 +1,29 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useDispatch } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import Outstaffing from '../Outstaffing/Outstaffing'; import Outstaffing from '../Outstaffing/Outstaffing';
import Description from '../Description/Description'; import Description from '../Description/Description';
import { fetchProfile, fetchSkills } from '../../server/server'; import { fetchProfile, fetchSkills } from '../../server/server';
import { profiles, tags } from '../../redux/outstaffingSlice'; import { profiles, tags } from '../../redux/outstaffingSlice';
import { getRole } from '../../redux/roleSlice';
import { Footer } from '../Footer/Footer'; import { Footer } from '../Footer/Footer';
import { useHistory } from 'react-router-dom';
const Home = () => { const Home = () => {
const history = useHistory()
const [isLoadingMore, setIsLoadingMore] = useState(false); const [isLoadingMore, setIsLoadingMore] = useState(false);
const [index, setIndex] = useState(4); const [index, setIndex] = useState(4);
const dispatch = useDispatch(); const dispatch = useDispatch();
const role = useSelector(getRole)
useEffect(() => { useEffect(() => {
setIsLoadingMore(true); setIsLoadingMore(true);
fetchProfile(`${process.env.REACT_APP_API_URL}/api/profile?limit=`, index).then((profileArr) => { fetchProfile({ link:`${process.env.REACT_APP_API_URL}/api/profile?limit=`, index, history, role}).then((profileArr) => {
dispatch(profiles(profileArr)); dispatch(profiles(profileArr));
setIsLoadingMore(false); setIsLoadingMore(false);
}); });
fetchSkills(`${process.env.REACT_APP_API_URL}/api/skills/skills-on-main-page`).then((skills) => { fetchSkills({ link: `${process.env.REACT_APP_API_URL}/api/skills/skills-on-main-page`, history, role}).then((skills) => {
const keys = Object.keys(skills); const keys = Object.keys(skills);
const values = Object.values(skills); const values = Object.values(skills);

View File

@ -1,16 +1,28 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useDispatch } from 'react-redux'; import { useHistory } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { Loader } from '../Loader/Loader'; import { Loader } from '../Loader/Loader';
import { auth } from '../../redux/outstaffingSlice'; import { auth } from '../../redux/outstaffingSlice';
import { getRole } from '../../redux/roleSlice';
import './logoutButton.css' import './logoutButton.css'
export const LogoutButton = () => { export const LogoutButton = () => {
const [isLoggingOut, setIsLoggingOut] = useState(false); const [isLoggingOut, setIsLoggingOut] = useState(false);
const dispatch = useDispatch(); const dispatch = useDispatch();
const userRole = useSelector(getRole);
const history = useHistory();
return ( return (
<div className='logout-button'> <div className='logout-button'>
<button onClick={()=>{setIsLoggingOut(true); localStorage.clear(); dispatch(auth(false)); setIsLoggingOut(false); }}> <button onClick={()=>{
setIsLoggingOut(true);
localStorage.clear();
dispatch(auth(false));
setIsLoggingOut(false);
history.push(userRole === 'ROLE_DEV' ? '/authdev' : '/auth')
}}>
{ {
isLoggingOut ? <Loader /> : 'Выйти' isLoggingOut ? <Loader /> : 'Выйти'
} </button> } </button>

View File

@ -6,18 +6,19 @@ import { fetchItemsForId } from '../../server/server';
import style from './Outstaffing.module.css'; import style from './Outstaffing.module.css';
import { fetchProfile } from '../../server/server'; import { fetchProfile } from '../../server/server';
import { useHistory } from 'react-router-dom';
import { getRole } from '../../redux/roleSlice';
const handlePositionClick = ({dispatch, positionId, isSelected, onSelect}) => { const handlePositionClick = ({dispatch, positionId, isSelected, onSelect, history, role}) => {
if(isSelected) { if(isSelected) {
fetchProfile(`${process.env.REACT_APP_API_URL}/api/profile?limit=`, 4).then((profileArr) => { fetchProfile({ link: `${process.env.REACT_APP_API_URL}/api/profile?limit=`, index: 4, history, role }).then((profileArr) => {
dispatch(filteredCandidates(profileArr)); dispatch(filteredCandidates(profileArr));
dispatch(selectedItems([])); dispatch(selectedItems([]));
onSelect(positionId); onSelect(positionId);
} }
); );
} else { } else {
fetchItemsForId(`${process.env.REACT_APP_API_URL}/api/profile?position_id=`, positionId).then((el) => { fetchItemsForId({ link: `${process.env.REACT_APP_API_URL}/api/profile?position_id=`, index: positionId, history, role, }).then((el) => {
dispatch(filteredCandidates(el)); dispatch(filteredCandidates(el));
dispatch(selectedItems([])); dispatch(selectedItems([]));
onSelect(positionId); onSelect(positionId);
@ -27,6 +28,8 @@ const handlePositionClick = ({dispatch, positionId, isSelected, onSelect}) => {
}; };
const OutstaffingBlock = ({ dataTags = [], selected, img, header, positionId, isSelected, onSelect }) => { const OutstaffingBlock = ({ dataTags = [], selected, img, header, positionId, isSelected, onSelect }) => {
const history = useHistory();
const role = useSelector(getRole);
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -57,7 +60,7 @@ const OutstaffingBlock = ({ dataTags = [], selected, img, header, positionId, is
}} }}
> >
<div className={`${style.outstaffing__box} ${isSelected?style.outstaffing__box__selected:''}`} > <div className={`${style.outstaffing__box} ${isSelected?style.outstaffing__box__selected:''}`} >
<div className={`${style.outstaffing__box__img} ${selected ? style.border : ''}`} onClick={()=>handlePositionClick({dispatch, positionId, isSelected, onSelect})}> <div className={`${style.outstaffing__box__img} ${selected ? style.border : ''}`} onClick={()=>handlePositionClick({dispatch, positionId, isSelected, onSelect, history, role})}>
<h3>{header}</h3> <h3>{header}</h3>
<img className={classes} src={img} alt="img" /> <img className={classes} src={img} alt="img" />
</div> </div>

View File

@ -5,8 +5,12 @@ import { Loader } from '../Loader/Loader';
import style from './TagSelect.module.css'; import style from './TagSelect.module.css';
import { selectedItems, selectItems, selectTags, filteredCandidates, setPositionId } from '../../redux/outstaffingSlice'; import { selectedItems, selectItems, selectTags, filteredCandidates, setPositionId } from '../../redux/outstaffingSlice';
import { fetchItemsForId } from '../../server/server'; import { fetchItemsForId } from '../../server/server';
import { useHistory } from 'react-router-dom';
import { getRole } from '../../redux/roleSlice';
const TagSelect = () => { const TagSelect = () => {
const history = useHistory;
const role = useSelector(getRole);
const [searchLoading, setSearchLoading] = useState(false); const [searchLoading, setSearchLoading] = useState(false);
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -20,7 +24,7 @@ const TagSelect = () => {
dispatch(setPositionId(null)); dispatch(setPositionId(null));
const filterItemsId = itemsArr.map((item) => item.id).join(); const filterItemsId = itemsArr.map((item) => item.id).join();
fetchItemsForId(`${process.env.REACT_APP_API_URL}/api/profile?skills=`, filterItemsId).then((el) => { fetchItemsForId({ link: `${process.env.REACT_APP_API_URL}/api/profile?skills=`, index: filterItemsId, history, role, }).then((el) => {
dispatch(filteredCandidates(el)) dispatch(filteredCandidates(el))
setSearchLoading(false) setSearchLoading(false)
}); });

View File

@ -84,7 +84,6 @@
} }
@media (max-width: 575.98px) { @media (max-width: 575.98px) {
.candidateSidebar__info__btn,
.candidateSidebar__info__l, .candidateSidebar__info__l,
.candidateSidebar__arrows { .candidateSidebar__arrows {
display: none; display: none;

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { useHistory, useParams, } from 'react-router-dom'; import { useHistory, useParams, Link } from 'react-router-dom';
import { currentCandidate, selectCurrentCandidate } from '../redux/outstaffingSlice'; import { currentCandidate, selectCurrentCandidate } from '../redux/outstaffingSlice';
import SVG from 'react-inlinesvg'; import SVG from 'react-inlinesvg';
import { WithLogout } from '../hoc/withLogout'; import { WithLogout } from '../hoc/withLogout';
@ -14,6 +14,7 @@ import rectangle from '../images/rectangle_secondPage.png';
import telegramIcon from '../images/telegram-icon.svg'; import telegramIcon from '../images/telegram-icon.svg';
import './formPage.scss'; import './formPage.scss';
import { getRole } from '../redux/roleSlice';
const goBack = (history) => { const goBack = (history) => {
history.goBack(); history.goBack();
@ -23,10 +24,11 @@ const FormPage = () => {
const params = useParams(); const params = useParams();
const history = useHistory(); const history = useHistory();
const dispatch = useDispatch(); const dispatch = useDispatch();
const candidate = useSelector(selectCurrentCandidate) const candidate = useSelector(selectCurrentCandidate);
const role = useSelector(getRole);
if(!candidate.id) { if(!candidate.id) {
fetchItemsForId(`${process.env.REACT_APP_API_URL}/api/profile/`, Number(params.id)).then((el) => fetchItemsForId({ link: `${process.env.REACT_APP_API_URL}/api/profile/`, index: Number(params.id), history, role, }).then((el) =>
dispatch(currentCandidate(el)) dispatch(currentCandidate(el))
); );
} }
@ -67,7 +69,7 @@ const FormPage = () => {
<div className='form-page__telegram'> <div className='form-page__telegram'>
<div className='form-page__telegram-text'>Заявка на собеседование через телеграм</div> <div className='form-page__telegram-text'>Заявка на собеседование через телеграм</div>
<div className='form-page__telegram-icon'> <div className='form-page__telegram-icon'>
<SVG src={telegramIcon} /> <a href='https://t.me/st0kir' target='_blank'><SVG src={telegramIcon} /></a>
</div> </div>
</div> </div>
</div> </div>

21
src/redux/roleSlice.js Normal file
View File

@ -0,0 +1,21 @@
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
role: null,
};
export const roleSlice = createSlice({
name: 'role',
initialState,
reducers: {
setRole: (state, action) => {
state.role = action.payload;
},
},
});
export const { setRole } = roleSlice.actions;
export const getRole = (state) => state.role.role;
export default roleSlice.reducer;

View File

@ -1,11 +1,15 @@
export const withAuthRedirect = actionCall => (link, index) => { export const withAuthRedirect = actionCall => ({link, index, history, role}) => {
return actionCall(link, index) return actionCall(link, index)
.then(res => { .then(res => {
if(res.status && res.status == 401) { if(res.status && res.status == 401) {
localStorage.clear(); localStorage.clear();
history.push(role === 'ROLE_DEV' ? '/authdev' : '/auth')
} }
return res; return res;
}) })
.catch(err => localStorage.clear()) .catch(err => {
localStorage.clear();
history.push(role === 'ROLE_DEV' ? '/authdev' : '/auth');
})
} }

View File

@ -1,10 +1,12 @@
import { configureStore } from '@reduxjs/toolkit'; import { configureStore } from '@reduxjs/toolkit';
import outstaffingReducer from '../redux/outstaffingSlice'; import outstaffingReducer from '../redux/outstaffingSlice';
import loaderReducer from '../redux/loaderSlice'; import loaderReducer from '../redux/loaderSlice';
import roleReducer from '../redux/roleSlice';
export const store = configureStore({ export const store = configureStore({
reducer: { reducer: {
outstaffing: outstaffingReducer, outstaffing: outstaffingReducer,
loader: loaderReducer, loader: loaderReducer,
role: roleReducer
}, },
}); });