Merge pull request #28 from apuc/authentication

interview page and design fixes
This commit is contained in:
kavalar 2021-08-18 15:57:25 +03:00 committed by GitHub
commit be7c689ccd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 271 additions and 79 deletions

19
package-lock.json generated
View File

@ -6395,6 +6395,11 @@
"strip-eof": "^1.0.0"
}
},
"exenv": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
"integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50="
},
"exit": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
@ -12801,6 +12806,20 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz",
"integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew=="
},
"react-from-dom": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/react-from-dom/-/react-from-dom-0.6.1.tgz",
"integrity": "sha512-7aAZx7LhRnmR51W5XtmTBYHGFl2n1AdEk1uoXLuzHa1OoGXrxOW/iwLcudvgp6BGX/l4Yh1rtMrIzvhlvbVddg=="
},
"react-inlinesvg": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/react-inlinesvg/-/react-inlinesvg-2.3.0.tgz",
"integrity": "sha512-fEGOdDf4k4bcveArbEpj01pJcH8pOCKLxmSj2POFdGvEk5YK0NZVnH6BXpW/PzACHPRsuh1YKAhNZyFnD28oxg==",
"requires": {
"exenv": "^1.2.2",
"react-from-dom": "^0.6.0"
}
},
"react-input-autosize": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz",

View File

@ -16,6 +16,7 @@
"react": "^17.0.2",
"react-bootstrap": "^1.6.0",
"react-dom": "^17.0.2",
"react-inlinesvg": "^2.3.0",
"react-loader-spinner": "^4.0.0",
"react-outside-click-handler": "^1.3.0",
"react-phone-input-2": "^2.14.0",

View File

