Merge pull request #13 from apuc/authentication

Authentication
This commit is contained in:
kavalar 2021-08-11 17:50:15 +03:00 committed by GitHub
commit de67de276c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 104 additions and 11 deletions

27
package-lock.json generated
View File

@ -9946,6 +9946,11 @@
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
}, },
"lodash.pick": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
"integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM="
},
"lodash.template": { "lodash.template": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
@ -10358,6 +10363,11 @@
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
}, },
"mousetrap": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.5.tgz",
"integrity": "sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA=="
},
"move-concurrently": { "move-concurrently": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@ -14620,6 +14630,23 @@
"util.promisify": "~1.0.0" "util.promisify": "~1.0.0"
} }
}, },
"sweetalert2": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-8.19.0.tgz",
"integrity": "sha512-nFL++N3bitkEkd487Tv4i5ZxusmnoAAXHjtk7lp603Opxb8wlvVnz3hqa7qiIw6QFL04JC810E6qVQNf8s0vYQ=="
},
"sweetalert2-react": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/sweetalert2-react/-/sweetalert2-react-0.8.3.tgz",
"integrity": "sha512-l960IJWHE6BHDEImcn//thzQOY9moVccf6xgg42HDyLwpU/2wLvv9P82fD0sQn0WGAUwbjDz3Xfuj9oQI4iFzQ==",
"requires": {
"lodash.pick": "^4.4.0",
"mousetrap": "^1.6.0",
"prop-types": "^15.0.0",
"sweetalert2": "^8.5.0",
"warning": "^4.0.3"
}
},
"symbol-tree": { "symbol-tree": {
"version": "3.2.4", "version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",

View File

@ -24,6 +24,7 @@
"redux-devtools-extension": "^2.13.9", "redux-devtools-extension": "^2.13.9",
"sass": "^1.34.0", "sass": "^1.34.0",
"sass-loader": "^11.1.1", "sass-loader": "^11.1.1",
"sweetalert2-react": "^0.8.3",
"web-vitals": "^1.1.2" "web-vitals": "^1.1.2"
}, },
"scripts": { "scripts": {

View File

@ -20,6 +20,11 @@ import { selectIsLoading } from '../../redux/loaderSlice';
import { Redirect, Link } from 'react-router-dom'; import { Redirect, Link } from 'react-router-dom';
import { Loader } from '../Loader/Loader' import { Loader } from '../Loader/Loader'
import { withSwalInstance } from 'sweetalert2-react';
import swal from 'sweetalert2';
const SweetAlert = withSwalInstance(swal);
const AuthForDevelopers = () => { const AuthForDevelopers = () => {
const dispatch = useDispatch() const dispatch = useDispatch()
const isAuth = useSelector(selectAuth) const isAuth = useSelector(selectAuth)
@ -27,6 +32,7 @@ const AuthForDevelopers = () => {
const [username, setUsername] = useState('') const [username, setUsername] = useState('')
const [password, setPassword] = useState('') const [password, setPassword] = useState('')
const [error, setError] = useState(null);
if(isAuth) { if(isAuth) {
return <Redirect to='/' /> return <Redirect to='/' />
@ -67,6 +73,17 @@ const AuthForDevelopers = () => {
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
/> />
{ error && <div className={style.form__error}>
<SweetAlert
show={!!error}
title="Ошибка"
text={error}
onConfirm={() => setError(null)}
/>
</div> }
<div className={style.form__buttons}> <div className={style.form__buttons}>
<button <button
className={style.form__btn} className={style.form__btn}
@ -79,6 +96,10 @@ const AuthForDevelopers = () => {
dispatch: ()=> { dispatch: ()=> {
dispatch(auth(true)) dispatch(auth(true))
dispatch(loading(false)) dispatch(loading(false))
},
catchError: () => {
setError('Некорректные данные для входа')
dispatch(loading(false))
} }
}) })
} : ()=>{}} } : ()=>{}}

View File

@ -182,7 +182,7 @@
background-color: #ffffff; background-color: #ffffff;
border: 2px solid #6aaf5c; border: 2px solid #6aaf5c;
font-family: 'Muller'; font-family: 'Muller';
font-size: 2em; font-size: 1.8em;
letter-spacing: normal; letter-spacing: normal;
line-height: 71.88px; line-height: 71.88px;
text-align: center; text-align: center;
@ -192,6 +192,12 @@
color: #6aaf5c !important; color: #6aaf5c !important;
} }
/* .form__error {
font-size: 16px;
color: #b21;
margin-left: 45px;
} */
@media (max-width: 575.98px) { @media (max-width: 575.98px) {
.form__btn { .form__btn {
margin: 0 auto; margin: 0 auto;

View File

@ -21,6 +21,11 @@ import { selectIsLoading } from '../../redux/loaderSlice';
import { Redirect, Link } from 'react-router-dom'; import { Redirect, Link } from 'react-router-dom';
import { Loader } from '../Loader/Loader' import { Loader } from '../Loader/Loader'
import { withSwalInstance } from 'sweetalert2-react';
import swal from 'sweetalert2';
const SweetAlert = withSwalInstance(swal);
const AuthForPartners = () => { const AuthForPartners = () => {
const dispatch = useDispatch() const dispatch = useDispatch()
const isAuth = useSelector(selectAuth) const isAuth = useSelector(selectAuth)
@ -28,6 +33,7 @@ const AuthForPartners = () => {
const [username, setUsername] = useState('') const [username, setUsername] = useState('')
const [password, setPassword] = useState('') const [password, setPassword] = useState('')
const [error, setError] = useState(null);
if(isAuth) { if(isAuth) {
return <Redirect to='/' /> return <Redirect to='/' />
@ -62,6 +68,15 @@ const AuthForPartners = () => {
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
/> />
{ error && <div className={style.form__error}>
<SweetAlert
show={!!error}
title="Ошибка"
text={error}
onConfirm={() => setError(null)}
/>
</div> }
<div className={style.form__buttons}> <div className={style.form__buttons}>
<button <button
className={style.form__btn} className={style.form__btn}
@ -74,6 +89,10 @@ const AuthForPartners = () => {
dispatch: ()=> { dispatch: ()=> {
dispatch(auth(true)) dispatch(auth(true))
dispatch(loading(false)) dispatch(loading(false))
},
catchError: () => {
setError('Некорректные данные для входа')
dispatch(loading(false))
} }
}) })
} : ()=>{}} } : ()=>{}}

View File

@ -179,7 +179,7 @@
background-color: #ffffff; background-color: #ffffff;
border: 2px solid #6aaf5c; border: 2px solid #6aaf5c;
font-family: 'Muller'; font-family: 'Muller';
font-size: 2em; font-size: 1.8em;
letter-spacing: normal; letter-spacing: normal;
line-height: 71.88px; line-height: 71.88px;
text-align: center; text-align: center;
@ -189,6 +189,12 @@
color: #6aaf5c !important; color: #6aaf5c !important;
} }
/* .form__error {
font-size: 16px;
color: #b21;
margin-left: 45px;
} */
@media (max-width: 575.98px) { @media (max-width: 575.98px) {
.form__btn { .form__btn {
margin: 0 auto; margin: 0 auto;

View File

@ -102,7 +102,7 @@ const Candidate = () => {
<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 candidate={currentCandidateObj} />
</div> </div>
<div className="col-12 col-xl-8"> <div className="col-12 col-xl-8">
<div className={style.candidate__main__description}> <div className={style.candidate__main__description}>

View File

@ -18,8 +18,6 @@ const Description = ({ onLoadMore }) => {
fetchProfile(`${process.env.REACT_APP_API_URL}/api/profile?limit=`, 1000).then((p) => getAllCandidates(p)); fetchProfile(`${process.env.REACT_APP_API_URL}/api/profile?limit=`, 1000).then((p) => getAllCandidates(p));
}, []); }, []);
console.log('render',filteredListArr, itemsArr)
if(!filteredListArr) { if(!filteredListArr) {
return ( return (
<section className={style.description}> <section className={style.description}>
@ -33,7 +31,7 @@ const Description = ({ 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}>
{SKILLS[el.position_id]}, {LEVELS[el.level]} {el.specification} {SKILLS[el.position_id]}, {LEVELS[el.level]}
</h3> </h3>
{el.vc_text_short ? ( {el.vc_text_short ? (
@ -80,7 +78,7 @@ const Description = ({ 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}>
{SKILLS[el.position_id]}, {LEVELS[el.level]} {el.specification} {SKILLS[el.position_id]}, {LEVELS[el.level]}
</h3> </h3>
{el.vc_text_short ? ( {el.vc_text_short ? (

View File

@ -3,13 +3,27 @@ import { Link } from 'react-router-dom';
import maleBig from '../../images/medium_male_big.png'; import maleBig from '../../images/medium_male_big.png';
import style from './Sidebar.module.css'; import style from './Sidebar.module.css';
const Sidebar = () => { const getYearsString = (years) => {
let yearsString = 'года';
if (years%10 === 1) {
yearsString = 'год';
} else if (years === 11 || years === 12 || years === 13 || years === 14) {
yearsString = 'лет';
} else if (years%10 === 2 || years%10 === 3 || years%10 === 4) {
yearsString = 'года';
}
return `${years} ${yearsString}`;
}
const Sidebar = ({ candidate }) => {
return ( return (
<div className={style.candidateSidebar}> <div className={style.candidateSidebar}>
<div className={style.candidateSidebar__info}> <div className={style.candidateSidebar__info}>
<img src={maleBig} alt="" /> <img src={maleBig} alt="" />
<p className={style.candidateSidebar__info__e}>Опыт работы</p> { candidate && candidate.years_of_exp && <>
<p className={style.candidateSidebar__info__y}>4+ лет</p> <p className={style.candidateSidebar__info__e}>Опыт работы</p>
<p className={style.candidateSidebar__info__y}>{getYearsString(candidate.years_of_exp)}</p>
</> }
<Link to={`/form`}> <Link to={`/form`}>
<button className={style.candidateSidebar__info__btn}>Выбрать к собеседованию</button> <button className={style.candidateSidebar__info__btn}>Выбрать к собеседованию</button>
</Link> </Link>

View File

@ -64,7 +64,7 @@ export const fetchForm = async (link, info) => {
} catch (error) {} } catch (error) {}
} }
export const fetchAuth = async ({ username, password, dispatch }) => { export const fetchAuth = async ({ username, password, dispatch, catchError }) => {
const baseURL = process.env.REACT_APP_BASE_URL; const baseURL = process.env.REACT_APP_BASE_URL;
const apiURL = process.env.REACT_APP_API_URL; const apiURL = process.env.REACT_APP_API_URL;
try { try {
@ -84,6 +84,7 @@ export const fetchAuth = async ({ username, password, dispatch }) => {
) )
if(!response.ok) { if(!response.ok) {
catchError();
return response.statusText; return response.statusText;
} }