add redux
This commit is contained in:
parent
397f867f2b
commit
e90414b6b9
74
package-lock.json
generated
74
package-lock.json
generated
@ -1938,6 +1938,24 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.2.tgz",
|
||||||
"integrity": "sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q=="
|
"integrity": "sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q=="
|
||||||
},
|
},
|
||||||
|
"@reduxjs/toolkit": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-eGL50G+Vj5AG5uD0lineb6rRtbs96M8+hxbcwkHpZ8LQcmt0Bm33WyBSnj5AweLkjQ7ZP+KFRDHiLMznljRQ3A==",
|
||||||
|
"requires": {
|
||||||
|
"immer": "^9.0.1",
|
||||||
|
"redux": "^4.1.0",
|
||||||
|
"redux-thunk": "^2.3.0",
|
||||||
|
"reselect": "^4.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"immer": {
|
||||||
|
"version": "9.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.3.tgz",
|
||||||
|
"integrity": "sha512-mONgeNSMuyjIe0lkQPa9YhdmTv8P19IeHV0biYhcXhbd5dhdB9HSK93zBpyKjp6wersSUgT5QyU0skmejUVP2A=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@restart/context": {
|
"@restart/context": {
|
||||||
"version": "2.1.4",
|
"version": "2.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz",
|
||||||
@ -2371,6 +2389,15 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/hoist-non-react-statics": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
|
||||||
|
"requires": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"hoist-non-react-statics": "^3.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/html-minifier-terser": {
|
"@types/html-minifier-terser": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
|
||||||
@ -2466,6 +2493,17 @@
|
|||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/react-redux": {
|
||||||
|
"version": "7.1.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz",
|
||||||
|
"integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==",
|
||||||
|
"requires": {
|
||||||
|
"@types/hoist-non-react-statics": "^3.3.0",
|
||||||
|
"@types/react": "*",
|
||||||
|
"hoist-non-react-statics": "^3.3.0",
|
||||||
|
"redux": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/react-transition-group": {
|
"@types/react-transition-group": {
|
||||||
"version": "4.4.1",
|
"version": "4.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
||||||
@ -12695,6 +12733,19 @@
|
|||||||
"warning": "^4.0.3"
|
"warning": "^4.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-redux": {
|
||||||
|
"version": "7.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz",
|
||||||
|
"integrity": "sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.12.1",
|
||||||
|
"@types/react-redux": "^7.1.16",
|
||||||
|
"hoist-non-react-statics": "^3.3.2",
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"react-is": "^16.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-refresh": {
|
"react-refresh": {
|
||||||
"version": "0.8.3",
|
"version": "0.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
|
||||||
@ -12975,6 +13026,24 @@
|
|||||||
"strip-indent": "^3.0.0"
|
"strip-indent": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"redux": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.9.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redux-devtools-extension": {
|
||||||
|
"version": "2.13.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.9.tgz",
|
||||||
|
"integrity": "sha512-cNJ8Q/EtjhQaZ71c8I9+BPySIBVEKssbPpskBfsXqb8HJ002A3KRVHfeRzwRo6mGPqsm7XuHTqNSNeS1Khig0A=="
|
||||||
|
},
|
||||||
|
"redux-thunk": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
|
||||||
|
},
|
||||||
"regenerate": {
|
"regenerate": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
||||||
@ -13129,6 +13198,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||||
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
|
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
|
||||||
},
|
},
|
||||||
|
"reselect": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA=="
|
||||||
|
},
|
||||||
"resolve": {
|
"resolve": {
|
||||||
"version": "1.18.1",
|
"version": "1.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz",
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://html.craft-group.xyz/outstaffing/",
|
"homepage": "https://html.craft-group.xyz/outstaffing/",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@reduxjs/toolkit": "^1.6.0",
|
||||||
"@testing-library/jest-dom": "^5.12.0",
|
"@testing-library/jest-dom": "^5.12.0",
|
||||||
"@testing-library/react": "^11.2.7",
|
"@testing-library/react": "^11.2.7",
|
||||||
"@testing-library/user-event": "^12.8.3",
|
"@testing-library/user-event": "^12.8.3",
|
||||||
@ -13,9 +14,11 @@
|
|||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-bootstrap": "^1.6.0",
|
"react-bootstrap": "^1.6.0",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
"react-redux": "^7.2.4",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"react-select": "^4.3.1",
|
"react-select": "^4.3.1",
|
||||||
|
"redux-devtools-extension": "^2.13.9",
|
||||||
"sass": "^1.34.0",
|
"sass": "^1.34.0",
|
||||||
"sass-loader": "^11.1.1",
|
"sass-loader": "^11.1.1",
|
||||||
"web-vitals": "^1.1.2"
|
"web-vitals": "^1.1.2"
|
||||||
|
10
src/App.js
10
src/App.js
@ -13,11 +13,17 @@ const ReportPage = lazy(() => import('./pages/ReportFormPage.js'));
|
|||||||
const App = () => {
|
const App = () => {
|
||||||
const [isAuth, setIsAuth] = useState(true);
|
const [isAuth, setIsAuth] = useState(true);
|
||||||
const [candidates, setCandidates] = useState([]);
|
const [candidates, setCandidates] = useState([]);
|
||||||
|
const [candidateForCalendar, setCandidateForCalendar] = useState([]);
|
||||||
|
|
||||||
const getCandidate = (candidateArr) => {
|
const getCandidate = (candidateArr) => {
|
||||||
|
console.log('candidateArr ', candidateArr);
|
||||||
setCandidates(candidateArr);
|
setCandidates(candidateArr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getCandidateForCalendar = (candidate) => {
|
||||||
|
setCandidateForCalendar(candidate);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
<Suspense fallback={<div>Loading...</div>}>
|
<Suspense fallback={<div>Loading...</div>}>
|
||||||
@ -27,10 +33,10 @@ const App = () => {
|
|||||||
<HomePage getCandidate={getCandidate} />
|
<HomePage getCandidate={getCandidate} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/candidate/:id">
|
<Route path="/candidate/:id">
|
||||||
<CandidatePage candidatesArr={candidates} />
|
<CandidatePage candidatesArr={candidates} getCandidateForCalendar={getCandidateForCalendar} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/calendar">
|
<Route path="/calendar">
|
||||||
<CalendarPage />
|
<CalendarPage candidateForCalendar={candidateForCalendar} />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="/report">
|
<Route path="/report">
|
||||||
<ReportPage />
|
<ReportPage />
|
||||||
|
@ -6,13 +6,17 @@ import rectangle from '../../images/rectangle_secondPage.png';
|
|||||||
import CalendarComponent from './CalendarComponent';
|
import CalendarComponent from './CalendarComponent';
|
||||||
import { currentMonth } from './calendarHelper';
|
import { currentMonth } from './calendarHelper';
|
||||||
|
|
||||||
const Calendar = () => {
|
const Calendar = ({ candidateForCalendar }) => {
|
||||||
const [month, setMonth] = useState('');
|
const [month, setMonth] = useState('');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMonth(currentMonth);
|
setMonth(currentMonth);
|
||||||
}, [month]);
|
}, [month]);
|
||||||
|
|
||||||
|
const { name, skillsName } = candidateForCalendar;
|
||||||
|
|
||||||
|
const abbreviatedName = name.substring(0, name.lastIndexOf(' '));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={style.calendar}>
|
<section className={style.calendar}>
|
||||||
<div className="container">
|
<div className="container">
|
||||||
@ -23,12 +27,10 @@ const Calendar = () => {
|
|||||||
<div className="col-12 col-xl-12 d-flex justify-content-between align-items-center flex-column flex-sm-row">
|
<div className="col-12 col-xl-12 d-flex justify-content-between align-items-center flex-column flex-sm-row">
|
||||||
<div className={style.calendarHeader__info}>
|
<div className={style.calendarHeader__info}>
|
||||||
<img className={style.calendarHeader__info__img} src={calendarMale} alt="img" />
|
<img className={style.calendarHeader__info__img} src={calendarMale} alt="img" />
|
||||||
<h3 className={style.calendarHeader__info__name}>
|
<h3 className={style.calendarHeader__info__name}>{abbreviatedName}</h3>
|
||||||
Александр <br /> Комов
|
|
||||||
</h3>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={style.calendarHeader__title}>
|
<div className={style.calendarHeader__title}>
|
||||||
<h3 className={style.calendarHeader__title__text}>Frontend разработчик, Middle</h3>
|
<h3 className={style.calendarHeader__title__text}>{skillsName} разработчик</h3>
|
||||||
<img className={style.calendarHeader__title__img} src={rectangle} alt="img" />
|
<img className={style.calendarHeader__title__img} src={rectangle} alt="img" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -11,7 +11,7 @@ import SectionFour from './sections/SectionFour';
|
|||||||
import SectionFive from './sections/SectionFive';
|
import SectionFive from './sections/SectionFive';
|
||||||
import SectionSkills from './sections/SectionSkills';
|
import SectionSkills from './sections/SectionSkills';
|
||||||
|
|
||||||
const Candidate = ({ candidatesArr }) => {
|
const Candidate = ({ candidatesArr, getCandidateForCalendar }) => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
const { id: candidateId } = useParams();
|
const { id: candidateId } = useParams();
|
||||||
@ -66,7 +66,7 @@ const Candidate = ({ candidatesArr }) => {
|
|||||||
<div className={style.candidate__main}>
|
<div className={style.candidate__main}>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12 col-xl-4">
|
<div className="col-12 col-xl-4">
|
||||||
<Sidebar />
|
<Sidebar getCandidateForCalendar={getCandidateForCalendar} currentCandidateObj={currentCandidate} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-12 col-xl-8">
|
<div className="col-12 col-xl-8">
|
||||||
|
@ -17,9 +17,7 @@ const Description = ({ candidatesListArr, getCandidate, onLoadMore }) => {
|
|||||||
<img className={style.description__img} src={dog} alt="" />
|
<img className={style.description__img} src={dog} alt="" />
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12 col-xl-6">
|
<div className="col-12 col-xl-6">
|
||||||
<h3 className={style.description__title}>
|
<h3 className={style.description__title}>{el.header} разработчик</h3>
|
||||||
{el.name} - {el.skillsName}
|
|
||||||
</h3>
|
|
||||||
<p className={style.description__text}>
|
<p className={style.description__text}>
|
||||||
- 10 лет пишу приложения под IOS, отлично владею Objective-C и Swift.
|
- 10 лет пишу приложения под IOS, отлично владею Objective-C и Swift.
|
||||||
</p>
|
</p>
|
||||||
|
@ -1,80 +1,26 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
|
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 front from '../../images/front_end.png';
|
import front from '../../images/front_end.png';
|
||||||
import back from '../../images/back_end.png';
|
import back from '../../images/back_end.png';
|
||||||
import design from '../../images/design.png';
|
import design from '../../images/design.png';
|
||||||
import { fetchProfile, fetchSkills } from '../../server/server';
|
import { fetchProfile, fetchSkills } from '../../server/server';
|
||||||
|
import { profiles, selectProfiles, tags, candidates, selectCandidates, selectTab } from '../../redux/outstaffingSlice';
|
||||||
const tabsList = [
|
|
||||||
{
|
|
||||||
name: 'Frontend',
|
|
||||||
img: front,
|
|
||||||
text: '# Популярный стек',
|
|
||||||
header: 'Фронтенд',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Backend',
|
|
||||||
img: back,
|
|
||||||
text: '# Популярный стек',
|
|
||||||
header: 'Бэкенд',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Design',
|
|
||||||
img: design,
|
|
||||||
text: '# Популярный стек',
|
|
||||||
header: 'Дизайн',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const Home = ({ getCandidate }) => {
|
const Home = ({ getCandidate }) => {
|
||||||
const [tabs, setTabs] = useState([]);
|
const [count, setCount] = useState(2);
|
||||||
const [tags, setTags] = useState([]);
|
|
||||||
const [profiles, setProfiles] = useState([]);
|
const dispatch = useDispatch();
|
||||||
const [selectedTab, setSelectedTab] = useState('');
|
const profilesArr = useSelector(selectProfiles);
|
||||||
const [countArr, setCountArr] = useState(2);
|
const candidatesArr = useSelector(selectCandidates);
|
||||||
const [candidatesArray, setCandidatesArray] = useState([]);
|
const selectedTab = useSelector(selectTab);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTabs(tabsList);
|
|
||||||
|
|
||||||
fetchProfile('https://guild.craft-group.xyz/api/profile')
|
fetchProfile('https://guild.craft-group.xyz/api/profile')
|
||||||
.then((profileArr) => setProfiles(profileArr))
|
.then((profileArr) => dispatch(profiles(profileArr)))
|
||||||
.catch((e) => console.log(e));
|
.catch((e) => console.log(e));
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (profiles.length) {
|
|
||||||
setCandidatesArray(
|
|
||||||
profiles.map((profile) => {
|
|
||||||
let skillsName = '';
|
|
||||||
let img;
|
|
||||||
|
|
||||||
if (Number(profile.position_id) === 1) {
|
|
||||||
skillsName = 'Frontend';
|
|
||||||
img = front;
|
|
||||||
} else if (Number(profile.position_id) === 2) {
|
|
||||||
skillsName = 'Backend';
|
|
||||||
img = back;
|
|
||||||
} else if (Number(profile.position_id) === 3) {
|
|
||||||
skillsName = 'Marketer';
|
|
||||||
img = design;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: profile.id,
|
|
||||||
profileId: profile.position_id,
|
|
||||||
name: profile.fio,
|
|
||||||
skills: profile.skillValues,
|
|
||||||
skillsName: skillsName,
|
|
||||||
img: img,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, [profiles]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchSkills('https://guild.craft-group.xyz/api/skills/skills-on-main-page').then((skills) => {
|
fetchSkills('https://guild.craft-group.xyz/api/skills/skills-on-main-page').then((skills) => {
|
||||||
const keys = Object.keys(skills);
|
const keys = Object.keys(skills);
|
||||||
const values = Object.values(skills);
|
const values = Object.values(skills);
|
||||||
@ -84,26 +30,58 @@ const Home = ({ getCandidate }) => {
|
|||||||
return { id: val.id, value: val.tags, name: keys[index] };
|
return { id: val.id, value: val.tags, name: keys[index] };
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
setTags(tempTags);
|
dispatch(tags(tempTags));
|
||||||
});
|
});
|
||||||
}, []);
|
}, [dispatch]);
|
||||||
|
|
||||||
const shorthandArray = candidatesArray.slice(0, countArr);
|
useEffect(() => {
|
||||||
|
dispatch(
|
||||||
|
candidates(
|
||||||
|
profilesArr.map((profile) => {
|
||||||
|
let skillsName = '';
|
||||||
|
let img;
|
||||||
|
let header;
|
||||||
|
|
||||||
|
if (Number(profile.position_id) === 1) {
|
||||||
|
skillsName = 'Frontend';
|
||||||
|
img = front;
|
||||||
|
header = 'Фронтенд';
|
||||||
|
} else if (Number(profile.position_id) === 2) {
|
||||||
|
skillsName = 'Backend';
|
||||||
|
img = back;
|
||||||
|
header = 'Бэкенд';
|
||||||
|
} else if (Number(profile.position_id) === 3) {
|
||||||
|
skillsName = 'Marketer';
|
||||||
|
img = design;
|
||||||
|
header = 'Дизайн';
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: profile.id,
|
||||||
|
profileId: profile.position_id,
|
||||||
|
name: profile.fio,
|
||||||
|
skills: profile.skillValues,
|
||||||
|
skillsName,
|
||||||
|
img,
|
||||||
|
header,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}, [profilesArr, dispatch]);
|
||||||
|
|
||||||
|
const shorthandArray = candidatesArr.slice(0, count);
|
||||||
|
|
||||||
const loadMore = (count) => {
|
const loadMore = (count) => {
|
||||||
setCountArr((prev) => prev + count);
|
setCount((prev) => prev + count);
|
||||||
};
|
|
||||||
|
|
||||||
const handleBlockClick = (name) => {
|
|
||||||
setSelectedTab(name);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Outstaffing onhandleTabBar={(name) => handleBlockClick(name)} selected={selectedTab} tabs={tabs} tags={tags} />
|
<Outstaffing selected={selectedTab} candidatesArray={candidatesArr} />
|
||||||
<Description
|
<Description
|
||||||
candidatesListArr={
|
candidatesListArr={
|
||||||
selectedTab ? candidatesArray.filter((item) => item.skillsName === selectedTab) : shorthandArray
|
selectedTab ? candidatesArr.filter((item) => item.skillsName === selectedTab) : shorthandArray
|
||||||
}
|
}
|
||||||
getCandidate={getCandidate}
|
getCandidate={getCandidate}
|
||||||
onLoadMore={loadMore}
|
onLoadMore={loadMore}
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
import style from './Outstaffing.module.css';
|
import style from './Outstaffing.module.css';
|
||||||
import OutstaffingBlock from './OutstaffingBlock';
|
import OutstaffingBlock from './OutstaffingBlock';
|
||||||
import TagSelect from '../Select/TagSelect';
|
import TagSelect from '../Select/TagSelect';
|
||||||
|
import { selectTags } from '../../redux/outstaffingSlice';
|
||||||
|
|
||||||
const Outstaffing = ({ onhandleTabBar, selected, tabs, tags }) => {
|
const Outstaffing = ({ selected, candidatesArray }) => {
|
||||||
const [selectedItems, setSelectedItems] = useState([]);
|
const [selectedItems, setSelectedItems] = useState([]);
|
||||||
|
|
||||||
|
const tagsArr = useSelector(selectTags);
|
||||||
|
|
||||||
const handleBlockClick = (item) => {
|
const handleBlockClick = (item) => {
|
||||||
|
console.log('item ', item);
|
||||||
if (!selectedItems.find((el) => item === el.value)) {
|
if (!selectedItems.find((el) => item === el.value)) {
|
||||||
setSelectedItems([...selectedItems, { value: item, label: item }]);
|
setSelectedItems([...selectedItems, { value: item, label: item }]);
|
||||||
}
|
}
|
||||||
@ -37,28 +42,25 @@ const Outstaffing = ({ onhandleTabBar, selected, tabs, tags }) => {
|
|||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12 col-xl-4">
|
<div className="col-12 col-xl-4">
|
||||||
<OutstaffingBlock
|
<OutstaffingBlock
|
||||||
data={tabs.find((item) => item.name === 'Frontend')}
|
data={candidatesArray.find((item) => item.skillsName === 'Frontend')}
|
||||||
dataTags={tags.flat().filter((tag) => tag.name === 'skills_front')}
|
dataTags={tagsArr.flat().filter((tag) => tag.name === 'skills_front')}
|
||||||
onClick={(item) => handleBlockClick(item)}
|
onClick={(item) => handleBlockClick(item)}
|
||||||
onTabBarClick={(name) => onhandleTabBar(name)}
|
|
||||||
selected={selected === 'Frontend'}
|
selected={selected === 'Frontend'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12 col-xl-4">
|
<div className="col-12 col-xl-4">
|
||||||
<OutstaffingBlock
|
<OutstaffingBlock
|
||||||
data={tabs.find((item) => item.name === 'Backend')}
|
data={candidatesArray.find((item) => item.skillsName === 'Backend')}
|
||||||
dataTags={tags.flat().filter((tag) => tag.name === 'skills_back')}
|
dataTags={tagsArr.flat().filter((tag) => tag.name === 'skills_back')}
|
||||||
onClick={(item) => handleBlockClick(item)}
|
onClick={(item) => handleBlockClick(item)}
|
||||||
onTabBarClick={(name) => onhandleTabBar(name)}
|
|
||||||
selected={selected === 'Backend'}
|
selected={selected === 'Backend'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12 col-xl-4">
|
<div className="col-12 col-xl-4">
|
||||||
<OutstaffingBlock
|
<OutstaffingBlock
|
||||||
data={tabs.find((item) => item.name === 'Design')}
|
data={candidatesArray.find((item) => item.skillsName === 'Marketer')}
|
||||||
dataTags={tags.flat().filter((tag) => tag.name === 'skills_design')}
|
dataTags={tagsArr.flat().filter((tag) => tag.name === 'skills_design')}
|
||||||
onClick={(item) => handleBlockClick(item)}
|
onClick={(item) => handleBlockClick(item)}
|
||||||
onTabBarClick={(name) => onhandleTabBar(name)}
|
|
||||||
selected={selected === 'Design'}
|
selected={selected === 'Design'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -66,7 +68,7 @@ const Outstaffing = ({ onhandleTabBar, selected, tabs, tags }) => {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<TagSelect
|
<TagSelect
|
||||||
options={tags}
|
options={tagsArr}
|
||||||
selectedItems={selectedItems}
|
selectedItems={selectedItems}
|
||||||
tagSubmit={handleSubmit}
|
tagSubmit={handleSubmit}
|
||||||
setSelectedItems={setSelectedItems}
|
setSelectedItems={setSelectedItems}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { selectedTab } from '../../redux/outstaffingSlice';
|
||||||
import style from './Outstaffing.module.css';
|
import style from './Outstaffing.module.css';
|
||||||
|
|
||||||
const OutstaffingBlock = ({ dataTags = [], data = {}, onClick, onTabBarClick, selected }) => {
|
const OutstaffingBlock = ({ dataTags = [], data = {}, onClick, selected }) => {
|
||||||
const { header, img, text, name } = data;
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const { header, img, skillsName } = data;
|
||||||
|
|
||||||
let classes;
|
let classes;
|
||||||
|
|
||||||
@ -20,13 +24,13 @@ const OutstaffingBlock = ({ dataTags = [], data = {}, onClick, onTabBarClick, se
|
|||||||
<div className={style.outstaffing__box}>
|
<div className={style.outstaffing__box}>
|
||||||
<div
|
<div
|
||||||
className={`${style.outstaffing__box__img} ${selected ? style.border : null}`}
|
className={`${style.outstaffing__box__img} ${selected ? style.border : null}`}
|
||||||
onClick={() => onTabBarClick(name)}
|
onClick={() => dispatch(selectedTab(skillsName))}
|
||||||
>
|
>
|
||||||
<h3>{header}</h3>
|
<h3>{header}</h3>
|
||||||
<img className={classes} src={img} alt="img" />
|
<img className={classes} src={img} alt="img" />
|
||||||
</div>
|
</div>
|
||||||
<div className={`${selected ? style.mobile__block : style.mobile__none}`}>
|
<div className={`${selected ? style.mobile__block : style.mobile__none}`}>
|
||||||
<p className={style.outstaffing__box__text}>{text}</p>
|
<p className={style.outstaffing__box__text}># Популярный стек</p>
|
||||||
{dataTags && (
|
{dataTags && (
|
||||||
<ul className={style.items}>
|
<ul className={style.items}>
|
||||||
{dataTags.map((item) => (
|
{dataTags.map((item) => (
|
||||||
|
@ -5,14 +5,14 @@ import arrowLeft from '../../images/arrow_left.png';
|
|||||||
import arrowRight from '../../images/arrow_right.png';
|
import arrowRight from '../../images/arrow_right.png';
|
||||||
import style from './Sidebar.module.css';
|
import style from './Sidebar.module.css';
|
||||||
|
|
||||||
const Sidebar = () => {
|
const Sidebar = ({ getCandidateForCalendar, currentCandidateObj }) => {
|
||||||
return (
|
return (
|
||||||
<div className={style.candidateSidebar}>
|
<div className={style.candidateSidebar}>
|
||||||
<div className={style.candidateSidebar__info}>
|
<div className={style.candidateSidebar__info}>
|
||||||
<img src={dogBig} alt="" />
|
<img src={dogBig} alt="" />
|
||||||
<p className={style.candidateSidebar__info__e}>Опыт работы</p>
|
<p className={style.candidateSidebar__info__e}>Опыт работы</p>
|
||||||
<p className={style.candidateSidebar__info__y}>4+ лет</p>
|
<p className={style.candidateSidebar__info__y}>4+ лет</p>
|
||||||
<Link to={`/calendar`}>
|
<Link to={`/calendar`} onClick={() => getCandidateForCalendar(currentCandidateObj)}>
|
||||||
<button className={style.candidateSidebar__info__btn}>Выбрать к собеседованию</button>
|
<button className={style.candidateSidebar__info__btn}>Выбрать к собеседованию</button>
|
||||||
</Link>
|
</Link>
|
||||||
<p className={style.candidateSidebar__info__l}>Посмотреть ещё</p>
|
<p className={style.candidateSidebar__info__l}>Посмотреть ещё</p>
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
import { store } from './store/store';
|
||||||
|
import { Provider } from 'react-redux';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
ReactDOM.render(<App />, document.getElementById('root'));
|
ReactDOM.render(
|
||||||
|
<Provider store={store}>
|
||||||
|
<App />
|
||||||
|
</Provider>,
|
||||||
|
document.getElementById('root')
|
||||||
|
);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Calendar from '../components/Calendar/Calendar';
|
import Calendar from '../components/Calendar/Calendar';
|
||||||
|
|
||||||
const CalendarPage = () => {
|
const CalendarPage = ({ candidateForCalendar }) => {
|
||||||
return <Calendar />;
|
return <Calendar candidateForCalendar={candidateForCalendar} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CalendarPage;
|
export default CalendarPage;
|
||||||
|
@ -2,6 +2,8 @@ import React from 'react';
|
|||||||
|
|
||||||
import Candidate from '../components/Candidate/Candidate';
|
import Candidate from '../components/Candidate/Candidate';
|
||||||
|
|
||||||
const CandidatePage = ({ candidatesArr }) => <Candidate candidatesArr={candidatesArr} />;
|
const CandidatePage = ({ candidatesArr, getCandidateForCalendar }) => (
|
||||||
|
<Candidate candidatesArr={candidatesArr} getCandidateForCalendar={getCandidateForCalendar} />
|
||||||
|
);
|
||||||
|
|
||||||
export default CandidatePage;
|
export default CandidatePage;
|
||||||
|
41
src/redux/outstaffingSlice.js
Normal file
41
src/redux/outstaffingSlice.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
tags: [],
|
||||||
|
profiles: [],
|
||||||
|
candidates: [],
|
||||||
|
selectedTab: '',
|
||||||
|
selectedItems: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const outstaffingSlice = createSlice({
|
||||||
|
name: 'outstaffing',
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
tags: (state, action) => {
|
||||||
|
state.tags = action.payload;
|
||||||
|
},
|
||||||
|
profiles: (state, action) => {
|
||||||
|
state.profiles = action.payload;
|
||||||
|
},
|
||||||
|
candidates: (state, action) => {
|
||||||
|
state.candidates = action.payload;
|
||||||
|
},
|
||||||
|
selectedTab: (state, action) => {
|
||||||
|
state.selectedTab = action.payload;
|
||||||
|
},
|
||||||
|
selectedItem: (state, action) => {
|
||||||
|
state.selectedItem = action.payload;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { tags, profiles, candidates, selectedTab, selectedItems } = outstaffingSlice.actions;
|
||||||
|
|
||||||
|
export const selectProfiles = (state) => state.outstaffing.profiles;
|
||||||
|
export const selectTags = (state) => state.outstaffing.tags;
|
||||||
|
export const selectCandidates = (state) => state.outstaffing.candidates;
|
||||||
|
export const selectTab = (state) => state.outstaffing.selectedTab;
|
||||||
|
export const selectItems = (state) => state.outstaffing.selectedItems;
|
||||||
|
|
||||||
|
export default outstaffingSlice.reducer;
|
8
src/store/store.js
Normal file
8
src/store/store.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
|
import outstaffingReducer from '../redux/outstaffingSlice';
|
||||||
|
|
||||||
|
export const store = configureStore({
|
||||||
|
reducer: {
|
||||||
|
outstaffing: outstaffingReducer,
|
||||||
|
},
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user