@ -23,7 +23,6 @@ const Calendar = () => {
return (
<section className={style.calendar}>
<div className="container">
<div className="row">
<h2 className={style.calendar__title}>
Добрый день, <span>Александр !</span>
@ -53,7 +52,6 @@ const Calendar = () => {
</p>
</div>
</div>
</div>
</section>
);
};

View File

@ -2,7 +2,6 @@ import React, { useEffect } from 'react';
import { useHistory, useParams, Link } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import { currentCandidate, selectCurrentCandidate } from '../../redux/outstaffingSlice';
import style from './Candidate.module.css';
import arrow from '../../images/right-arrow.png';
import rectangle from '../../images/rectangle_secondPage.png';
import Sidebar from '../Sidebar/Sidebar';
@ -12,11 +11,17 @@ import back from '../../images/back_end.png';
import design from '../../images/design.png';
import { fetchItemsForId } from '../../server/server';
import './candidate.css';
const Candidate = () => {
const history = useHistory();
const { id: candidateId } = useParams();
const dispatch = useDispatch();
useEffect(() => {
window.scrollTo(0, 0)
}, [])
useEffect(() => {
fetchItemsForId(`${process.env.REACT_APP_API_URL}/api/profile/`, Number(candidateId)).then((el) =>
dispatch(currentCandidate(el))
@ -36,22 +41,22 @@ const Candidate = () => {
switch (Number(position_id)) {
case 1: {
styles.classes = style.back;
styles.classes = 'back';
styles.header = 'Backend';
styles.img = back;
break;
}
case 2: {
styles.classes = style.des;
styles.classes = 'des';
styles.header = 'Frontend';
styles.img = front;
break;
}
case 3: {
style.classes = style.front;
style.header = 'Design';
style.img = design;
styles.classes = 'front';
styles.header = 'Design';
styles.img = design;
break;
}
default:
@ -68,11 +73,10 @@ const Candidate = () => {
const { header, img, classes } = setStyles();
return (
<section className={style.candidate}>
<div className="container">
<div className='candidate'>
<div className="row">
<div className="col-12">
<div className={style.candidate__title}>
<div className='candidate__title'>
<h2>
<span>Аутстаффинг</span> it-персонала
</h2>
@ -82,41 +86,41 @@ const Candidate = () => {
<div className="row">
<div className="col-12">
<div className={style.candidate__header}>
<div className={style.arrow} onClick={() => history.push('/')}>
<div className={style.arrow__img}>
<div className='candidate__header'>
<div className='arrow' onClick={() => history.push('/')}>
<div className='arrow__img'>
<img src={arrow} alt="" />
</div>
<div className={style.arrow__sp}>
<div className='arrow__sp'>
<span>Вернуться к списку</span>
</div>
</div>
<div className={style.icon}>
<div className='icon'>
<h3>{header}</h3>
<img className={classes} src={img} alt="" />
</div>
</div>
</div>
</div>
<div className={style.candidate__main}>
<div className='candidate__main'>
<div className="row">
<div className="col-12 col-xl-4">
<Sidebar candidate={currentCandidateObj} />
</div>
<div className="col-12 col-xl-8">
<div className={style.candidate__main__description}>
<div className='candidate__main__description'>
<img src={rectangle} alt="" />
<p className={style.hashtag}># Описание опыта</p>
<p className='hashtag'># Описание опыта</p>
{text ? (
<div className={style.candidate__text} dangerouslySetInnerHTML={createMarkup(text)}></div>
<div className='candidate__text' dangerouslySetInnerHTML={createMarkup(text)}></div>
) : (
<p className={style.candidate__textSecondary}>
<p className='candidate__textSecondary'>
{currentCandidateObj.vc_text ? currentCandidateObj.vc_text : 'Описание отсутствует...' }
</p>
)}
<Link to={`/candidate/${currentCandidateObj.id}/form`}>
<button type="submit" className={style.candidate__btn}>
<button type="submit" className='candidate__btn'>
Выбрать к собеседованию
</button>
</Link>
@ -125,8 +129,7 @@ const Candidate = () => {
</div>
</div>
</div>
</div>
</section>
</div>
);
};

View File

@ -1,9 +1,9 @@
import React from 'react';
import style from './Candidate.module.css';
import './candidate.css';
const SectionSkills = ({ skillsArr }) => {
return (
<div className={style.SectionSkills}>
<div className='SectionSkills'>
<h3>Навыки:</h3>
<ul>{skillsArr && skillsArr.map((skills) => <li key={skills.id}>{skills.skill.name}</li>)}</ul>
</div>

View File

@ -277,3 +277,7 @@
text-align: left;
line-height: 28px;
}
.candidate + .logout-button{
top: 80px !important;
}

View File

@ -154,7 +154,7 @@
}
.description__list {
padding: 5px;
padding: 0;
list-style: none;
display: flex;
flex-wrap: wrap;
@ -168,7 +168,7 @@
letter-spacing: normal;
text-align: left;
line-height: 36px;
margin-left: 10px;
margin-right: 10px;
word-wrap: break-word;
}

View File

@ -1,7 +1,6 @@
import React, { useState } from 'react';
import style from './Form.module.css';
import { fetchForm } from '../../server/server';
import arrow from '../../images/right-arrow.png';
import { useHistory, useParams, Redirect } from 'react-router-dom';
import PhoneInput from 'react-phone-input-2'
import 'react-phone-input-2/lib/style.css'
@ -49,14 +48,12 @@ const Form = () => {
)
};
const goBack = () => {
history.goBack();
};
console.log('s',status)
return (
<div className="container">
<>
{status && <SweetAlert
show={!!status}
text={status.errors ? status.errors[Object.keys(status.errors)[0]] : 'Форма отправлена'}
@ -64,14 +61,6 @@ const Form = () => {
/>}
<div className="row">
<div className="col-sm-12">
<div className={style.form__arrow} onClick={() => goBack()}>
<div className={style.form__arrow__img}>
<img src={arrow} alt="" />
</div>
<div className={style.form__arrow__sp}>
<span>Вернуться к кандидату</span>
</div>
</div>
<form className={style.form} id="test">
<label htmlFor="email">Емейл:</label>
<input
@ -116,7 +105,7 @@ const Form = () => {
</form>
</div>
</div>
</div>
</>
);
};

View File

@ -19,7 +19,7 @@
.form > input {
max-width: 366px;
height: 75px;
height: 62px;
box-shadow: 0 0 59px rgba(44, 44, 44, 0.05);
border-radius: 37px;
border: 1px solid #c4c4c4;
@ -39,7 +39,7 @@
.form > textarea {
max-width: 366px;
height: 75px;
height: 62px;
margin-bottom: 40px;
box-shadow: 0 0 59px rgba(44, 44, 44, 0.05);
border-radius: 37px;
@ -64,7 +64,7 @@ textarea {
}
.form__btn {
width: 288px;
width: 332px;
height: 75px;
box-shadow: 6px 5px 20px rgba(82, 151, 34, 0.21);
border-radius: 38px;
@ -86,12 +86,7 @@ textarea {
text-align: center;
}
.form__arrow {
display: flex;
justify-content: flex-start;
align-items: center;
margin-top: 80px;
}
@media (max-width: 575.98px) {
.form__arrow {
@ -99,21 +94,7 @@ textarea {
}
}
.form__arrow__img > img {
cursor: pointer;
}
.form__arrow__sp > span {
margin-left: 40px;
margin-right: 120px;
font-family: 'GT Eesti Pro Display';
font-size: 1.8em;
font-weight: 100;
font-style: normal;
letter-spacing: normal;
line-height: 36px;
text-align: left;
}
@media (max-width: 575.98px) {
.form__arrow__sp > span {

View File

@ -1,5 +1,5 @@
.logout-button {
position: fixed;
position: absolute;
top: 70px;
right: 2.5rem;
z-index: 100;

View File

@ -27,7 +27,6 @@ const Outstaffing = () => {
return (
<>
<section className={style.outstaffing}>
<div className="container">
<div className="row">
<div className="col-12">
<div className={style.outstaffing__title}>
@ -43,7 +42,7 @@ const Outstaffing = () => {
<OutstaffingBlock
dataTags={tagsArr && tagsArr.flat().filter((tag) => tag.name === 'skills_front')}
img={front}
header="Фронтенд"
header="Frontend"
positionId='2'
isSelected={positionId==='2'}
onSelect={id=>onSelectPosition(id)}
@ -53,7 +52,7 @@ const Outstaffing = () => {
<OutstaffingBlock
dataTags={tagsArr.flat().filter((tag) => tag.name === 'skills_back')}
img={back}
header="Бэкенд"
header="Backend"
positionId='1'
isSelected={positionId==='1'}
onSelect={id=>onSelectPosition(id)}
@ -70,7 +69,6 @@ const Outstaffing = () => {
/>
</div>
</div>
</div>
</section>
<TagSelect />
</>

View File

@ -24,7 +24,6 @@ const ReportForm = () => {
return (
<section className="reportForm">
<div className="container">
<div className="row">
<div className="col-xl-12">
<div className={style.reportForm__block}>
@ -87,7 +86,6 @@ const ReportForm = () => {
</div>
</div>
</div>
</div>
</section>
);
};

View File

@ -30,7 +30,6 @@ const TagSelect = () => {
return (
<>
<section className={style.search}>
<div className="container">
<div className="row">
<div className="col-12">
<h2 className={style.search__title}>Найти специалиста по навыкам</h2>
@ -52,7 +51,6 @@ const TagSelect = () => {
</div>
</div>
</div>
</div>
</section>
</>
);

View File

@ -2,8 +2,10 @@ import React from 'react';
import { LogoutButton } from '../components/LogoutButton/LogoutButton';
export const WithLogout = (props) => {
return <>
<LogoutButton />
{props.children}
</>
return (
<div className='container'>
{props.children}
<LogoutButton />
</div>
)
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="55" height="55" viewBox="0 0 55 55"><g><g><image width="55" height="55" xlink:href="data:image/png;base64,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"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -22,3 +22,6 @@ h1 {
display: none;
}
.container {
position: relative !important;
}

View File

@ -1,7 +1,78 @@
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory, useParams, } from 'react-router-dom';
import { currentCandidate, selectCurrentCandidate } from '../redux/outstaffingSlice';
import SVG from 'react-inlinesvg';
import { WithLogout } from '../hoc/withLogout';
import Form from '../components/Form/Form';
import { LEVELS, SKILLS } from '../components/constants/constants';
import { fetchItemsForId } from '../server/server';
const FormPage = () => <WithLogout><Form /></WithLogout>;
import arrow from '../images/right-arrow.png';
import rectangle from '../images/rectangle_secondPage.png';
import telegramIcon from '../images/telegram-icon.svg';
import './formPage.scss';
const goBack = (history) => {
history.goBack();
};
const FormPage = () => {
const params = useParams();
const history = useHistory();
const dispatch = useDispatch();
const candidate = useSelector(selectCurrentCandidate)
if(!candidate.id) {
fetchItemsForId(`${process.env.REACT_APP_API_URL}/api/profile/`, Number(params.id)).then((el) =>
dispatch(currentCandidate(el))
);
}
return (
<WithLogout>
<div className='form-page'>
<div className='form-page__back'>
<div className='form-page__arrow' onClick={() => goBack(history)}>
<div className='form-page__arrow-img'>
<img src={arrow} alt="" />
</div>
<div className='form-page__back-to-candidate'>
<span>Вернуться к кандидату</span>
</div>
</div>
</div>
<div className='form-page__candidate'>
<div className='form-page__avatar'>
<img src={candidate.photo} />
</div>
<div className='form-page__candidate-info'>
<div className='form-page__position'>
<span>{candidate.specification} {SKILLS[candidate.position_id]}, {LEVELS[candidate.level]}</span>
</div>
<div className='form-page__selected'>
<img src={rectangle} />
<span>Выбранный кандидат</span>
</div>
</div>
</div>
<div className='form-page__interview'>
<div className='form-page__form'><Form /></div>
<div className='form-page__separator'>
<div className='form-page__line'></div>
<div className='form-page__option'>или</div>
</div>
<div className='form-page__telegram'>
<div className='form-page__telegram-text'>Заявка на собеседование через телеграм</div>
<div className='form-page__telegram-icon'>
<SVG src={telegramIcon} />
</div>
</div>
</div>
</div>
</WithLogout>
)
}
export default FormPage;

126
src/pages/formPage.scss Normal file
View File

@ -0,0 +1,126 @@
.form-page {
&__arrow {
display: flex;
justify-content: flex-start;
align-items: center;
margin-top: 80px;
margin-left: -32px;
&-img {
cursor: pointer;
}
}
&__candidate {
margin-top: 60px;
margin-left: 48px;
display: flex;
}
&__back-to-candidate {
margin-left: 40px;
margin-right: 120px;
font-family: 'GT Eesti Pro Display';
font-size: 1.8em;
font-weight: 100;
line-height: 36px;
}
&__avatar {
img {
width: 61px;
height: 61px;
}
margin-right: 16px;
}
&__position {
color: #000000;
font-family: "GT Eesti Pro Display";
font-size: 22px;
font-weight: 700;
line-height: 36px;
}
&__selected {
span {
color: #000000;
font-family: "GT Eesti Pro Display";
font-size: 10px;
font-weight: 300;
line-height: 22.38px;
}
img {
width: 152px;
margin-right: 18px;
}
}
&__interview {
display: flex;
justify-content: center;
align-items: center;
}
&__form {
width: 45%;
}
&__separator {
width: 10%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
&__line {
width: 3px;
height: 135px;
background-color: #e4f1f6;
margin-bottom: 26px;
}
&__option {
color: #000000;
font-family: "GT Eesti Pro Display";
font-size: 18px;
font-weight: 400;
font-style: normal;
letter-spacing: normal;
line-height: 36px;
text-align: center;
font-style: normal;
letter-spacing: normal;
line-height: normal;
}
&__telegram {
width: 45%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
&-text {
width: 225px;
color: #000000;
font-family: "GT Eesti Pro Display";
font-size: 18px;
font-weight: 400;
font-style: normal;
letter-spacing: normal;
line-height: 33px;
text-align: center;
font-style: normal;
letter-spacing: normal;
margin-bottom: 29px;
}
}
}
.form-page + .logout-button{
top: 0px !important;
right: 2.5rem;
}