add form page

This commit is contained in:
Hope87 2021-07-03 17:37:30 +03:00
parent 629447c95c
commit 082ae23f49
16 changed files with 530 additions and 141 deletions

View File

@ -11,6 +11,7 @@ const HomePage = lazy(() => import('./pages/HomePage'));
const CandidatePage = lazy(() => import('./pages/CandidatePage')); const CandidatePage = lazy(() => import('./pages/CandidatePage'));
const CalendarPage = lazy(() => import('./pages/CalendarPage')); const CalendarPage = lazy(() => import('./pages/CalendarPage'));
const ReportPage = lazy(() => import('./pages/ReportFormPage.js')); const ReportPage = lazy(() => import('./pages/ReportFormPage.js'));
const FormPage = lazy(() => import('./pages/FormPage.js'));
const App = () => { const App = () => {
const isAuth = useSelector(selectAuth); const isAuth = useSelector(selectAuth);
@ -35,6 +36,9 @@ const App = () => {
<Route path="/calendar"> <Route path="/calendar">
<CalendarPage /> <CalendarPage />
</Route> </Route>
<Route path="/form">
<FormPage />
</Route>
<Route path="/report"> <Route path="/report">
<ReportPage /> <ReportPage />
</Route> </Route>

View File

@ -269,10 +269,6 @@
text-transform: uppercase; text-transform: uppercase;
} }
/* .specialists {
margin-left: 26px;
} */
.info__list { .info__list {
list-style: none; list-style: none;
margin-top: 110px; margin-top: 110px;

View File

@ -8,6 +8,140 @@ import rectangle from '../../images/rectangle_secondPage.png';
import Sidebar from '../Sidebar/Sidebar'; import Sidebar from '../Sidebar/Sidebar';
import SectionSkills from './SectionSkills'; import SectionSkills from './SectionSkills';
// const Candidate = () => {
// const history = useHistory();
// const { id: candidateId } = useParams();
// const dispatch = useDispatch();
// const candidatesArr = useSelector(selectCandidates);
// dispatch(currentCandidate(candidatesArr.find((el) => Number(el.id) === Number(candidateId))));
// const currentCandidateObj = useSelector(selectCurrentCandidate);
// console.log('currentCandidateObj ', currentCandidateObj);
// const { name, skillsName, img, skills, text } = currentCandidateObj;
// let classes;
// if (skillsName === 'Backend') {
// classes = style.back;
// console.log(classes);
// } else if (skillsName === 'Design') {
// classes = style.des;
// } else if (skillsName === 'Frontend') {
// classes = style.front;
// }
// return (
// <section className={style.candidate}>
// <div className="container">
// <div className="row">
// <div className="col-12">
// <div className={style.candidate__title}>
// <h2>
// <span>Аутстаффинг</span> it-персонала
// </h2>
// </div>
// </div>
// </div>
// <div className="row">
// <div className="col-12">
// <div className={style.candidate__header}>
// <div className={style.arrow} onClick={() => history.push('/')}>
// <div className={style.arrow__img}>
// <img src={arrow} alt="" />
// </div>
// <div className={style.arrow__sp}>
// <span>Вернуться к списку</span>
// </div>
// </div>
// <div className={style.icon}>
// <h3>{skillsName}</h3>
// <img className={classes} src={img} alt="" />
// </div>
// </div>
// </div>
// </div>
// <div className={style.candidate__main}>
// <div className="row">
// <div className="col-12 col-xl-4">
// <Sidebar />
// </div>
// <div className="col-12 col-xl-8">
// <div className={style.candidate__main__description}>
// <h2>{name}</h2>
// <img src={rectangle} alt="" />
// <p className={style.hashtag}># Описание опыта</p>
// <div className={style.SectionOne}>
// <h3>SVM - сервис выездных менеджеров для банка ПСБ</h3>
// <p>
// Приложение, которое позволяет управлять работой т.н. выездных менеджеров (ВМ). Банк предоставляет их
// услуги своим (потенциальным или реальным) клиентам, позволяя подключать расчетно-кассовое
// обслуживание или регистрировать свой бизнес. Клиенту не нужно приходить в отделение/офис банка - все
// необходимые бумаги ВМ подготовит заранее и принесет на согласование и подпись в удобное ему (клиент)
// время и место.
// </p>
// <h4>Senior PHP/JS Developer</h4>
// </div>
// <p className={style.hashtag}># Средства и инструменты:</p>
// <div className={style.SectionTwo}>
// <p>
// - Разработал и внедрил веб приложения, а также программное обеспечение с использованием Node.js,
// MySQL, JavaScript, HTML, CSS, React.js и Vue.JS. - Поддерживал существующий веб-сайт на базе PHP.
// Перевел существующую платформу с Laravel на современную архитектуру React/Redux и Node.
// </p>
// <p>
// - Проектировал и разрабатывал компоненты пользовательского интерфейса с использованием HTML, CSS и
// JavaScript. - Повысил скорость загрузки веб-сайта и время безотказной работы за счете переписывания
// всех основных компонентов и внедрения новой архетиктуры. - Разработал персональное APIs.
// </p>
// </div>
// <p className={style.hashtag}># Описание опыта</p>
// <div className={style.SectionThree}>
// <h3>Multitur - личный кабинет для сервиса поиска/подбора отелей</h3>
// <p>
// Личный кабинет для сотрудников отелей, который позволяет управлять информацией по отелю на сайте.
// </p>
// <h4>Senior PHP/JS Developer</h4>
// </div>
// <div className={style.SectionFour}>
// <p className={style.hashtag}># Средства и инструменты:</p>
// <p>Backend - REST API на PHP 7.1 с использованием фреймворка Laravel 5.8</p>
// <p>Frontend - Vue.js</p>
// <p>БД - MYSQL</p>
// </div>
// <p className={style.hashtag}># Функционал:</p>
// <>
// <div className={style.SectionFive}>
// <p>Регистрации/авторизации;</p>
// <p>Управления правами менеджеров отеля, назначение поставщиков</p>
// <p>Управления описанием и профилем отелей;</p>
// <p>Управления финансами, ценообразованием, квотами;</p>
// <p>Переписки со своими менеджерами, а также с вышестоящими инстанциями;</p>
// <p>Управления новостями отеля;</p>
// <p>Просмотра расширенной статистики по заявкам и людям;</p>
// </div>
// <button type="submit" className={style.SectionFive__btn}>
// Выбрать к собеседованию
// </button>
// </>
// <SectionSkills skillsArr={skills} />
// </div>
// </div>
// </div>
// </div>
// </div>
// </section>
// );
// };
// export default Candidate;
//////////////////////////////////////////////////
const Candidate = () => { const Candidate = () => {
const history = useHistory(); const history = useHistory();
const { id: candidateId } = useParams(); const { id: candidateId } = useParams();
@ -18,7 +152,9 @@ const Candidate = () => {
dispatch(currentCandidate(candidatesArr.find((el) => Number(el.id) === Number(candidateId)))); dispatch(currentCandidate(candidatesArr.find((el) => Number(el.id) === Number(candidateId))));
const currentCandidateObj = useSelector(selectCurrentCandidate); const currentCandidateObj = useSelector(selectCurrentCandidate);
const { name, skillsName, img, skills } = currentCandidateObj; console.log('currentCandidateObj ', currentCandidateObj);
const { name, skillsName, img, skills, text } = currentCandidateObj;
let classes; let classes;
@ -31,6 +167,10 @@ const Candidate = () => {
classes = style.front; classes = style.front;
} }
function createMarkup(text) {
return { __html: text.split('</p>').join('</p>') };
}
return ( return (
<section className={style.candidate}> <section className={style.candidate}>
<div className="container"> <div className="container">
@ -73,59 +213,14 @@ const Candidate = () => {
<h2>{name}</h2> <h2>{name}</h2>
<img src={rectangle} alt="" /> <img src={rectangle} alt="" />
<p className={style.hashtag}># Описание опыта</p> <p className={style.hashtag}># Описание опыта</p>
<div className={style.SectionOne}> {text ? (
<h3>SVM - сервис выездных менеджеров для банка ПСБ</h3> <div className={style.candidate__text} dangerouslySetInnerHTML={createMarkup(text)}></div>
<p> ) : (
Приложение, которое позволяет управлять работой т.н. выездных менеджеров (ВМ). Банк предоставляет их <p className={style.candidate__textSecondary}>Описание отсутствует...</p>
услуги своим (потенциальным или реальным) клиентам, позволяя подключать расчетно-кассовое )}
обслуживание или регистрировать свой бизнес. Клиенту не нужно приходить в отделение/офис банка - все
необходимые бумаги ВМ подготовит заранее и принесет на согласование и подпись в удобное ему (клиент)
время и место.
</p>
<h4>Senior PHP/JS Developer</h4>
</div>
<p className={style.hashtag}># Средства и инструменты:</p>
<div className={style.SectionTwo}>
<p>
- Разработал и внедрил веб приложения, а также программное обеспечение с использованием Node.js,
MySQL, JavaScript, HTML, CSS, React.js и Vue.JS. - Поддерживал существующий веб-сайт на базе PHP.
Перевел существующую платформу с Laravel на современную архитектуру React/Redux и Node.
</p>
<p>
- Проектировал и разрабатывал компоненты пользовательского интерфейса с использованием HTML, CSS и
JavaScript. - Повысил скорость загрузки веб-сайта и время безотказной работы за счете переписывания
всех основных компонентов и внедрения новой архетиктуры. - Разработал персональное APIs.
</p>
</div>
<p className={style.hashtag}># Описание опыта</p>
<div className={style.SectionThree}>
<h3>Multitur - личный кабинет для сервиса поиска/подбора отелей</h3>
<p>
Личный кабинет для сотрудников отелей, который позволяет управлять информацией по отелю на сайте.
</p>
<h4>Senior PHP/JS Developer</h4>
</div>
<div className={style.SectionFour}>
<p className={style.hashtag}># Средства и инструменты:</p>
<p>Backend - REST API на PHP 7.1 с использованием фреймворка Laravel 5.8</p>
<p>Frontend - Vue.js</p>
<p>БД - MYSQL</p>
</div>
<p className={style.hashtag}># Функционал:</p>
<>
<div className={style.SectionFive}>
<p>Регистрации/авторизации;</p>
<p>Управления правами менеджеров отеля, назначение поставщиков</p>
<p>Управления описанием и профилем отелей;</p>
<p>Управления финансами, ценообразованием, квотами;</p>
<p>Переписки со своими менеджерами, а также с вышестоящими инстанциями;</p>
<p>Управления новостями отеля;</p>
<p>Просмотра расширенной статистики по заявкам и людям;</p>
</div>
<button type="submit" className={style.SectionFive__btn}> <button type="submit" className={style.SectionFive__btn}>
Выбрать к собеседованию Выбрать к собеседованию
</button> </button>
</>
<SectionSkills skillsArr={skills} /> <SectionSkills skillsArr={skills} />
</div> </div>
</div> </div>

View File

@ -340,3 +340,23 @@
text-align: left; text-align: left;
margin-left: 20px; margin-left: 20px;
} }
.candidate__text > p {
font-family: 'GT Eesti Pro Display';
font-size: 1.6em;
font-weight: 100;
font-style: normal;
letter-spacing: normal;
text-align: left;
}
.candidate__textSecondary {
font-family: 'GT Eesti Pro Display';
font-size: 1.6em;
font-weight: 100;
font-style: normal;
letter-spacing: normal;
line-height: 24px;
text-align: left;
line-height: 28px;
}

View File

@ -1,17 +1,84 @@
import React, { useState } from 'react'; import React from 'react';
import style from './Description.module.css'; import style from './Description.module.css';
import dog from '../../images/dog.jpg'; import dog from '../../images/dog.jpg';
import rectangle from '../../images/rectangle_secondPage.png'; import rectangle from '../../images/rectangle_secondPage.png';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { LEVELS } from '../constants/constants'; import { LEVELS } from '../constants/constants';
import { selectProfiles, selectFilteredCandidates } from '../../redux/outstaffingSlice';
import { useSelector } from 'react-redux';
const Description = ({ candidatesListArr, onLoadMore }) => { // const Description = ({ candidatesListArr, onLoadMore }) => {
const [text, setText] = useState([]); // function createMarkup(text) {
// return { __html: text.split('</p>').slice(0, 3).join('') };
// }
// return (
// <section className={style.description}>
// <div className="container">
// <div className={style.description__wrapper}>
// {candidatesListArr.map((el) => (
// <div className="row" key={el.id}>
// <div className="col-2">
// <img className={style.description__img} src={dog} alt="" />
// </div>
// <div className="col-12 col-xl-6">
// <h3 className={style.description__title}>
// {el.skillsName} разработчик, {LEVELS[el.level]}
// </h3>
// {el.text ? (
// <div className={style.description__text} dangerouslySetInnerHTML={createMarkup(el.text)}></div>
// ) : (
// <p className={style.description__textSecondary}>Описание отсутствует...</p>
// )}
// </div>
// <div className="col-12 col-xl-4">
// <Link to={`/candidate/${el.id}`}>
// <button className={style.description__button}>Подробное резюме</button>
// </Link>
// </div>
// <div className="col-xl-2"></div>
// <div className="col-12 col-xl-6">
// {el.skills.map((e) => (
// <span key={e.id} className={style.description__sp}>
// {e.skill.name}
// </span>
// ))}
// <img className={style.description__rectangle} src={rectangle} alt="" />
// </div>
// <div className="col-xl-4"></div>
// </div>
// ))}
// </div>
// <div className="row">
// <div className="col-12">
// <div className={style.description__footer}>
// <div className={style.description__footer__btn}>
// <button onClick={() => onLoadMore(2)}>Загрузить еще</button>
// </div>
// </div>
// </div>
// </div>
// </div>
// </section>
// );
// };
// export default Description;
const Description = ({ onLoadMore }) => {
const candidatesListArr = useSelector(selectProfiles);
const filteredListArr = useSelector(selectFilteredCandidates);
function createMarkup(text) {
return { __html: text.split('</p>').slice(0, 3).join('') };
}
return ( return (
<section className={style.description}> <section className={style.description}>
<div className="container"> <div className="container">
<div className={style.description__wrapper}> {/* <div className={style.description__wrapper}>
{candidatesListArr.map((el) => ( {candidatesListArr.map((el) => (
<div className="row" key={el.id}> <div className="row" key={el.id}>
<div className="col-2"> <div className="col-2">
@ -19,17 +86,11 @@ const Description = ({ candidatesListArr, onLoadMore }) => {
</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.skillsName} разработчик, {LEVELS[el.level]} {el.fio} разработчик, {LEVELS[el.level]}
</h3> </h3>
{text.length > 0 ? ( {el.vc_text ? (
<> <div className={style.description__text} dangerouslySetInnerHTML={createMarkup(el.vc_text)}></div>
<p className={style.description__text}>
- 10 лет пишу приложения под IOS, отлично владею Objective-C и Swift.
</p>
<p className={style.description__text}>- 5 лет руковожу командами мобильной разработки.</p>
<p className={style.description__text}>- 3 года преподаю в IOS-школе Сбера</p>
</>
) : ( ) : (
<p className={style.description__textSecondary}>Описание отсутствует...</p> <p className={style.description__textSecondary}>Описание отсутствует...</p>
)} )}
@ -41,7 +102,77 @@ const Description = ({ candidatesListArr, onLoadMore }) => {
</div> </div>
<div className="col-xl-2"></div> <div className="col-xl-2"></div>
<div className="col-12 col-xl-6"> <div className="col-12 col-xl-6">
{el.skills.map((e) => ( {el.skillValues.map((e) => (
<span key={e.id} className={style.description__sp}>
{e.skill.name}
</span>
))}
<img className={style.description__rectangle} src={rectangle} alt="" />
</div>
<div className="col-xl-4"></div>
</div>
))}
</div> */}
<div className={style.description__wrapper}>
{filteredListArr && filteredListArr.length > 0
? filteredListArr.map((el) => (
<div className="row" key={el.id}>
<div className="col-2">
<img className={style.description__img} src={dog} alt="" />
</div>
<div className="col-12 col-xl-6">
<h3 className={style.description__title}>
{el.fio} разработчик, {LEVELS[el.level]}
</h3>
{el.vc_text ? (
<div className={style.description__text} dangerouslySetInnerHTML={createMarkup(el.vc_text)}></div>
) : (
<p className={style.description__textSecondary}>Описание отсутствует...</p>
)}
</div>
<div className="col-12 col-xl-4">
<Link to={`/candidate/${el.id}`}>
<button className={style.description__button}>Подробное резюме</button>
</Link>
</div>
<div className="col-xl-2"></div>
<div className="col-12 col-xl-6">
{el.skillValues.map((e) => (
<span key={e.id} className={style.description__sp}>
{e.skill.name}
</span>
))}
<img className={style.description__rectangle} src={rectangle} alt="" />
</div>
<div className="col-xl-4"></div>
</div>
))
: candidatesListArr.map((el) => (
<div className="row" key={el.id}>
<div className="col-2">
<img className={style.description__img} src={dog} alt="" />
</div>
<div className="col-12 col-xl-6">
<h3 className={style.description__title}>
{el.fio} разработчик, {LEVELS[el.level]}
</h3>
{el.vc_text ? (
<div className={style.description__text} dangerouslySetInnerHTML={createMarkup(el.vc_text)}></div>
) : (
<p className={style.description__textSecondary}>Описание отсутствует...</p>
)}
</div>
<div className="col-12 col-xl-4">
<Link to={`/candidate/${el.id}`}>
<button className={style.description__button}>Подробное резюме</button>
</Link>
</div>
<div className="col-xl-2"></div>
<div className="col-12 col-xl-6">
{el.skillValues.map((e) => (
<span key={e.id} className={style.description__sp}> <span key={e.id} className={style.description__sp}>
{e.skill.name} {e.skill.name}
</span> </span>
@ -59,15 +190,6 @@ const Description = ({ candidatesListArr, onLoadMore }) => {
<div className={style.description__footer__btn}> <div className={style.description__footer__btn}>
<button onClick={() => onLoadMore(2)}>Загрузить еще</button> <button onClick={() => onLoadMore(2)}>Загрузить еще</button>
</div> </div>
{/* <div className={style.description__footer__box}>
<div className={style.arrow__left}>
<img src={arrowLeft} alt="" />
</div>
<span className={style.description__footer__sp}>1 / 15</span>
<div className={style.arrow__right}>
<img src={arrowRight} alt="" />
</div>
</div> */}
</div> </div>
</div> </div>
</div> </div>

View File

@ -73,9 +73,9 @@
} }
} }
.description__text { .description__text > p {
font-family: 'GT Eesti Pro Display'; font-family: 'GT Eesti Pro Display';
font-size: 1.7em; font-size: 1.6em;
font-weight: 100; font-weight: 100;
font-style: normal; font-style: normal;
letter-spacing: normal; letter-spacing: normal;
@ -84,6 +84,10 @@
line-height: 28px; line-height: 28px;
} }
.description__text > p:first-child {
font-size: 1.8em;
}
.description__textSecondary { .description__textSecondary {
font-family: 'GT Eesti Pro Display'; font-family: 'GT Eesti Pro Display';
font-size: 1.7em; font-size: 1.7em;
@ -148,7 +152,6 @@
} }
.description__sp { .description__sp {
/* display: block; */
font-family: 'GT Eesti Pro Display'; font-family: 'GT Eesti Pro Display';
font-size: 1.7em; font-size: 1.7em;
font-weight: 400; font-weight: 400;
@ -225,34 +228,3 @@
text-align: center; text-align: center;
margin: 0 10px; margin: 0 10px;
} }
.arrow__left {
position: relative;
width: 30px;
height: 30px;
border-radius: 20px;
background-color: #f6f6f6;
cursor: pointer;
}
.arrow__left > img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.arrow__right {
position: relative;
width: 30px;
height: 30px;
border-radius: 20px;
background-color: #74be4d;
cursor: pointer;
}
.arrow__right > img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

View File

@ -0,0 +1,69 @@
import React, { useState } from 'react';
import style from './Form.module.css';
import { fetchForm } from '../../server/server';
const Form = () => {
const [email, setEmail] = useState('');
const [phone, setPhone] = useState('');
const [comment, setСomment] = useState('');
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
if (name === 'Email') {
setEmail(value);
} else if (name === 'Phone') {
setPhone(value);
} else if (name === 'Comment') {
setСomment(value);
} else {
return;
}
};
const handleSubmit = (e) => {
e.preventDefault();
const info = {
email: email,
phone: phone,
comment: comment,
};
fetchForm('https://guild.craft-group.xyz/api/profile/add-to-interview', info).then((el) =>
el.json().then((e) => console.log('object ', e))
);
};
return (
<div className="container">
<div className="row">
<div className="col-sm-12">
<form className={style.form}>
<label htmlFor="email">Емейл:</label>
<input onChange={handleChange} id="email" name="Email" type="email" placeholder="Емейл" value={email} />
<label htmlFor="phone">Номер телефона:</label>
<input onChange={handleChange} id="phone" type="number" name="Phone" placeholder="Телефон" value={phone} />
<textarea
onChange={handleChange}
rows="5"
cols="40"
name="Comment"
placeholder="Оставьте комментарий"
value={comment}
></textarea>
<button onClick={handleSubmit} className={style.form__btn} type="submit">
Отправить
</button>
</form>
</div>
</div>
</div>
);
};
export default Form;

View File

@ -0,0 +1,84 @@
.form {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 180px;
}
.form > label {
color: #48802d;
font-family: 'GT Eesti Pro Display';
font-size: 2.4em;
font-weight: 500;
font-style: normal;
letter-spacing: normal;
line-height: 16.81px;
text-align: left;
margin-bottom: 20px;
margin-left: 45px;
}
.form > input {
max-width: 366px;
height: 75px;
box-shadow: 0 0 59px rgba(44, 44, 44, 0.05);
border-radius: 37px;
border: 1px solid #c4c4c4;
background-color: #ffffff;
margin-bottom: 60px;
color: #a6a6a6;
font-family: 'GT Eesti Pro Display';
font-size: 2.2em;
font-weight: 300;
font-style: normal;
letter-spacing: normal;
line-height: normal;
text-align: left;
padding-left: 45px;
outline: none;
}
.form > textarea {
max-width: 366px;
height: 75px;
margin-bottom: 40px;
box-shadow: 0 0 59px rgba(44, 44, 44, 0.05);
border-radius: 37px;
border: 1px solid #c4c4c4;
background-color: #ffffff;
margin-bottom: 60px;
color: #a6a6a6;
font-family: 'GT Eesti Pro Display';
font-size: 1.2em;
font-weight: 300;
font-style: normal;
letter-spacing: normal;
line-height: normal;
text-align: left;
padding-left: 25px;
padding-top: 25px;
outline: none;
}
.form__btn {
width: 288px;
height: 75px;
box-shadow: 6px 5px 20px rgba(82, 151, 34, 0.21);
border-radius: 38px;
background-color: #ffffff;
background-image: linear-gradient(to top, #6aaf5c 0%, #52b709 100%),
linear-gradient(
36deg,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.16) 47%,
rgba(255, 255, 255, 0.17) 50%,
rgba(255, 255, 255, 0) 100%
);
border: none;
color: #ffffff;
font-family: 'Muller';
font-size: 2.2em;
letter-spacing: normal;
line-height: 71.88px;
text-align: center;
}

View File

@ -6,7 +6,8 @@ import { fetchProfile, fetchSkills } from '../../server/server';
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 { profiles, selectProfiles, tags, candidates, selectCandidates, selectTab } from '../../redux/outstaffingSlice'; // import { profiles, selectProfiles, tags, candidates, selectCandidates, selectTab } from '../../redux/outstaffingSlice';
import { profiles, selectProfiles, tags, candidates } from '../../redux/outstaffingSlice';
const Home = () => { const Home = () => {
const [index, setIndex] = useState(2); const [index, setIndex] = useState(2);
@ -14,9 +15,9 @@ const Home = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const profilesArr = useSelector(selectProfiles); const profilesArr = useSelector(selectProfiles);
const candidatesArr = useSelector(selectCandidates); // const candidatesArr = useSelector(selectCandidates);
const selectedTab = useSelector(selectTab); // const selectedTab = useSelector(selectTab);
useEffect(() => { useEffect(() => {
fetchProfile(`https://guild.craft-group.xyz/api/profile?limit=`, index) fetchProfile(`https://guild.craft-group.xyz/api/profile?limit=`, index)
@ -61,6 +62,7 @@ const Home = () => {
name: profile.fio, name: profile.fio,
skills: profile.skillValues, skills: profile.skillValues,
level: profile.level, level: profile.level,
text: profile.vc_text,
skillsName, skillsName,
header, header,
img, img,
@ -77,12 +79,13 @@ const Home = () => {
return ( return (
<> <>
<Outstaffing /> <Outstaffing />
<Description {/* <Description
candidatesListArr={ candidatesListArr={
selectedTab ? candidatesArr.filter((item) => item.skillsName === selectedTab) : candidatesArr selectedTab ? candidatesArr.filter((item) => item.skillsName === selectedTab) : candidatesArr
} }
onLoadMore={loadMore} onLoadMore={loadMore}
/> /> */}
<Description onLoadMore={loadMore} />
</> </>
); );
}; };

View File

@ -52,7 +52,7 @@ const Outstaffing = () => {
dataTags={tagsArr.flat().filter((tag) => tag.name === 'skills_design')} dataTags={tagsArr.flat().filter((tag) => tag.name === 'skills_design')}
selected={selected === 'Marketer'} selected={selected === 'Marketer'}
img={design} img={design}
header="Маркетинг" header="Дизайн"
/> />
</div> </div>
</div> </div>

View File

@ -10,9 +10,9 @@ const OutstaffingBlock = ({ dataTags = [], data = {}, selected, img, header }) =
const { skillsName } = data; const { skillsName } = data;
const handleBlockClick = (item) => { const handleBlockClick = (item, id) => {
if (!itemsArr.find((el) => item === el.value)) { if (!itemsArr.find((el) => item === el.value)) {
dispatch(selectedItems([...itemsArr, { value: item, label: item }])); dispatch(selectedItems([...itemsArr, { id, value: item, label: item }]));
} }
}; };
@ -42,7 +42,7 @@ const OutstaffingBlock = ({ dataTags = [], data = {}, selected, img, header }) =
{dataTags && ( {dataTags && (
<ul className={style.items}> <ul className={style.items}>
{dataTags.map((item) => ( {dataTags.map((item) => (
<li key={item.id} onClick={() => handleBlockClick(item.value)}> <li key={item.id} onClick={() => handleBlockClick(item.value, item.id)}>
{item.value} {item.value}
</li> </li>
))} ))}

View File

@ -2,7 +2,8 @@ import React from 'react';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import Select from 'react-select'; import Select from 'react-select';
import style from './TagSelect.module.css'; import style from './TagSelect.module.css';
import { selectedItems, selectItems, selectTags } from '../../redux/outstaffingSlice'; import { selectedItems, selectItems, selectTags, filteredCandidates } from '../../redux/outstaffingSlice';
import { fetchItemsForId } from '../../server/server';
const TagSelect = () => { const TagSelect = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -12,9 +13,11 @@ const TagSelect = () => {
const tagsArr = useSelector(selectTags); const tagsArr = useSelector(selectTags);
const handleSubmit = () => { const handleSubmit = () => {
const filterItems = JSON.stringify(itemsArr.map((item) => item.value)); const filterItemsId = itemsArr.map((item) => item.id).join();
alert(`Back-end: ${filterItems}`); fetchItemsForId('https://guild.craft-group.xyz/api/profile?skills=', filterItemsId).then((el) =>
dispatch(filteredCandidates(el))
);
dispatch(selectedItems([])); dispatch(selectedItems([]));
}; };
@ -35,7 +38,7 @@ const TagSelect = () => {
className={style.select} className={style.select}
classNamePrefix={style.select} classNamePrefix={style.select}
options={tagsArr.flat().map((item) => { options={tagsArr.flat().map((item) => {
return { value: item.value, label: item.value }; return { id: item.id, value: item.value, label: item.value };
})} })}
/> />
<button onClick={handleSubmit} type="submit"> <button onClick={handleSubmit} type="submit">

View File

@ -10,21 +10,10 @@ const Sidebar = () => {
<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={`/form`}>
<button className={style.candidateSidebar__info__btn}>Выбрать к собеседованию</button> <button className={style.candidateSidebar__info__btn}>Выбрать к собеседованию</button>
</Link> </Link>
{/* <p className={style.candidateSidebar__info__l}>Посмотреть ещё</p> */}
</div> </div>
{/* <div className={style.candidateSidebar__arrows}>
<div className={style.arrow__left}>
<img src={arrowLeft} alt="" />
</div>
<span className={style.arrows__sp}>1 / 15</span>
<div className={style.arrow__right}>
<img src={arrowRight} alt="" />
</div>
</div> */}
</div> </div>
); );
}; };

6
src/pages/FormPage.js Normal file
View File

@ -0,0 +1,6 @@
import React from 'react';
import Form from '../components/Form/Form';
const FormPage = () => <Form />;
export default FormPage;

View File

@ -4,6 +4,7 @@ const initialState = {
tags: [], tags: [],
profiles: [], profiles: [],
candidates: [], candidates: [],
filteredCandidates: [],
selectedItems: [], selectedItems: [],
selectedTab: '', selectedTab: '',
currentCandidate: {}, currentCandidate: {},
@ -23,6 +24,9 @@ export const outstaffingSlice = createSlice({
candidates: (state, action) => { candidates: (state, action) => {
state.candidates = action.payload; state.candidates = action.payload;
}, },
filteredCandidates: (state, action) => {
state.filteredCandidates = action.payload;
},
selectedTab: (state, action) => { selectedTab: (state, action) => {
state.selectedTab = action.payload; state.selectedTab = action.payload;
}, },
@ -38,12 +42,13 @@ export const outstaffingSlice = createSlice({
}, },
}); });
export const { tags, profiles, candidates, selectedTab, selectedItems, auth, currentCandidate } = export const { tags, profiles, candidates, selectedTab, selectedItems, auth, currentCandidate, filteredCandidates } =
outstaffingSlice.actions; outstaffingSlice.actions;
export const selectProfiles = (state) => state.outstaffing.profiles; export const selectProfiles = (state) => state.outstaffing.profiles;
export const selectTags = (state) => state.outstaffing.tags; export const selectTags = (state) => state.outstaffing.tags;
export const selectCandidates = (state) => state.outstaffing.candidates; export const selectCandidates = (state) => state.outstaffing.candidates;
export const selectFilteredCandidates = (state) => state.outstaffing.filteredCandidates;
export const selectTab = (state) => state.outstaffing.selectedTab; export const selectTab = (state) => state.outstaffing.selectedTab;
export const selectItems = (state) => state.outstaffing.selectedItems; export const selectItems = (state) => state.outstaffing.selectedItems;
export const selectCurrentCandidate = (state) => state.outstaffing.currentCandidate; export const selectCurrentCandidate = (state) => state.outstaffing.currentCandidate;

View File

@ -2,6 +2,8 @@ export const fetchProfile = async (link, index) => {
const response = await fetch(`${link}${index}`); const response = await fetch(`${link}${index}`);
let data = await response.json(); let data = await response.json();
console.log('data ', data);
return data; return data;
}; };
@ -11,3 +13,22 @@ export const fetchSkills = async (link) => {
return data; return data;
}; };
export const fetchItemsForId = async (link, id) => {
const response = await fetch(`${link}${id}`);
let data = await response.json();
return data;
};
export const fetchForm = async (link, info) => {
const response = await fetch(link, {
method: 'POST',
body: JSON.stringify(info),
headers: {
'Content-Type': 'application/json',
},
});
return response;
};