фиксы
This commit is contained in:
parent
2a8c26c3c6
commit
642a8a9641
@ -4,8 +4,8 @@ import {BrowserRouter as Router, Route, Routes, Navigate} from 'react-router-dom
|
|||||||
|
|
||||||
import AuthForPartners from "./pages/AuthForPartners/AuthForPartners";
|
import AuthForPartners from "./pages/AuthForPartners/AuthForPartners";
|
||||||
import AuthForDevelopers from "./pages/AuthForDevelopers/AuthForDevelopers";
|
import AuthForDevelopers from "./pages/AuthForDevelopers/AuthForDevelopers";
|
||||||
import Home from "./components/Home/Home";
|
import Home from "./pages/Home/Home";
|
||||||
import CandidatePage from './pages/CandidatePage'
|
import Candidate from "./components/Candidate/Candidate";
|
||||||
import Calendar from "./components/Calendar/Calendar";
|
import Calendar from "./components/Calendar/Calendar";
|
||||||
import ReportForm from "./components/ReportForm/ReportForm";
|
import ReportForm from "./components/ReportForm/ReportForm";
|
||||||
import {ProfileCalendar} from "./components/ProfileCalendar/ProfileCalendar";
|
import {ProfileCalendar} from "./components/ProfileCalendar/ProfileCalendar";
|
||||||
@ -24,6 +24,7 @@ import 'bootstrap/dist/css/bootstrap.min.css'
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -36,7 +37,7 @@ const App = () => {
|
|||||||
<Route exact path='/authdev' element={<AuthForDevelopers/>}/>
|
<Route exact path='/authdev' element={<AuthForDevelopers/>}/>
|
||||||
<Route exact path='/auth' element={<AuthForPartners/>}/>
|
<Route exact path='/auth' element={<AuthForPartners/>}/>
|
||||||
|
|
||||||
<Route exact path='/candidate/:id' element={<CandidatePage/>}/>
|
<Route exact path='/candidate/:id' element={<Candidate/>}/>
|
||||||
<Route exact path='/candidate/:id/form' element={<FormPage/>}/>
|
<Route exact path='/candidate/:id/form' element={<FormPage/>}/>
|
||||||
<Route path='/:userId/calendar' element={<Calendar/>}/>
|
<Route path='/:userId/calendar' element={<Calendar/>}/>
|
||||||
|
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
import React, {useState} from 'react'
|
import React, {useState} from 'react'
|
||||||
import {Link} from 'react-router-dom'
|
import {Link, useNavigate} from 'react-router-dom'
|
||||||
import {useDispatch, useSelector} from 'react-redux'
|
import {useDispatch, useSelector} from 'react-redux'
|
||||||
import {withSwalInstance} from 'sweetalert2-react'
|
import {withSwalInstance} from 'sweetalert2-react'
|
||||||
import swal from 'sweetalert2'
|
import swal from 'sweetalert2'
|
||||||
|
|
||||||
import {Loader} from '../Loader/Loader'
|
import {Loader} from '../Loader/Loader'
|
||||||
|
import ErrorBoundary from "../../hoc/ErrorBoundary";
|
||||||
|
|
||||||
import {auth, setUserInfo} from '../../redux/outstaffingSlice'
|
import {auth, selectAuth, setUserInfo} from '../../redux/outstaffingSlice'
|
||||||
import {loading} from '../../redux/loaderSlice'
|
import {loading} from '../../redux/loaderSlice'
|
||||||
import {setRole} from '../../redux/roleSlice'
|
import {setRole} from '../../redux/roleSlice'
|
||||||
|
|
||||||
import {selectIsLoading} from '../../redux/loaderSlice'
|
import {selectIsLoading} from '../../redux/loaderSlice'
|
||||||
|
|
||||||
|
import {useRequest} from "../../hooks/useRequest";
|
||||||
|
|
||||||
import ellipse from '../../images/ellipse.png'
|
import ellipse from '../../images/ellipse.png'
|
||||||
|
|
||||||
import './authBox.scss'
|
import './authBox.scss'
|
||||||
import {useRequest} from "../../hooks/useRequest";
|
|
||||||
|
|
||||||
|
|
||||||
const SweetAlert = withSwalInstance(swal);
|
const SweetAlert = withSwalInstance(swal);
|
||||||
@ -23,14 +25,21 @@ const SweetAlert = withSwalInstance(swal);
|
|||||||
export const AuthBox = ({title, altTitle, roleChangeLink}) => {
|
export const AuthBox = ({title, altTitle, roleChangeLink}) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const {apiRequest} = useRequest();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const isAuth = useSelector(selectAuth);
|
||||||
const isLoading = useSelector(selectIsLoading);
|
const isLoading = useSelector(selectIsLoading);
|
||||||
|
|
||||||
|
const {apiRequest} = useRequest();
|
||||||
|
|
||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
|
if (isAuth) {
|
||||||
|
navigate('/')
|
||||||
|
}
|
||||||
|
|
||||||
const submitHandler = () => {
|
const submitHandler = () => {
|
||||||
|
|
||||||
if (!isLoading) {
|
if (!isLoading) {
|
||||||
@ -97,12 +106,14 @@ export const AuthBox = ({title, altTitle, roleChangeLink}) => {
|
|||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<div className='auth-box__form-error'>
|
<div className='auth-box__form-error'>
|
||||||
<SweetAlert
|
<ErrorBoundary>
|
||||||
show={!!error}
|
<SweetAlert
|
||||||
title='Ошибка'
|
show={!!error}
|
||||||
text={error}
|
title='Ошибка'
|
||||||
onConfirm={() => setError(null)}
|
text={error}
|
||||||
/>
|
onConfirm={() => setError(null)}
|
||||||
|
/>
|
||||||
|
</ErrorBoundary>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -124,6 +135,7 @@ export const AuthBox = ({title, altTitle, roleChangeLink}) => {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -18,13 +18,19 @@ import back from '../../images/back_end.png'
|
|||||||
import design from '../../images/design.png'
|
import design from '../../images/design.png'
|
||||||
|
|
||||||
import './candidate.scss'
|
import './candidate.scss'
|
||||||
|
import {LogoutButton} from "../LogoutButton/LogoutButton";
|
||||||
|
import {Header} from "../Header/Header";
|
||||||
|
|
||||||
|
|
||||||
const Candidate = () => {
|
const Candidate = () => {
|
||||||
const {id: candidateId} = useParams();
|
const {id: candidateId} = useParams();
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const currentCandidateObj = useSelector(selectCurrentCandidate);
|
||||||
|
|
||||||
const [activeSnippet, setActiveSnippet] = useState(true);
|
const [activeSnippet, setActiveSnippet] = useState(true);
|
||||||
|
|
||||||
const {apiRequest} = useRequest();
|
const {apiRequest} = useRequest();
|
||||||
@ -39,8 +45,6 @@ const Candidate = () => {
|
|||||||
}).then((el) => dispatch(currentCandidate(el)))
|
}).then((el) => dispatch(currentCandidate(el)))
|
||||||
}, [dispatch, candidateId]);
|
}, [dispatch, candidateId]);
|
||||||
|
|
||||||
const currentCandidateObj = useSelector(selectCurrentCandidate);
|
|
||||||
|
|
||||||
const {position_id, skillValues, vc_text: text} = currentCandidateObj;
|
const {position_id, skillValues, vc_text: text} = currentCandidateObj;
|
||||||
|
|
||||||
const setStyles = () => {
|
const setStyles = () => {
|
||||||
@ -80,108 +84,105 @@ const Candidate = () => {
|
|||||||
const {header, img, classes} = setStyles();
|
const {header, img, classes} = setStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='candidate'>
|
<>
|
||||||
<div className='row'>
|
<Header/>
|
||||||
<div className='col-12'>
|
<div className='container candidate'>
|
||||||
<div className='candidate__title'>
|
|
||||||
<h2>
|
|
||||||
<span>Аутстаффинг</span> it-персонала
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='row'>
|
|
||||||
<div className='col-12 candidate__header'>
|
|
||||||
|
|
||||||
<div className='candidate__arrow' onClick={() => navigate('/')}>
|
|
||||||
<div className='candidate__arrow-img'>
|
|
||||||
<img src={arrow} alt=''/>
|
|
||||||
</div>
|
|
||||||
<div className='candidate__arrow-sp'>
|
|
||||||
<span>Вернуться к списку</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='candidate__icon'>
|
|
||||||
<h3>{header}</h3>
|
|
||||||
<img className={classes} src={img} alt=''/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='candidate__main'>
|
|
||||||
<div className='row'>
|
<div className='row'>
|
||||||
<div className='col-12 col-xl-4'>
|
<div className='col-12 candidate__header'>
|
||||||
<Sidebar candidate={currentCandidateObj} position activeSnippet={activeSnippet}
|
|
||||||
setActiveSnippet={setActiveSnippet}/>
|
<div className='candidate__arrow' onClick={() => navigate('/')}>
|
||||||
|
<div className='candidate__arrow-img'>
|
||||||
|
<img src={arrow} alt=''/>
|
||||||
|
</div>
|
||||||
|
<div className='candidate__arrow-sp'>
|
||||||
|
<span>Вернуться к списку</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='candidate__icon'>
|
||||||
|
<h3>{header}</h3>
|
||||||
|
<img className={classes} src={img} alt=''/>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{
|
</div>
|
||||||
activeSnippet ?
|
<div className='candidate__main'>
|
||||||
(
|
<div className='row'>
|
||||||
<div className='col-12 col-xl-8'>
|
<div className='col-12 col-xl-4'>
|
||||||
<div className='candidate__main-description'>
|
<Sidebar candidate={currentCandidateObj} position activeSnippet={activeSnippet}
|
||||||
<img src={rectangle} alt=''/>
|
setActiveSnippet={setActiveSnippet}/>
|
||||||
<p className='candidate__hashtag'># Описание опыта</p>
|
</div>
|
||||||
{text ? (
|
{
|
||||||
<div
|
activeSnippet ?
|
||||||
className='candidate__text'
|
(
|
||||||
dangerouslySetInnerHTML={createMarkup(text)}
|
<div className='col-12 col-xl-8'>
|
||||||
></div>
|
<div className='candidate__main-description'>
|
||||||
) : (
|
<img src={rectangle} alt=''/>
|
||||||
<p className='candidate__text-secondary'>
|
<p className='candidate__hashtag'># Описание опыта</p>
|
||||||
{currentCandidateObj.vc_text
|
{text ? (
|
||||||
? currentCandidateObj.vc_text
|
<div
|
||||||
: 'Описание отсутствует...'}
|
className='candidate__text'
|
||||||
</p>
|
dangerouslySetInnerHTML={createMarkup(text)}
|
||||||
)}
|
></div>
|
||||||
|
) : (
|
||||||
|
<p className='candidate__text-secondary'>
|
||||||
|
{currentCandidateObj.vc_text
|
||||||
|
? currentCandidateObj.vc_text
|
||||||
|
: 'Описание отсутствует...'}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
<SkillSection skillsArr={skillValues}/>
|
<SkillSection skillsArr={skillValues}/>
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) :
|
||||||
) :
|
(
|
||||||
(
|
<div className="col-12 col-xl-8">
|
||||||
<div className="col-12 col-xl-8">
|
<div className="candidate__works works">
|
||||||
<div className="candidate__works works">
|
<div className="works__body">
|
||||||
<div className="works__body">
|
<div className="works__item item-works">
|
||||||
<div className="works__item item-works">
|
<div className="item-works__body">
|
||||||
<div className="item-works__body">
|
<Link to="/" className="item-works__link">Vuetifyis.com</Link>
|
||||||
<Link to="/" className="item-works__link">Vuetifyis.com</Link>
|
<div className="item-works__text">Forked from
|
||||||
<div className="item-works__text">Forked from peluprvi/vuetifyjs.com <br/> Vuetifyjs.com
|
peluprvi/vuetifyjs.com <br/> Vuetifyjs.com
|
||||||
documentation
|
documentation
|
||||||
|
</div>
|
||||||
|
<div className="item-works__mark">Angular</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="item-works__mark">Angular</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="works__item item-works">
|
||||||
<div className="works__item item-works">
|
<div className="item-works__body">
|
||||||
<div className="item-works__body">
|
<Link to="/" className="item-works__link">Vuetifyis.com</Link>
|
||||||
<Link to="/" className="item-works__link">Vuetifyis.com</Link>
|
<div className="item-works__text">Forked from
|
||||||
<div className="item-works__text">Forked from peluprvi/vuetifyjs.com <br/> Vuetifyjs.com
|
peluprvi/vuetifyjs.com <br/> Vuetifyjs.com
|
||||||
documentation
|
documentation
|
||||||
|
</div>
|
||||||
|
<div className="item-works__mark">Angular</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="item-works__mark">Angular</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="works__item item-works">
|
||||||
<div className="works__item item-works">
|
<div className="item-works__body">
|
||||||
<div className="item-works__body">
|
<Link to="/" className="item-works__link">Vuetifyis.com</Link>
|
||||||
<Link to="/" className="item-works__link">Vuetifyis.com</Link>
|
<div className="item-works__text">Forked from
|
||||||
<div className="item-works__text">Forked from peluprvi/vuetifyjs.com <br/> Vuetifyjs.com
|
peluprvi/vuetifyjs.com <br/> Vuetifyjs.com
|
||||||
documentation
|
documentation
|
||||||
|
</div>
|
||||||
|
<div className="item-works__mark item-works__mark_yellow">Laravel</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="item-works__mark item-works__mark_yellow">Laravel</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Footer/>
|
||||||
</div>
|
</div>
|
||||||
<Footer/>
|
</>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,26 +1,6 @@
|
|||||||
@use 'sass:math';
|
@use 'sass:math';
|
||||||
.candidate {
|
.candidate {
|
||||||
&__title {
|
|
||||||
margin-top: 60px;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
text-align: center;
|
|
||||||
color: #52b709;
|
|
||||||
font-family: 'GT Eesti Pro Display', sans-serif;
|
|
||||||
font-size: 5em;
|
|
||||||
font-weight: 700;
|
|
||||||
font-style: normal;
|
|
||||||
letter-spacing: normal;
|
|
||||||
line-height: 77.81px;
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: #282828;
|
|
||||||
font-style: normal;
|
|
||||||
letter-spacing: 0.56px;
|
|
||||||
line-height: normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__header {
|
&__header {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -3,6 +3,7 @@ import {useSelector} from 'react-redux'
|
|||||||
import {Link} from 'react-router-dom'
|
import {Link} from 'react-router-dom'
|
||||||
|
|
||||||
import {Loader} from '../Loader/Loader'
|
import {Loader} from '../Loader/Loader'
|
||||||
|
import ErrorBoundary from "../../hoc/ErrorBoundary";
|
||||||
|
|
||||||
import {LEVELS, SKILLS} from '../../constants/constants'
|
import {LEVELS, SKILLS} from '../../constants/constants'
|
||||||
import {selectProfiles, selectFilteredCandidates,} from '../../redux/outstaffingSlice'
|
import {selectProfiles, selectFilteredCandidates,} from '../../redux/outstaffingSlice'
|
||||||
@ -12,211 +13,217 @@ import rectangle from '../../images/rectangle_secondPage.png'
|
|||||||
|
|
||||||
import './description.scss'
|
import './description.scss'
|
||||||
|
|
||||||
const Description = ({ onLoadMore, isLoadingMore }) => {
|
|
||||||
|
const Description = ({onLoadMore, isLoadingMore}) => {
|
||||||
|
|
||||||
const candidatesListArr = useSelector(selectProfiles);
|
const candidatesListArr = useSelector(selectProfiles);
|
||||||
const filteredListArr = useSelector(selectFilteredCandidates);
|
const filteredListArr = useSelector(selectFilteredCandidates);
|
||||||
|
|
||||||
|
|
||||||
if (!filteredListArr) {
|
if (!filteredListArr) {
|
||||||
return (
|
return (
|
||||||
|
<section className='description'>
|
||||||
|
<div className='container'>
|
||||||
|
<div className='description__wrapper'>
|
||||||
|
<ErrorBoundary>
|
||||||
|
{candidatesListArr && Array.isArray(candidatesListArr) && candidatesListArr.length > 0 ? (
|
||||||
|
candidatesListArr.map((el) => (
|
||||||
|
<div className='row' key={el.id}>
|
||||||
|
<div className='col-2 col-xs-12'>
|
||||||
|
<img className='description__img' src={el.photo} alt=''/>
|
||||||
|
</div>
|
||||||
|
<div className='col-12 col-xl-6'>
|
||||||
|
<h3 className='description__title'>
|
||||||
|
<Link to={`/candidate/${el.id}`}>
|
||||||
|
{el.specification} {SKILLS[el.position_id]},{' '}
|
||||||
|
{LEVELS[el.level]}{' '}
|
||||||
|
</Link>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{el.vc_text_short ? (
|
||||||
|
<div className='description__text'>
|
||||||
|
{el.vc_text_short}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className='description__text-secondary'>
|
||||||
|
Описание отсутствует...
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='col-12 col-xl-4'>
|
||||||
|
<Link to={`/candidate/${el.id}`}>
|
||||||
|
<button className='description__button'>
|
||||||
|
Подробное резюме
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className='col-xl-2'></div>
|
||||||
|
<div className='col-12 col-xl-6'>
|
||||||
|
<ul className='description__list'>
|
||||||
|
{Array.isArray(el?.skillValues) && el.skillValues.map((e) => (
|
||||||
|
<li key={e.id} className='description__list-item'>
|
||||||
|
{e.skill.name}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<img
|
||||||
|
className='description__rectangle'
|
||||||
|
src={rectangle}
|
||||||
|
alt=''
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='col-xl-4'></div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className='description__empty'>
|
||||||
|
{isLoadingMore
|
||||||
|
? 'В данный момент в категории нет свободных специалистов'
|
||||||
|
: 'Загрузка...'}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</ErrorBoundary>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='row'>
|
||||||
|
<div className='col-12'>
|
||||||
|
<div className='description__footer'>
|
||||||
|
<div className='description__footer-btn'>
|
||||||
|
<button onClick={() => onLoadMore(2)}>
|
||||||
|
{isLoadingMore ? (
|
||||||
|
<Loader width={40} height={40}/>
|
||||||
|
) : (
|
||||||
|
'Загрузить еще'
|
||||||
|
)}{' '}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<section className='description'>
|
<section className='description'>
|
||||||
<div className='container'>
|
<div className='container'>
|
||||||
<div className='description__wrapper'>
|
<div className='description__wrapper'>
|
||||||
{candidatesListArr && Array.isArray(candidatesListArr) && candidatesListArr.length > 0 ? (
|
<ErrorBoundary>
|
||||||
candidatesListArr.map((el) => (
|
{filteredListArr && Array.isArray(filteredListArr) && filteredListArr.length > 0
|
||||||
<div className='row' key={el.id}>
|
? filteredListArr.map((el) => (
|
||||||
<div className='col-2 col-xs-12'>
|
<div className='row' key={el.id}>
|
||||||
<img className='description__img' src={el.photo} alt='' />
|
<div className='col-2'>
|
||||||
</div>
|
<img className='description__img' src={el.photo} alt=''/>
|
||||||
<div className='col-12 col-xl-6'>
|
</div>
|
||||||
<h3 className='description__title'>
|
<div className='col-12 col-xl-6'>
|
||||||
<Link to={`/candidate/${el.id}`}>
|
<h3 className='description__title'>
|
||||||
{el.specification} {SKILLS[el.position_id]},{' '}
|
<Link to={`/candidate/${el.id}`}>
|
||||||
{LEVELS[el.level]}{' '}
|
{' '}
|
||||||
</Link>
|
{el.specification} {SKILLS[el.position_id]},{' '}
|
||||||
</h3>
|
{LEVELS[el.level]}{' '}
|
||||||
|
</Link>
|
||||||
|
</h3>
|
||||||
|
|
||||||
{el.vc_text_short ? (
|
{el.vc_text_short ? (
|
||||||
<div className='description__text'>
|
<div className='description__text'>
|
||||||
{el.vc_text_short}
|
{el.vc_text_short}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className='description__text-secondary'>
|
||||||
|
Описание отсутствует...
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='col-12 col-xl-4'>
|
||||||
|
<Link to={`/candidate/${el.id}`}>
|
||||||
|
<button className='description__button'>
|
||||||
|
Подробное резюме
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className='col-xl-2'></div>
|
||||||
|
<div className='col-12 col-xl-6'>
|
||||||
|
<ul className='description__list'>
|
||||||
|
{Array.isArray(el?.skillValues) && el.skillValues?.map((e) => (
|
||||||
|
<li key={e.id} className='description__list-item'>
|
||||||
|
{e.skill.name}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<img
|
||||||
|
className='description__rectangle'
|
||||||
|
src={rectangle}
|
||||||
|
alt=''
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='col-xl-4'></div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
))
|
||||||
<p className='description__text-secondary'>
|
: /* : <div className={style.description__empty}>В данный момент в категории нет свободных специалистов</div> } */
|
||||||
Описание отсутствует...
|
candidatesListArr && Array.isArray(candidatesListArr) &&
|
||||||
</p>
|
candidatesListArr.map((el) => (
|
||||||
)}
|
<div className='row' key={el.id}>
|
||||||
</div>
|
<div className='col-2'>
|
||||||
<div className='col-12 col-xl-4'>
|
<img className='description__img' src={male} alt=''/>
|
||||||
<Link to={`/candidate/${el.id}`}>
|
</div>
|
||||||
<button className='description__button'>
|
<div className='col-12 col-xl-6'>
|
||||||
Подробное резюме
|
<h3 className='description__title'>
|
||||||
</button>
|
{SKILLS[el.position_id]}, {LEVELS[el.level]}
|
||||||
</Link>
|
</h3>
|
||||||
</div>
|
|
||||||
<div className='col-xl-2'></div>
|
{el.vc_text_short ? (
|
||||||
<div className='col-12 col-xl-6'>
|
<div className='description__text'>
|
||||||
<ul className='description__list'>
|
{el.vc_text_short}
|
||||||
{Array.isArray(el?.skillValues) && el.skillValues.map((e) => (
|
</div>
|
||||||
<li key={e.id} className='description__list-item'>
|
) : (
|
||||||
{e.skill.name}
|
<p className='description__text-secondary'>
|
||||||
</li>
|
Описание отсутствует...
|
||||||
))}
|
</p>
|
||||||
</ul>
|
)}
|
||||||
<img
|
</div>
|
||||||
className='description__rectangle'
|
<div className='col-12 col-xl-4'>
|
||||||
src={rectangle}
|
<Link to={`/candidate/${el.id}`}>
|
||||||
alt=''
|
<button className='description__button'>
|
||||||
/>
|
Подробное резюме
|
||||||
</div>
|
</button>
|
||||||
<div className='col-xl-4'></div>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
))
|
<div className='col-xl-2'></div>
|
||||||
) : (
|
<div className='col-12 col-xl-6'>
|
||||||
<div className='description__empty'>
|
<ul className='description__list'>
|
||||||
{isLoadingMore
|
{Array.isArray(el?.skillValues) && el.skillValues?.map((e) => (
|
||||||
? 'В данный момент в категории нет свободных специалистов'
|
<li key={e.id} className='description__list-item'>
|
||||||
: 'Загрузка...'}
|
{e.skill.name}
|
||||||
</div>
|
</li>
|
||||||
)}
|
))}
|
||||||
|
</ul>
|
||||||
|
<img
|
||||||
|
className='description__rectangle'
|
||||||
|
src={rectangle}
|
||||||
|
alt=''
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='col-xl-4'></div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</ErrorBoundary>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='row'>
|
<div className='row'>
|
||||||
<div className='col-12'>
|
<div className='col-12'>
|
||||||
<div className='description__footer'>
|
<div className='description__footer'>
|
||||||
<div className='description__footer-btn'>
|
<div className='description__footer-btn'>
|
||||||
<button onClick={() => onLoadMore(2)}>
|
{candidatesListArr &&
|
||||||
{isLoadingMore ? (
|
filteredListArr.length === 0 ? (
|
||||||
<Loader width={40} height={40} />
|
<button onClick={() => onLoadMore(2)}>Загрузить еще</button>
|
||||||
) : (
|
) : null}
|
||||||
'Загрузить еще'
|
|
||||||
)}{' '}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<section className='description'>
|
|
||||||
<div className='container'>
|
|
||||||
<div className='description__wrapper'>
|
|
||||||
{filteredListArr && Array.isArray(filteredListArr) && filteredListArr.length > 0
|
|
||||||
? filteredListArr.map((el) => (
|
|
||||||
<div className='row' key={el.id}>
|
|
||||||
<div className='col-2'>
|
|
||||||
<img className='description__img' src={el.photo} alt='' />
|
|
||||||
</div>
|
|
||||||
<div className='col-12 col-xl-6'>
|
|
||||||
<h3 className='description__title'>
|
|
||||||
<Link to={`/candidate/${el.id}`}>
|
|
||||||
{' '}
|
|
||||||
{el.specification} {SKILLS[el.position_id]},{' '}
|
|
||||||
{LEVELS[el.level]}{' '}
|
|
||||||
</Link>
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
{el.vc_text_short ? (
|
|
||||||
<div className='description__text'>
|
|
||||||
{el.vc_text_short}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<p className='description__text-secondary'>
|
|
||||||
Описание отсутствует...
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className='col-12 col-xl-4'>
|
|
||||||
<Link to={`/candidate/${el.id}`}>
|
|
||||||
<button className='description__button'>
|
|
||||||
Подробное резюме
|
|
||||||
</button>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
<div className='col-xl-2'></div>
|
|
||||||
<div className='col-12 col-xl-6'>
|
|
||||||
<ul className='description__list'>
|
|
||||||
{Array.isArray(el?.skillValues) && el.skillValues?.map((e) => (
|
|
||||||
<li key={e.id} className='description__list-item'>
|
|
||||||
{e.skill.name}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<img
|
|
||||||
className='description__rectangle'
|
|
||||||
src={rectangle}
|
|
||||||
alt=''
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='col-xl-4'></div>
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
: /* : <div className={style.description__empty}>В данный момент в категории нет свободных специалистов</div> } */
|
|
||||||
candidatesListArr && Array.isArray(candidatesListArr) &&
|
|
||||||
candidatesListArr.map((el) => (
|
|
||||||
<div className='row' key={el.id}>
|
|
||||||
<div className='col-2'>
|
|
||||||
<img className='description__img' src={male} alt='' />
|
|
||||||
</div>
|
|
||||||
<div className='col-12 col-xl-6'>
|
|
||||||
<h3 className='description__title'>
|
|
||||||
{SKILLS[el.position_id]}, {LEVELS[el.level]}
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
{el.vc_text_short ? (
|
|
||||||
<div className='description__text'>
|
|
||||||
{el.vc_text_short}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<p className='description__text-secondary'>
|
|
||||||
Описание отсутствует...
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className='col-12 col-xl-4'>
|
|
||||||
<Link to={`/candidate/${el.id}`}>
|
|
||||||
<button className='description__button'>
|
|
||||||
Подробное резюме
|
|
||||||
</button>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
<div className='col-xl-2'></div>
|
|
||||||
<div className='col-12 col-xl-6'>
|
|
||||||
<ul className='description__list'>
|
|
||||||
{Array.isArray(el?.skillValues) && el.skillValues?.map((e) => (
|
|
||||||
<li key={e.id} className='description__list-item'>
|
|
||||||
{e.skill.name}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
<img
|
|
||||||
className='description__rectangle'
|
|
||||||
src={rectangle}
|
|
||||||
alt=''
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='col-xl-4'></div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='row'>
|
|
||||||
<div className='col-12'>
|
|
||||||
<div className='description__footer'>
|
|
||||||
<div className='description__footer-btn'>
|
|
||||||
{candidatesListArr &&
|
|
||||||
filteredListArr.length === 0 ? (
|
|
||||||
<button onClick={() => onLoadMore(2)}>Загрузить еще</button>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
15
src/components/Header/Header.js
Normal file
15
src/components/Header/Header.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {LogoutButton} from "../LogoutButton/LogoutButton";
|
||||||
|
|
||||||
|
import './header.scss'
|
||||||
|
|
||||||
|
export const Header = () => {
|
||||||
|
return (
|
||||||
|
<div className='container header'>
|
||||||
|
<h2>
|
||||||
|
<span>Аутстаффинг</span> it-персонала
|
||||||
|
</h2>
|
||||||
|
<LogoutButton/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
};
|
26
src/components/Header/header.scss
Normal file
26
src/components/Header/header.scss
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
.header {
|
||||||
|
margin-top: 60px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
color: #52b709;
|
||||||
|
font-family: 'GT Eesti Pro Display', sans-serif;
|
||||||
|
font-size: 5em;
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
letter-spacing: normal;
|
||||||
|
line-height: 77.81px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: #282828;
|
||||||
|
font-style: normal;
|
||||||
|
letter-spacing: 0.56px;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,10 +2,11 @@ import SVGLoader from 'react-loader-spinner'
|
|||||||
import './loader.scss'
|
import './loader.scss'
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export const Loader = ({ width = 50, height = 50 }) => {
|
|
||||||
|
export const Loader = ({width = 50, height = 50}) => {
|
||||||
return (
|
return (
|
||||||
<div className='loader'>
|
<div className='loader'>
|
||||||
<SVGLoader type='Circles' color='#fff' height={height} width={width} />
|
<SVGLoader type='Circles' color='#fff' height={height} width={width}/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,7 @@ import {useSelector, useDispatch} from 'react-redux'
|
|||||||
|
|
||||||
import OutstaffingBlock from '../OutstaffingBlock/OutstaffingBlock'
|
import OutstaffingBlock from '../OutstaffingBlock/OutstaffingBlock'
|
||||||
import TagSelect from '../Select/TagSelect'
|
import TagSelect from '../Select/TagSelect'
|
||||||
|
import {Header} from "../Header/Header";
|
||||||
|
|
||||||
import {selectTags, getPositionId, setPositionId} from '../../redux/outstaffingSlice'
|
import {selectTags, getPositionId, setPositionId} from '../../redux/outstaffingSlice'
|
||||||
|
|
||||||
@ -11,7 +12,8 @@ import back from '../../images/back_end.png'
|
|||||||
import design from '../../images/design.png'
|
import design from '../../images/design.png'
|
||||||
|
|
||||||
import './outstaffing.scss'
|
import './outstaffing.scss'
|
||||||
import {LogoutButton} from "../LogoutButton/LogoutButton";
|
|
||||||
|
|
||||||
|
|
||||||
const createSelectPositionHandler =
|
const createSelectPositionHandler =
|
||||||
({positionId, setPositionId, dispatch}) =>
|
({positionId, setPositionId, dispatch}) =>
|
||||||
@ -36,12 +38,6 @@ const Outstaffing = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<section className='outstaffing'>
|
<section className='outstaffing'>
|
||||||
<div className='outstaffing__title'>
|
|
||||||
<h2>
|
|
||||||
<span>Аутстаффинг</span> it-персонала
|
|
||||||
</h2>
|
|
||||||
<LogoutButton/>
|
|
||||||
</div>
|
|
||||||
<div className='row'>
|
<div className='row'>
|
||||||
<div className='col-12 col-xl-4'>
|
<div className='col-12 col-xl-4'>
|
||||||
<OutstaffingBlock
|
<OutstaffingBlock
|
||||||
|
@ -1,30 +1,3 @@
|
|||||||
.outstaffing {
|
|
||||||
&__title {
|
|
||||||
margin-top: 60px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
flex: 1;
|
|
||||||
text-align: center;
|
|
||||||
color: #52b709;
|
|
||||||
font-family: 'GT Eesti Pro Display', sans-serif;
|
|
||||||
font-size: 5em;
|
|
||||||
font-weight: 700;
|
|
||||||
font-style: normal;
|
|
||||||
letter-spacing: normal;
|
|
||||||
line-height: 77.81px;
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: #282828;
|
|
||||||
font-style: normal;
|
|
||||||
letter-spacing: 0.56px;
|
|
||||||
line-height: normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 375.98px) {
|
@media (max-width: 375.98px) {
|
||||||
.outstaffing__title > h2 {
|
.outstaffing__title > h2 {
|
||||||
|
22
src/hoc/ErrorBoundary.js
Normal file
22
src/hoc/ErrorBoundary.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import React, {Component} from "react";
|
||||||
|
|
||||||
|
class ErrorBoundary extends Component {
|
||||||
|
state = {
|
||||||
|
error: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
static getDerivedStateFromError(error) {
|
||||||
|
return {error};
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { error } = this.state;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return <div>Что-то пошло не так =( {error}</div>;
|
||||||
|
}
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ErrorBoundary
|
@ -1,7 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { WithLogout } from '../hoc/withLogout';
|
|
||||||
import Candidate from '../components/Candidate/Candidate';
|
|
||||||
|
|
||||||
const CandidatePage = () => <WithLogout><Candidate /></WithLogout>;
|
|
||||||
|
|
||||||
export default CandidatePage;
|
|
@ -1,14 +1,15 @@
|
|||||||
import React, {useState, useEffect} from 'react'
|
import React, {useState, useEffect} from 'react'
|
||||||
import {useDispatch} from 'react-redux'
|
import {useDispatch} from 'react-redux'
|
||||||
|
|
||||||
import Outstaffing from '../Outstaffing/Outstaffing'
|
import Outstaffing from '../../components/Outstaffing/Outstaffing'
|
||||||
import Description from '../Description/Description'
|
import Description from '../../components/Description/Description'
|
||||||
import {Footer} from '../Footer/Footer'
|
import {Footer} from '../../components/Footer/Footer'
|
||||||
|
|
||||||
import {profiles, tags} from '../../redux/outstaffingSlice'
|
import {profiles, tags} from '../../redux/outstaffingSlice'
|
||||||
|
|
||||||
import {useRequest} from "../../hooks/useRequest";
|
import {useRequest} from "../../hooks/useRequest";
|
||||||
import {LogoutButton} from "../LogoutButton/LogoutButton";
|
import {LogoutButton} from "../../components/LogoutButton/LogoutButton";
|
||||||
|
import {Header} from "../../components/Header/Header";
|
||||||
|
|
||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
@ -30,8 +31,7 @@ const Home = () => {
|
|||||||
setIsLoadingMore(false)
|
setIsLoadingMore(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
apiRequest('/skills/skills-on-main-page', {
|
apiRequest('/skills/skills-on-main-page', {}).then((skills) => {
|
||||||
}).then((skills) => {
|
|
||||||
if (!skills) {
|
if (!skills) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
@ -54,12 +54,14 @@ const Home = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='container'>
|
<>
|
||||||
|
<Header/>
|
||||||
<Outstaffing/>
|
<div className='container'>
|
||||||
<Description onLoadMore={loadMore} isLoadingMore={isLoadingMore}/>
|
<Outstaffing/>
|
||||||
<Footer/>
|
<Description onLoadMore={loadMore} isLoadingMore={isLoadingMore}/>
|
||||||
</div>
|
<Footer/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user