Merge pull request #9 from apuc/authentication
logout, hover transition and small fixes
This commit is contained in:
commit
d58b7b62d3
8
package-lock.json
generated
8
package-lock.json
generated
@ -12735,6 +12735,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||||
},
|
},
|
||||||
|
"react-loader-spinner": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-loader-spinner/-/react-loader-spinner-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-RU2vpEej6G4ECei0h3q6bgLU10of9Lw5O+4AwF/mtkrX5oY20Sh/AxoPJ7etbrs/7Q3u4jN5qwCwGLRKCHpk6g==",
|
||||||
|
"requires": {
|
||||||
|
"prop-types": "^15.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-overlays": {
|
"react-overlays": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.0.1.tgz",
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
"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-loader-spinner": "^4.0.0",
|
||||||
"react-redux": "^7.2.4",
|
"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",
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<meta name="theme-color" content="#000000" />
|
|
||||||
<meta
|
|
||||||
name="description"
|
|
||||||
content="Web site created using create-react-app"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<title>React App</title>
|
<head>
|
||||||
</head>
|
<meta charset="utf-8" />
|
||||||
<body>
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<meta name="theme-color" content="#000000" />
|
||||||
<div id="root"></div>
|
<meta name="description" content="Web site created using create-react-app" />
|
||||||
|
|
||||||
|
<title>Outstaffing</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
@ -1,6 +1,7 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useDispatch } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
import { auth } from '../../redux/outstaffingSlice'
|
import { auth } from '../../redux/outstaffingSlice'
|
||||||
|
import { loading } from '../../redux/loaderSlice'
|
||||||
import style from './AuthForDevelopers.module.css'
|
import style from './AuthForDevelopers.module.css'
|
||||||
import ellipse from '../../images/ellipse.png'
|
import ellipse from '../../images/ellipse.png'
|
||||||
import arrow from '../../images/arrow__login_page.png'
|
import arrow from '../../images/arrow__login_page.png'
|
||||||
@ -14,13 +15,15 @@ import vector from '../../images/Vector_Smart_Object.png'
|
|||||||
import vectorBlack from '../../images/Vector_Smart_Object_black.png'
|
import vectorBlack from '../../images/Vector_Smart_Object_black.png'
|
||||||
import { fetchAuth } from '../../server/server'
|
import { fetchAuth } from '../../server/server'
|
||||||
|
|
||||||
import { useSelector } from 'react-redux'
|
|
||||||
import { selectAuth } from '../../redux/outstaffingSlice';
|
import { selectAuth } from '../../redux/outstaffingSlice';
|
||||||
|
import { selectIsLoading } from '../../redux/loaderSlice';
|
||||||
import { Redirect, Link } from 'react-router-dom';
|
import { Redirect, Link } from 'react-router-dom';
|
||||||
|
import { Loader } from '../Loader/Loader'
|
||||||
|
|
||||||
const AuthForDevelopers = () => {
|
const AuthForDevelopers = () => {
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const isAuth = useSelector(selectAuth)
|
const isAuth = useSelector(selectAuth)
|
||||||
|
const isLoading = useSelector(selectIsLoading)
|
||||||
|
|
||||||
const [username, setUsername] = useState('')
|
const [username, setUsername] = useState('')
|
||||||
const [password, setPassword] = useState('')
|
const [password, setPassword] = useState('')
|
||||||
@ -66,19 +69,23 @@ const AuthForDevelopers = () => {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
className={style.form__btn}
|
className={style.form__btn}
|
||||||
onClick={(e) => {
|
onClick={!isLoading ? (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
dispatch(loading(true))
|
||||||
fetchAuth({
|
fetchAuth({
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
dispatch: ()=> dispatch(auth(true))
|
dispatch: ()=> {
|
||||||
|
dispatch(auth(true))
|
||||||
|
dispatch(loading(false))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}}
|
} : ()=>{}}
|
||||||
>
|
>
|
||||||
Войти
|
{ isLoading ? <Loader /> : 'Войти' }
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button className={`${style.form__btn} ${style.auth__link}`}>
|
<button className={`${style.form__btn__partners} ${style.auth__link}`}>
|
||||||
<Link to='/auth'>Для партнёров</Link>
|
<Link to='/auth'>Для партнёров</Link>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -153,6 +153,32 @@
|
|||||||
letter-spacing: normal;
|
letter-spacing: normal;
|
||||||
line-height: 71.88px;
|
line-height: 71.88px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
border: 2px solid #6aaf5c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__btn:hover {
|
||||||
|
background-image: none;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 2px solid #6aaf5c;
|
||||||
|
color: #6aaf5c !important;
|
||||||
|
transition: .3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__btn__partners {
|
||||||
|
width: 288px;
|
||||||
|
height: 75px;
|
||||||
|
border-radius: 38px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 2px solid #6aaf5c;
|
||||||
|
font-family: 'Muller';
|
||||||
|
font-size: 2em;
|
||||||
|
letter-spacing: normal;
|
||||||
|
line-height: 71.88px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__btn__partners a {
|
||||||
|
color: #6aaf5c !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 575.98px) {
|
@media (max-width: 575.98px) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { auth } from '../../redux/outstaffingSlice';
|
import { auth } from '../../redux/outstaffingSlice';
|
||||||
|
import { loading } from '../../redux/loaderSlice'
|
||||||
import style from './AuthForPartners.module.css';
|
import style from './AuthForPartners.module.css';
|
||||||
import ellipse from '../../images/ellipse.png';
|
import ellipse from '../../images/ellipse.png';
|
||||||
import arrow from '../../images/arrow__login_page.png';
|
import arrow from '../../images/arrow__login_page.png';
|
||||||
@ -16,12 +17,15 @@ import { fetchAuth } from '../../server/server'
|
|||||||
|
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
import { selectAuth } from '../../redux/outstaffingSlice';
|
import { selectAuth } from '../../redux/outstaffingSlice';
|
||||||
|
import { selectIsLoading } from '../../redux/loaderSlice';
|
||||||
import { Redirect, Link } from 'react-router-dom';
|
import { Redirect, Link } from 'react-router-dom';
|
||||||
|
import { Loader } from '../Loader/Loader'
|
||||||
|
|
||||||
const AuthForPartners = () => {
|
const AuthForPartners = () => {
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const isAuth = useSelector(selectAuth)
|
const isAuth = useSelector(selectAuth)
|
||||||
|
const isLoading = useSelector(selectIsLoading)
|
||||||
|
console.log('iL',isLoading);
|
||||||
const [username, setUsername] = useState('')
|
const [username, setUsername] = useState('')
|
||||||
const [password, setPassword] = useState('')
|
const [password, setPassword] = useState('')
|
||||||
|
|
||||||
@ -58,20 +62,25 @@ const AuthForPartners = () => {
|
|||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<button className={style.form__btn}
|
<button
|
||||||
onClick={(e) => {
|
className={style.form__btn}
|
||||||
|
onClick={!isLoading ? (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
dispatch(loading(true))
|
||||||
fetchAuth({
|
fetchAuth({
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
dispatch: ()=> dispatch(auth(true))
|
dispatch: ()=> {
|
||||||
|
dispatch(auth(true))
|
||||||
|
dispatch(loading(false))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
} : ()=>{}}
|
||||||
}>
|
>
|
||||||
Войти
|
{ isLoading ? <Loader /> : 'Войти' }
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button className={`${style.form__btn} ${style.auth__link}`}>
|
<button className={`${style.form__btn__dev} ${style.auth__link}`}>
|
||||||
<Link to='/authdev'>Для разработчиков</Link>
|
<Link to='/authdev'>Для разработчиков</Link>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -153,6 +153,33 @@
|
|||||||
letter-spacing: normal;
|
letter-spacing: normal;
|
||||||
line-height: 71.88px;
|
line-height: 71.88px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
border: 2px solid #6aaf5c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__btn:hover {
|
||||||
|
background-image: none;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 2px solid #6aaf5c;
|
||||||
|
color: #6aaf5c !important;
|
||||||
|
transition: .3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.form__btn__dev {
|
||||||
|
width: 288px;
|
||||||
|
height: 75px;
|
||||||
|
border-radius: 38px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 2px solid #6aaf5c;
|
||||||
|
font-family: 'Muller';
|
||||||
|
font-size: 2em;
|
||||||
|
letter-spacing: normal;
|
||||||
|
line-height: 71.88px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form__btn__dev a {
|
||||||
|
color: #6aaf5c !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 575.98px) {
|
@media (max-width: 575.98px) {
|
||||||
|
@ -29,7 +29,9 @@ 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]}
|
<Link to={`/candidate/${el.id}`}>
|
||||||
|
{SKILLS[el.position_id]}, {LEVELS[el.level]}
|
||||||
|
</Link>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{el.vc_text_short ? (
|
{el.vc_text_short ? (
|
||||||
@ -64,7 +66,9 @@ 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]}
|
<Link to={`/candidate/${el.id}`}>
|
||||||
|
{SKILLS[el.position_id]}, {LEVELS[el.level]}
|
||||||
|
</Link>
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{el.vc_text_short ? (
|
{el.vc_text_short ? (
|
||||||
|
@ -53,6 +53,10 @@
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.description__title {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 575.98px) {
|
@media (max-width: 575.98px) {
|
||||||
.description__title {
|
.description__title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
14
src/components/Loader/Loader.js
Normal file
14
src/components/Loader/Loader.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import SVGLoader from "react-loader-spinner";
|
||||||
|
export const Loader = () => {
|
||||||
|
return (
|
||||||
|
<div className='loader'>
|
||||||
|
<SVGLoader
|
||||||
|
type="Circles"
|
||||||
|
color="#fff"
|
||||||
|
height={50}
|
||||||
|
width={50}
|
||||||
|
timeout={3000}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
14
src/components/LogoutButton/LogoutButton.js
Normal file
14
src/components/LogoutButton/LogoutButton.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { auth } from '../../redux/outstaffingSlice';
|
||||||
|
|
||||||
|
import './logoutButton.css'
|
||||||
|
|
||||||
|
export const LogoutButton = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
return (
|
||||||
|
<div className='logout-button' onClick={()=>{localStorage.clear(); dispatch(auth(false));}}>
|
||||||
|
<button>Выйти</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
30
src/components/LogoutButton/logoutButton.css
Normal file
30
src/components/LogoutButton/logoutButton.css
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
.logout-button {
|
||||||
|
position: fixed;
|
||||||
|
top: 2rem;
|
||||||
|
right: 3.5rem;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-button button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
border-radius: 20px;
|
||||||
|
background-color: #6aaf5c;
|
||||||
|
color: #ffffff;
|
||||||
|
border: 2px solid #6aaf5c;
|
||||||
|
font-family: 'Muller';
|
||||||
|
font-size: 2em;
|
||||||
|
letter-spacing: normal;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-button:hover button {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #6aaf5c;
|
||||||
|
border: 2px solid #6aaf5c;
|
||||||
|
box-shadow: 3px 2px 5px rgba(82, 151, 34, 0.21);
|
||||||
|
transition: .3s;
|
||||||
|
}
|
9
src/hoc/withLogout.js
Normal file
9
src/hoc/withLogout.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { LogoutButton } from '../components/LogoutButton/LogoutButton';
|
||||||
|
|
||||||
|
export const WithLogout = (props) => {
|
||||||
|
return <>
|
||||||
|
<LogoutButton />
|
||||||
|
{props.children}
|
||||||
|
</>
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { WithLogout } from '../hoc/withLogout';
|
||||||
import Calendar from '../components/Calendar/Calendar';
|
import Calendar from '../components/Calendar/Calendar';
|
||||||
|
|
||||||
const CalendarPage = () => {
|
const CalendarPage = () => {
|
||||||
return <Calendar />;
|
return <WithLogout><Calendar /></WithLogout>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CalendarPage;
|
export default CalendarPage;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { WithLogout } from '../hoc/withLogout';
|
||||||
import Candidate from '../components/Candidate/Candidate';
|
import Candidate from '../components/Candidate/Candidate';
|
||||||
|
|
||||||
const CandidatePage = () => <Candidate />;
|
const CandidatePage = () => <WithLogout><Candidate /></WithLogout>;
|
||||||
|
|
||||||
export default CandidatePage;
|
export default CandidatePage;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { WithLogout } from '../hoc/withLogout';
|
||||||
import Form from '../components/Form/Form';
|
import Form from '../components/Form/Form';
|
||||||
|
|
||||||
const FormPage = () => <Form />;
|
const FormPage = () => <WithLogout><Form /></WithLogout>;
|
||||||
|
|
||||||
export default FormPage;
|
export default FormPage;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { WithLogout } from '../hoc/withLogout';
|
||||||
import Home from '../components/Home/Home';
|
import Home from '../components/Home/Home';
|
||||||
|
|
||||||
const HomePage = () => <Home />;
|
const HomePage = () => <WithLogout><Home /></WithLogout>;
|
||||||
|
|
||||||
export default HomePage;
|
export default HomePage;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { WithLogout } from '../hoc/withLogout';
|
||||||
import ReportForm from '../components/ReportForm/ReportForm';
|
import ReportForm from '../components/ReportForm/ReportForm';
|
||||||
|
|
||||||
const ReportFormPage = () => <ReportForm />;
|
const ReportFormPage = () => <WithLogout><ReportForm /></WithLogout>;
|
||||||
|
|
||||||
export default ReportFormPage;
|
export default ReportFormPage;
|
||||||
|
21
src/redux/loaderSlice.js
Normal file
21
src/redux/loaderSlice.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
isLoading: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const loaderSlice = createSlice({
|
||||||
|
name: 'loader',
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
loading: (state, action) => {
|
||||||
|
state.isLoading = action.payload;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const { loading } = loaderSlice.actions;
|
||||||
|
|
||||||
|
export const selectIsLoading = (state) => state.loader.isLoading;
|
||||||
|
|
||||||
|
export default loaderSlice.reducer;
|
@ -1,8 +1,10 @@
|
|||||||
import { configureStore } from '@reduxjs/toolkit';
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
import outstaffingReducer from '../redux/outstaffingSlice';
|
import outstaffingReducer from '../redux/outstaffingSlice';
|
||||||
|
import loaderReducer from '../redux/loaderSlice';
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
outstaffing: outstaffingReducer,
|
outstaffing: outstaffingReducer,
|
||||||
|
loader: loaderReducer,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user