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

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

14314
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",
"moment": "^2.29.1",
"prompts": "2.4.0",
"react": "^17.0.2",
"react": "^18.2.0",
"react-app-polyfill": "^2.0.0",
"react-bootstrap": "^1.6.0",
"react-dev-utils": "^11.0.3",
"react-dom": "^17.0.2",
"react-inlinesvg": "^2.3.0",
"react-dev-utils": "^12.0.1",
"react-dom": "^18.2.0",
"react-inlinesvg": "3.0.1",
"react-loader-spinner": "^4.0.0",
"react-outside-click-handler": "^1.3.0",
"react-phone-input-2": "^2.14.0",
"react-redux": "^7.2.4",
"react-refresh": "^0.8.3",
"react-router": "latest",
"react-router-dom": "^6.2.1",
"react-select": "^4.3.1",
"react-select": "^5.7.0",
"react-syntax-highlighter": "^15.4.5",
"react-yandex-metrika": "^2.6.0",
"redux-devtools-extension": "^2.13.9",
"resolve": "1.18.1",
"resolve-url-loader": "^3.1.2",
"semver": "7.3.2",
"sweetalert2-react": "^0.8.3"
"sweetalert2": "^11.4.8"
},
"devDependencies": {
"@babel/core": "^7.20.12",
"@babel/preset-env": "^7.20.2",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"babel-loader": "^9.1.2",
"copy-webpack-plugin": "^10.2.0",
"cross-env": "^7.0.3",
"css-loader": "^6.7.3",
"css-loader": "6.7.3",
"dotenv-webpack": "^7.0.3",
"html-webpack-plugin": "latest",
"html-webpack-plugin": "5.5.0",
"mini-css-extract-plugin": "^2.7.2",
"node-sass": "^6.0.1",
"node-sass": "8.0.0",
"postcss": "^8.4.21",
"postcss-loader": "^6.2.1",
"postcss-preset-env": "^7.8.3",
"react-hot-loader": "^4.13.0",
"react-scripts": "5.0.1",
"sass": "^1.57.1",
"sass-loader": "^12.6.0",
"react-refresh": "^0.14.0",
"react-scripts": "^5.0.1",
"sass": "^1.58.0",
"sass-loader": "^13.2.0",
"sweetalert2-react-content": "^5.0.7",
"universal-cookie": "^4.0.4",
"web-vitals": "^3.1.1",
"webpack": "latest",
"webpack-bundle-analyzer": "latest",
"webpack-cli": "latest",
"webpack-dev-server": "latest",
"webpack-merge": "latest"
"webpack": "5.75.0",
"webpack-bundle-analyzer": "4.7.0",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "4.11.1",
"webpack-merge": "5.8.0"
},
"scripts": {
"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 {useDispatch, useSelector} from 'react-redux'
import {withSwalInstance} from 'sweetalert2-react'
import swal from 'sweetalert2'
import {Loader} from '../Loader/Loader'
import ErrorBoundary from "../../hoc/ErrorBoundary";
@ -10,7 +8,6 @@ import ErrorBoundary from "../../hoc/ErrorBoundary";
import {auth, selectAuth, setUserInfo} from '../../redux/outstaffingSlice'
import {loading} from '../../redux/loaderSlice'
import {setRole} from '../../redux/roleSlice'
import {selectIsLoading} from '../../redux/loaderSlice'
import {apiRequest} from "../../api/request";
@ -19,12 +16,14 @@ import ellipse from '../../images/ellipse.png'
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}) => {
const dispatch = useDispatch();
const ref = useRef();
const navigate = useNavigate();
@ -34,19 +33,32 @@ export const AuthBox = ({title, altTitle, roleChangeLink}) => {
const [error, setError] = useState(null);
if (isAuth) {
navigate('/')
}
const handleModalError = (error) => {
SweetAlert.fire({
title: 'Ошибка',
text: error
});
useEffect(()=> {
setError(null)
};
useEffect(() => {
if (!localStorage.getItem('auth_token')) {
dispatch(auth(false))
}
}, []);
useEffect(() => {
if (isAuth) {
navigate('/')
}
});
const submitHandler = () => {
let formData = new FormData(ref.current)
let formData = new FormData(ref.current);
if (!isLoading) {
dispatch(loading(true));
apiRequest('/user/login',
@ -107,12 +119,17 @@ export const AuthBox = ({title, altTitle, roleChangeLink}) => {
{error && (
<div className='auth-box__form-error'>
<ErrorBoundary>
<SweetAlert
show={!!error}
title='Ошибка'
text={error}
onConfirm={() => setError(null)}
/>
{
handleModalError(error)
}
{/*<SweetAlert*/}
{/* show={!!error}*/}
{/* title='Ошибка'*/}
{/* text={error}*/}
{/* onConfirm={() => setError(null)}*/}
{/*/>*/}
</ErrorBoundary>
</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 { Loader } from '../Loader/Loader'
import {Loader} from '../Loader/Loader'
import PhoneInput from 'react-phone-input-2'
import 'react-phone-input-2/lib/style.css'
import './form.scss'
import { withSwalInstance } from 'sweetalert2-react'
import swal from 'sweetalert2'
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 navigate = useNavigate();
const urlParams = useParams();
const [status, setStatus] = useState(null);
const [data, setData] = useState({
email: '',
@ -25,9 +26,29 @@ const Form = () => {
});
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 { id, value } = e.target;
const {id, value} = e.target;
setData((prev) => ({
...prev,
@ -41,11 +62,11 @@ const Form = () => {
setIsFetching(true);
const formData = new FormData();
formData.append('profile_id', urlParams.id);
formData.append('email', data.email);
formData.append('Email', data.email);
formData.append('phone', data.phone);
formData.append('comment', data.comment);
apiRequest('/interview-request/create-interview-request',{
apiRequest('/interview-request/create-interview-request', {
method: 'POST',
params: {
profile_id: urlParams.id,
@ -59,49 +80,28 @@ const Form = () => {
};
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='col-sm-12'>
<form className='form' id='test'>
<label htmlFor='email'>Емейл:</label>
<input
onChange={handleChange}
id='email'
name='Email'
type='email'
placeholder='Емейл'
value={data.email}
onChange={handleChange}
id='email'
name='Email'
type='email'
placeholder='Емейл'
value={data.email}
/>
<label htmlFor='phone'>Номер телефона:</label>
<PhoneInput
id='phone'
name='Phone'
country={'ru'}
value={data.phone}
onChange={(e) =>
handleChange({ target: { value: e, id: 'phone' } })
}
id='phone'
name='Phone'
country={'ru'}
value={data.phone}
onChange={(e) =>
handleChange({target: {value: e, id: 'phone'}})
}
/>
{/* <input
onChange={handleChange}
@ -113,22 +113,21 @@ const Form = () => {
/> */}
<textarea
onChange={handleChange}
id='comment'
rows='5'
cols='40'
name='Comment'
placeholder='Оставьте комментарий'
value={data.comment}
onChange={handleChange}
id='comment'
rows='5'
cols='40'
name='Comment'
placeholder='Оставьте комментарий'
value={data.comment}
></textarea>
<button onClick={handleSubmit} className='form__btn' type='submit'>
{isFetching ? <Loader /> : 'Отправить'}
{isFetching ? <Loader/> : 'Отправить'}
</button>
</form>
</div>
</div>
</>
)
};

View File

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

View File

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

View File

@ -1,8 +1,9 @@
import {Link} from 'react-router-dom'
import calendarImage from './../../../images/calendar.svg'
import './quiz.scss'
import {useDispatch} from "react-redux";
import {setSelectedTest} from "../../../redux/quizSlice";
import {urlForLocal} from "../../../helper";
import './quiz.scss'
export const MyTestsQuiz = ({listTests}) => {
@ -46,7 +47,7 @@ export const MyTestsQuiz = ({listTests}) => {
</h3>
<div className="item-test__body test-data">
<div className="test-data__calendar ">
<img src={calendarImage} alt=""/>
<img src={urlForLocal(calendarImage)} alt=""/>
{item.testing_date}
</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 ReactDOM from 'react-dom'
import { store } from './store/store'
import { Provider } from 'react-redux'
import ReactDOM from 'react-dom/client'
import {store} from './store/store'
import {Provider} from 'react-redux'
import App from './App'
import './index.css'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
ReactDOM.createRoot(document.getElementById("root"))
.render(
<Provider store={store}>
<App/>
</Provider>,
);

View File

@ -1,12 +1,12 @@
import React from 'react'
import React, {useEffect} from 'react'
import {useDispatch, useSelector} from 'react-redux'
import {useParams, useNavigate} from 'react-router-dom'
import SVG from 'react-inlinesvg'
import {WithLogout} from '../../hoc/withLogout'
import Form from '../../components/Form/Form'
import {Footer} from '../../components/Footer/Footer'
import {LogoutButton} from "../../components/LogoutButton/LogoutButton";
import arrow from '../../images/right-arrow.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 './formPage.scss'
import {apiRequest} from "../../api/request";
import {LogoutButton} from "../../components/LogoutButton/LogoutButton";
import {urlForLocal} from "../../helper";
import './formPage.scss'
const FormPage = () => {
const params = useParams();
@ -29,23 +27,22 @@ const FormPage = () => {
const dispatch = useDispatch();
const candidate = useSelector(selectCurrentCandidate);
const goBack = () => {
navigate(-1)
};
if (!candidate.id) {
apiRequest('/profile', {
params: Number(params.id)
})
.then((el) => dispatch(currentCandidate(el)))
}
useEffect(()=> {
if (!candidate.id) {
apiRequest('/profile', {
params: Number(params.id)
})
.then((el) => dispatch(currentCandidate(el)))
}
}, []);
return (
<div className='container'>
<div className='form-page'>
<div className='form-page__back'>
<div className='form-page__arrow' onClick={goBack}>
@ -60,7 +57,7 @@ const FormPage = () => {
</div>
<div className='form-page__candidate'>
<div className='form-page__avatar'>
<img src={candidate.photo} alt='candidate avatar'/>
{candidate.photo && <img src={urlForLocal(candidate.photo)} alt='candidate avatar'/>}
</div>
<div className='form-page__candidate-info'>
<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 {useSelector} from "react-redux";
import {selectedTest} from "../../redux/quizSlice";
import React from "react";
import React, {useEffect} from "react";
export const QuizTestPage = () => {
let navigate = useNavigate()
const test = useSelector(selectedTest)
let navigate = useNavigate();
const test = useSelector(selectedTest);
useEffect(() => {
if (!test) {
navigate('/quiz')
}
}, []);
if (!test) {
navigate('/quiz')
}
return (
<>
<HeaderPageTestsQuiz isVisibilityButton={false}/>

View File

@ -1,111 +1,71 @@
import {createAsyncThunk, createSlice} from '@reduxjs/toolkit';
import {fetchGet} from './../server/server'
import axios from "axios";
import {apiRequest} from "../api/request";
const initialState = {
// questions: [],
answer: [],
result: null,
isLoading: false,
dataQuestionnairesOfUser: [],
passedTests: [],
selectedTest: null,
userInfo: null
// questions: [],
answer: [],
result: null,
isLoading: false,
dataQuestionnairesOfUser: [],
passedTests: [],
selectedTest: null,
userInfo: null
};
export const setUserInfo = createAsyncThunk(
'userInfo',
async (id) => {
try{
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)
}
}
'userInfo',
(id) =>
apiRequest(`/profile/get-main-data?user_id=${id}`)
);
export const fetchUserAnswersMany = createAsyncThunk(
'answersUserMany',
async (checkedValues) => {
try{
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)
}
}
'answersUserMany',
(checkedValues) =>
apiRequest('/user-response/set-responses', {method: 'POST', data: {"userResponses": checkedValues}})
);
export const fetchUserAnswerOne = createAsyncThunk(
'answersUserOne',
async (checkedValues) => {
try{
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)
}
}
'answersUserOne',
(checkedValues) =>
apiRequest('/user-response/set-response', {method: 'POST', data: checkedValues[0]})
);
export const fetchGetAnswers = createAsyncThunk(
'answers',
async (question_id) => {
return await fetchGet({
link: `${process.env.REACT_APP_API_URL}/api/answer/get-answers?question_id=${question_id}`,
Origin: `${process.env.REACT_APP_BASE_URL}`,
}
)
}
'answers',
(question_id) =>
apiRequest(`/answer/get-answers?question_id=${question_id}`)
);
export const fetchResultTest = createAsyncThunk(
'result',
async (uuid) => {
return await fetchGet({
link: `${process.env.REACT_APP_API_URL}/api/user-questionnaire/questionnaire-completed?user_questionnaire_uuid=${uuid}`,
Origin: `${process.env.REACT_APP_BASE_URL}`,
}
)
}
'result',
(uuid) =>
apiRequest(`/user-questionnaire/questionnaire-completed?user_questionnaire_uuid=${uuid}`)
);
export const quizSlice = createSlice({
name: 'quiz',
initialState,
reducers: {
setQuestionnairesList: (state, action) => {
state.dataQuestionnairesOfUser = action.payload;
state.passedTests = action.payload.filter(item => item.status === 2)
},
setSelectedTest: (state, action) => {
state.selectedTest = action.payload
},
},
extraReducers: {
[setUserInfo.fulfilled]: (state, action) => {
state.userInfo = action.payload;
},
[fetchGetAnswers.fulfilled]: (state, action) => {
state.answer = action.payload;
},
[fetchResultTest.fulfilled]: (state, action) => {
state.result = action.payload;
},
},
name: 'quiz',
initialState,
reducers: {
setQuestionnairesList: (state, action) => {
state.dataQuestionnairesOfUser = action.payload;
state.passedTests = action.payload.filter(item => item.status === 2)
},
setSelectedTest: (state, action) => {
state.selectedTest = action.payload
},
},
extraReducers: {
[setUserInfo.fulfilled]: (state, action) => {
state.userInfo = action.payload;
},
[fetchGetAnswers.fulfilled]: (state, action) => {
state.answer = action.payload;
},
[fetchResultTest.fulfilled]: (state, action) => {
state.result = action.payload;
},
},
});
export const {setQuestionnairesList, setSelectedTest} = quizSlice.actions;

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)
}
});