Удалил старые запросы к апи, переписал страницу тестов на новый конструктор запроса. Обновил библиотеки, в том числе реакт до последней версии, переписал устаревший код с библиотек.

This commit is contained in:
Дмитрий Савенко 2023-02-02 18:10:44 +03:00
parent f1628e5745
commit c60e1b43d2
14 changed files with 6719 additions and 8058 deletions

14262
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -28,53 +28,54 @@
"identity-obj-proxy": "3.0.0", "identity-obj-proxy": "3.0.0",
"moment": "^2.29.1", "moment": "^2.29.1",
"prompts": "2.4.0", "prompts": "2.4.0",
"react": "^17.0.2", "react": "^18.2.0",
"react-app-polyfill": "^2.0.0", "react-app-polyfill": "^2.0.0",
"react-bootstrap": "^1.6.0", "react-bootstrap": "^1.6.0",
"react-dev-utils": "^11.0.3", "react-dev-utils": "^12.0.1",
"react-dom": "^17.0.2", "react-dom": "^18.2.0",
"react-inlinesvg": "^2.3.0", "react-inlinesvg": "3.0.1",
"react-loader-spinner": "^4.0.0", "react-loader-spinner": "^4.0.0",
"react-outside-click-handler": "^1.3.0", "react-outside-click-handler": "^1.3.0",
"react-phone-input-2": "^2.14.0", "react-phone-input-2": "^2.14.0",
"react-redux": "^7.2.4", "react-redux": "^7.2.4",
"react-refresh": "^0.8.3",
"react-router": "latest", "react-router": "latest",
"react-router-dom": "^6.2.1", "react-router-dom": "^6.2.1",
"react-select": "^4.3.1", "react-select": "^5.7.0",
"react-syntax-highlighter": "^15.4.5", "react-syntax-highlighter": "^15.4.5",
"react-yandex-metrika": "^2.6.0", "react-yandex-metrika": "^2.6.0",
"redux-devtools-extension": "^2.13.9", "redux-devtools-extension": "^2.13.9",
"resolve": "1.18.1", "resolve": "1.18.1",
"resolve-url-loader": "^3.1.2", "resolve-url-loader": "^3.1.2",
"semver": "7.3.2", "semver": "7.3.2",
"sweetalert2-react": "^0.8.3" "sweetalert2": "^11.4.8"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.12", "@babel/core": "^7.20.12",
"@babel/preset-env": "^7.20.2", "@babel/preset-env": "^7.20.2",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"babel-loader": "^9.1.2", "babel-loader": "^9.1.2",
"copy-webpack-plugin": "^10.2.0", "copy-webpack-plugin": "^10.2.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"css-loader": "^6.7.3", "css-loader": "6.7.3",
"dotenv-webpack": "^7.0.3", "dotenv-webpack": "^7.0.3",
"html-webpack-plugin": "latest", "html-webpack-plugin": "5.5.0",
"mini-css-extract-plugin": "^2.7.2", "mini-css-extract-plugin": "^2.7.2",
"node-sass": "^6.0.1", "node-sass": "8.0.0",
"postcss": "^8.4.21", "postcss": "^8.4.21",
"postcss-loader": "^6.2.1", "postcss-loader": "^6.2.1",
"postcss-preset-env": "^7.8.3", "postcss-preset-env": "^7.8.3",
"react-hot-loader": "^4.13.0", "react-refresh": "^0.14.0",
"react-scripts": "5.0.1", "react-scripts": "^5.0.1",
"sass": "^1.57.1", "sass": "^1.58.0",
"sass-loader": "^12.6.0", "sass-loader": "^13.2.0",
"sweetalert2-react-content": "^5.0.7",
"universal-cookie": "^4.0.4", "universal-cookie": "^4.0.4",
"web-vitals": "^3.1.1", "web-vitals": "^3.1.1",
"webpack": "latest", "webpack": "5.75.0",
"webpack-bundle-analyzer": "latest", "webpack-bundle-analyzer": "4.7.0",
"webpack-cli": "latest", "webpack-cli": "^5.0.1",
"webpack-dev-server": "latest", "webpack-dev-server": "4.11.1",
"webpack-merge": "latest" "webpack-merge": "5.8.0"
}, },
"scripts": { "scripts": {
"build": "cross-env SERVE=true webpack -c config/webpack/prod.js", "build": "cross-env SERVE=true webpack -c config/webpack/prod.js",

View File

@ -1,8 +1,6 @@
import React, {useEffect, useState} from 'react' import React, {useEffect, useRef, useState} from 'react'
import {Link, useNavigate} from 'react-router-dom' import {Link, useNavigate} from 'react-router-dom'
import {useDispatch, useSelector} from 'react-redux' import {useDispatch, useSelector} from 'react-redux'
import {withSwalInstance} from 'sweetalert2-react'
import swal from 'sweetalert2'
import {Loader} from '../Loader/Loader' import {Loader} from '../Loader/Loader'
import ErrorBoundary from "../../hoc/ErrorBoundary"; import ErrorBoundary from "../../hoc/ErrorBoundary";
@ -10,7 +8,6 @@ import ErrorBoundary from "../../hoc/ErrorBoundary";
import {auth, selectAuth, setUserInfo} from '../../redux/outstaffingSlice' import {auth, selectAuth, setUserInfo} from '../../redux/outstaffingSlice'
import {loading} from '../../redux/loaderSlice' import {loading} from '../../redux/loaderSlice'
import {setRole} from '../../redux/roleSlice' import {setRole} from '../../redux/roleSlice'
import {selectIsLoading} from '../../redux/loaderSlice' import {selectIsLoading} from '../../redux/loaderSlice'
import {apiRequest} from "../../api/request"; import {apiRequest} from "../../api/request";
@ -19,12 +16,14 @@ import ellipse from '../../images/ellipse.png'
import './authBox.scss' import './authBox.scss'
const {useRef} = require("react"); import Swal from 'sweetalert2'
import withReactContent from 'sweetalert2-react-content'
const SweetAlert = withReactContent(Swal);
const SweetAlert = withSwalInstance(swal);
export const AuthBox = ({title, altTitle, roleChangeLink}) => { export const AuthBox = ({title, altTitle, roleChangeLink}) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const ref = useRef(); const ref = useRef();
const navigate = useNavigate(); const navigate = useNavigate();
@ -34,9 +33,15 @@ export const AuthBox = ({title, altTitle, roleChangeLink}) => {
const [error, setError] = useState(null); const [error, setError] = useState(null);
if (isAuth) { const handleModalError = (error) => {
navigate('/') SweetAlert.fire({
} title: 'Ошибка',
text: error
});
setError(null)
};
useEffect(() => { useEffect(() => {
if (!localStorage.getItem('auth_token')) { if (!localStorage.getItem('auth_token')) {
@ -44,9 +49,16 @@ export const AuthBox = ({title, altTitle, roleChangeLink}) => {
} }
}, []); }, []);
useEffect(() => {
if (isAuth) {
navigate('/')
}
});
const submitHandler = () => { const submitHandler = () => {
let formData = new FormData(ref.current) let formData = new FormData(ref.current);
if (!isLoading) { if (!isLoading) {
dispatch(loading(true)); dispatch(loading(true));
apiRequest('/user/login', apiRequest('/user/login',
@ -107,12 +119,17 @@ export const AuthBox = ({title, altTitle, roleChangeLink}) => {
{error && ( {error && (
<div className='auth-box__form-error'> <div className='auth-box__form-error'>
<ErrorBoundary> <ErrorBoundary>
<SweetAlert
show={!!error}
title='Ошибка' {
text={error} handleModalError(error)
onConfirm={() => setError(null)} }
/> {/*<SweetAlert*/}
{/* show={!!error}*/}
{/* title='Ошибка'*/}
{/* text={error}*/}
{/* onConfirm={() => setError(null)}*/}
{/*/>*/}
</ErrorBoundary> </ErrorBoundary>
</div> </div>
)} )}

View File

@ -1,22 +1,23 @@
import React, { useState } from 'react' import React, {useEffect, useState} from 'react'
import {useParams, useNavigate} from 'react-router-dom' import {useParams, useNavigate} from 'react-router-dom'
import {Loader} from '../Loader/Loader' import {Loader} from '../Loader/Loader'
import PhoneInput from 'react-phone-input-2' import PhoneInput from 'react-phone-input-2'
import 'react-phone-input-2/lib/style.css' import 'react-phone-input-2/lib/style.css'
import './form.scss' import './form.scss'
import { withSwalInstance } from 'sweetalert2-react'
import swal from 'sweetalert2'
import {apiRequest} from "../../api/request"; import {apiRequest} from "../../api/request";
import Swal from 'sweetalert2'
import withReactContent from 'sweetalert2-react-content'
const SweetAlert = withSwalInstance(swal); const SweetAlert = withReactContent(Swal);
const Form = () => { const Form = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const urlParams = useParams(); const urlParams = useParams();
const [status, setStatus] = useState(null); const [status, setStatus] = useState(null);
const [data, setData] = useState({ const [data, setData] = useState({
email: '', email: '',
@ -25,6 +26,26 @@ const Form = () => {
}); });
const [isFetching, setIsFetching] = useState(false); const [isFetching, setIsFetching] = useState(false);
const handleModal = (status) => {
SweetAlert.fire({
text: status !== 200 || 201
? 'Какие-то неполадки =('
: 'Форма отправлена',
preConfirm: () =>
status !== 200 || 201 ? () => {
setStatus(null)
} : () => {
setStatus(null);
navigate(`/candidate/${urlParams.id}`)
}
});
};
useEffect(() => {
if (status) {
handleModal(status)
}
}, [status]);
const handleChange = (e) => { const handleChange = (e) => {
const {id, value} = e.target; const {id, value} = e.target;
@ -41,7 +62,7 @@ const Form = () => {
setIsFetching(true); setIsFetching(true);
const formData = new FormData(); const formData = new FormData();
formData.append('profile_id', urlParams.id); formData.append('profile_id', urlParams.id);
formData.append('email', data.email); formData.append('Email', data.email);
formData.append('phone', data.phone); formData.append('phone', data.phone);
formData.append('comment', data.comment); formData.append('comment', data.comment);
@ -59,27 +80,6 @@ const Form = () => {
}; };
return ( return (
<>
{status && (
<SweetAlert
show={!!status}
text={
status.errors
? status.errors[Object.keys(status.errors)[0]]
: 'Форма отправлена'
}
onConfirm={
status.errors
? () => {
setStatus(null)
}
: () => {
setStatus(null);
navigate(`/candidate/${urlParams.id}`)
}
}
/>
)}
<div className='row'> <div className='row'>
<div className='col-sm-12'> <div className='col-sm-12'>
<form className='form' id='test'> <form className='form' id='test'>
@ -128,7 +128,6 @@ const Form = () => {
</form> </form>
</div> </div>
</div> </div>
</>
) )
}; };

View File

@ -2,6 +2,7 @@ import {Link} from 'react-router-dom'
import './quiz.scss' import './quiz.scss'
import {useSelector} from "react-redux"; import {useSelector} from "react-redux";
import {selectedTest, selectUserInfo} from "../../../redux/quizSlice"; import {selectedTest, selectUserInfo} from "../../../redux/quizSlice";
import {urlForLocal} from "../../../helper";
export const HeaderPageTestsQuiz = ({isVisibilityButton}) => { export const HeaderPageTestsQuiz = ({isVisibilityButton}) => {
@ -14,7 +15,7 @@ export const HeaderPageTestsQuiz = ({isVisibilityButton}) => {
<div className="header-quiz__container"> <div className="header-quiz__container">
<div className="header-quiz__body"> <div className="header-quiz__body">
<div className="header-quiz__avatar"> <div className="header-quiz__avatar">
{userInfo.photo && <img src={userInfo.photo} alt={userInfo.photo}/>} {userInfo.photo && <img src={urlForLocal(userInfo.photo)} alt={userInfo.photo}/>}
</div> </div>
<div className="header-quiz__description"> <div className="header-quiz__description">
<div className="header-quiz__title-test title">{test.questionnaire_title}</div> <div className="header-quiz__title-test title">{test.questionnaire_title}</div>

View File

@ -1,8 +1,9 @@
import React, {useEffect} from 'react' import React, {useEffect} from 'react'
import {useDispatch, useSelector} from 'react-redux' import {useDispatch, useSelector} from 'react-redux'
import {selectUserInfo, setQuestionnairesList, setUserInfo} from "../../../redux/quizSlice"; import {selectUserInfo, setQuestionnairesList, setUserInfo} from "../../../redux/quizSlice";
import './quiz.scss'
import {apiRequest} from "../../../api/request"; import {apiRequest} from "../../../api/request";
import {urlForLocal} from "../../../helper";
import './quiz.scss'
export const HeaderQuiz = ({header}) => { export const HeaderQuiz = ({header}) => {
@ -13,12 +14,12 @@ export const HeaderQuiz = ({header}) => {
useEffect(() => { useEffect(() => {
dispatch(setUserInfo(userId)) dispatch(setUserInfo(userId))
}, [dispatch]); }, [userId, dispatch]);
useEffect(() => { useEffect(() => {
apiRequest(`/user-questionnaire/questionnaires-list?user_id=${userId}`) apiRequest(`/user-questionnaire/questionnaires-list?user_id=${userId}`)
.then(res => dispatch(setQuestionnairesList(res))) .then(res => dispatch(setQuestionnairesList(res)))
}, [dispatch]); }, [userId, dispatch]);
return ( return (
<div> <div>
@ -30,7 +31,7 @@ export const HeaderQuiz = ({header}) => {
{header && <h2 className={'header-quiz__title-main'}>Добрый день, {userInfo.fio}</h2>} {header && <h2 className={'header-quiz__title-main'}>Добрый день, {userInfo.fio}</h2>}
<div className="header-quiz__body header-quiz__body_interjacent"> <div className="header-quiz__body header-quiz__body_interjacent">
<div className="header-quiz__avatar"> <div className="header-quiz__avatar">
<img src={userInfo.photo} alt={userInfo.photo}/> <img src={urlForLocal(userInfo.photo)} alt={userInfo.photo}/>
</div> </div>
<div className="header-quiz__name-user">{userInfo.fio}</div> <div className="header-quiz__name-user">{userInfo.fio}</div>
<div className="header-quiz__title">{userInfo.position_name}</div> <div className="header-quiz__title">{userInfo.position_name}</div>

View File

@ -1,8 +1,9 @@
import {Link} from 'react-router-dom' import {Link} from 'react-router-dom'
import calendarImage from './../../../images/calendar.svg' import calendarImage from './../../../images/calendar.svg'
import './quiz.scss'
import {useDispatch} from "react-redux"; import {useDispatch} from "react-redux";
import {setSelectedTest} from "../../../redux/quizSlice"; import {setSelectedTest} from "../../../redux/quizSlice";
import {urlForLocal} from "../../../helper";
import './quiz.scss'
export const MyTestsQuiz = ({listTests}) => { export const MyTestsQuiz = ({listTests}) => {
@ -46,7 +47,7 @@ export const MyTestsQuiz = ({listTests}) => {
</h3> </h3>
<div className="item-test__body test-data"> <div className="item-test__body test-data">
<div className="test-data__calendar "> <div className="test-data__calendar ">
<img src={calendarImage} alt=""/> <img src={urlForLocal(calendarImage)} alt=""/>
{item.testing_date} {item.testing_date}
</div> </div>
<div className="test-data__hr"></div> <div className="test-data__hr"></div>

View File

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

View File

@ -1,14 +1,14 @@
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom/client'
import {store} from './store/store' import {store} from './store/store'
import {Provider} from 'react-redux' import {Provider} from 'react-redux'
import App from './App' import App from './App'
import './index.css' import './index.css'
ReactDOM.render( ReactDOM.createRoot(document.getElementById("root"))
.render(
<Provider store={store}> <Provider store={store}>
<App/> <App/>
</Provider>, </Provider>,
document.getElementById('root') );
)

View File

@ -1,12 +1,12 @@
import React from 'react' import React, {useEffect} from 'react'
import {useDispatch, useSelector} from 'react-redux' import {useDispatch, useSelector} from 'react-redux'
import {useParams, useNavigate} from 'react-router-dom' import {useParams, useNavigate} from 'react-router-dom'
import SVG from 'react-inlinesvg' import SVG from 'react-inlinesvg'
import {WithLogout} from '../../hoc/withLogout'
import Form from '../../components/Form/Form' import Form from '../../components/Form/Form'
import {Footer} from '../../components/Footer/Footer' import {Footer} from '../../components/Footer/Footer'
import {LogoutButton} from "../../components/LogoutButton/LogoutButton";
import arrow from '../../images/right-arrow.png' import arrow from '../../images/right-arrow.png'
import rectangle from '../../images/rectangle_secondPage.png' import rectangle from '../../images/rectangle_secondPage.png'
@ -16,12 +16,10 @@ import {LEVELS, SKILLS} from '../../constants/constants'
import {currentCandidate, selectCurrentCandidate} from '../../redux/outstaffingSlice' import {currentCandidate, selectCurrentCandidate} from '../../redux/outstaffingSlice'
import './formPage.scss'
import {apiRequest} from "../../api/request"; import {apiRequest} from "../../api/request";
import {LogoutButton} from "../../components/LogoutButton/LogoutButton"; import {urlForLocal} from "../../helper";
import './formPage.scss'
const FormPage = () => { const FormPage = () => {
const params = useParams(); const params = useParams();
@ -29,23 +27,22 @@ const FormPage = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const candidate = useSelector(selectCurrentCandidate); const candidate = useSelector(selectCurrentCandidate);
const goBack = () => { const goBack = () => {
navigate(-1) navigate(-1)
}; };
useEffect(()=> {
if (!candidate.id) { if (!candidate.id) {
apiRequest('/profile', { apiRequest('/profile', {
params: Number(params.id) params: Number(params.id)
}) })
.then((el) => dispatch(currentCandidate(el))) .then((el) => dispatch(currentCandidate(el)))
} }
}, []);
return ( return (
<div className='container'> <div className='container'>
<div className='form-page'> <div className='form-page'>
<div className='form-page__back'> <div className='form-page__back'>
<div className='form-page__arrow' onClick={goBack}> <div className='form-page__arrow' onClick={goBack}>
@ -60,7 +57,7 @@ const FormPage = () => {
</div> </div>
<div className='form-page__candidate'> <div className='form-page__candidate'>
<div className='form-page__avatar'> <div className='form-page__avatar'>
<img src={candidate.photo} alt='candidate avatar'/> {candidate.photo && <img src={urlForLocal(candidate.photo)} alt='candidate avatar'/>}
</div> </div>
<div className='form-page__candidate-info'> <div className='form-page__candidate-info'>
<div className='form-page__position'> <div className='form-page__position'>

View File

@ -3,15 +3,18 @@ import {HeaderPageTestsQuiz} from '../../components/features/quiz/HeaderPageTest
import {TaskQuiz} from '../../components/features/quiz/Task' import {TaskQuiz} from '../../components/features/quiz/Task'
import {useSelector} from "react-redux"; import {useSelector} from "react-redux";
import {selectedTest} from "../../redux/quizSlice"; import {selectedTest} from "../../redux/quizSlice";
import React from "react"; import React, {useEffect} from "react";
export const QuizTestPage = () => { export const QuizTestPage = () => {
let navigate = useNavigate() let navigate = useNavigate();
const test = useSelector(selectedTest) const test = useSelector(selectedTest);
useEffect(() => {
if (!test) { if (!test) {
navigate('/quiz') navigate('/quiz')
} }
}, []);
return ( return (
<> <>
<HeaderPageTestsQuiz isVisibilityButton={false}/> <HeaderPageTestsQuiz isVisibilityButton={false}/>

View File

@ -1,6 +1,6 @@
import {createAsyncThunk, createSlice} from '@reduxjs/toolkit'; import {createAsyncThunk, createSlice} from '@reduxjs/toolkit';
import {fetchGet} from './../server/server'
import axios from "axios"; import {apiRequest} from "../api/request";
const initialState = { const initialState = {
@ -15,72 +15,32 @@ const initialState = {
}; };
export const setUserInfo = createAsyncThunk( export const setUserInfo = createAsyncThunk(
'userInfo', 'userInfo',
async (id) => { (id) =>
try{ apiRequest(`/profile/get-main-data?user_id=${id}`)
return await fetchGet({
link: `${process.env.REACT_APP_API_URL}/api/profile/get-main-data?user_id=${id}`,
Origin: `${process.env.REACT_APP_BASE_URL}`,
}
)
}catch (e) {
console.log(e)
}
}
); );
export const fetchUserAnswersMany = createAsyncThunk( export const fetchUserAnswersMany = createAsyncThunk(
'answersUserMany', 'answersUserMany',
async (checkedValues) => { (checkedValues) =>
try{ apiRequest('/user-response/set-responses', {method: 'POST', data: {"userResponses": checkedValues}})
const response = await axios.post(`${process.env.REACT_APP_API_URL}/api/user-response/set-responses`,
{"userResponses": checkedValues}, {
headers: {
Authorization: `Bearer ${localStorage.getItem('auth_token')}`,
}
});
return response.data
}catch (e) {
console.log(e)
}
}
); );
export const fetchUserAnswerOne = createAsyncThunk( export const fetchUserAnswerOne = createAsyncThunk(
'answersUserOne', 'answersUserOne',
async (checkedValues) => { (checkedValues) =>
try{ apiRequest('/user-response/set-response', {method: 'POST', data: checkedValues[0]})
const response = await axios.post(`${process.env.REACT_APP_API_URL}/api/user-response/set-response`,
checkedValues[0], {
headers: {
Authorization: `Bearer ${localStorage.getItem('auth_token')}`,
}
});
return response.data
}catch (e) {
console.log(e)
}
}
); );
export const fetchGetAnswers = createAsyncThunk( export const fetchGetAnswers = createAsyncThunk(
'answers', 'answers',
async (question_id) => { (question_id) =>
return await fetchGet({ apiRequest(`/answer/get-answers?question_id=${question_id}`)
link: `${process.env.REACT_APP_API_URL}/api/answer/get-answers?question_id=${question_id}`,
Origin: `${process.env.REACT_APP_BASE_URL}`,
}
)
}
); );
export const fetchResultTest = createAsyncThunk( export const fetchResultTest = createAsyncThunk(
'result', 'result',
async (uuid) => { (uuid) =>
return await fetchGet({ apiRequest(`/user-questionnaire/questionnaire-completed?user_questionnaire_uuid=${uuid}`)
link: `${process.env.REACT_APP_API_URL}/api/user-questionnaire/questionnaire-completed?user_questionnaire_uuid=${uuid}`,
Origin: `${process.env.REACT_APP_BASE_URL}`,
}
)
}
); );
export const quizSlice = createSlice({ export const quizSlice = createSlice({

View File

@ -1,22 +0,0 @@
export const withAuthRedirect =
(actionCall) =>
({ link, params, history, role, logout, body }) => {
// const linkWithParams = params
// ? `${link}?${new URLSearchParams(params)}`
// : link;
// return actionCall(linkWithParams, body)
// .then((res) => {
// if (res.status && res.status === 401) {
// localStorage.clear();
// logout && logout();
// history.push(role === 'ROLE_DEV' ? '/authdev' : '/auth')
// }
//
// return res
// })
// .catch((err) => {
// localStorage.clear();
// logout && logout();
// history.push(role === 'ROLE_DEV' ? '/authdev' : '/auth')
// })
};

View File

@ -1,18 +0,0 @@
import { withAuthRedirect } from './authRedirect'
export const fetchGet = withAuthRedirect(async (link) => {
try {
const response = await fetch(link, {
method: 'GET',
headers: {
Authorization: `Bearer ${localStorage.getItem('auth_token')}`
}
});
let data = await response.json();
return data
} catch (error) {
console.log('Query error', error)
}
});