Переписываю спорные решения
This commit is contained in:
		| @@ -4,7 +4,6 @@ import {useSelector, useDispatch} from 'react-redux' | ||||
| import { | ||||
|   currentCandidate, | ||||
|   selectCurrentCandidate, | ||||
|   auth | ||||
| } from '../../redux/outstaffingSlice' | ||||
| import {getRole} from '../../redux/roleSlice' | ||||
| import {useState} from 'react' | ||||
| @@ -16,10 +15,11 @@ import SkillSection from '../SkillSection/SkillSection' | ||||
| import front from '../../images/front_end.png' | ||||
| import back from '../../images/back_end.png' | ||||
| import design from '../../images/design.png' | ||||
| import {fetchGet} from '../../server/server' | ||||
|  | ||||
| import {Footer} from '../Footer/Footer' | ||||
|  | ||||
| import './candidate.scss' | ||||
| import {useRequest} from "../../hooks/useRequest"; | ||||
|  | ||||
| const Candidate = () => { | ||||
|   const {id: candidateId} = useParams(); | ||||
| @@ -28,16 +28,15 @@ const Candidate = () => { | ||||
|   const role = useSelector(getRole); | ||||
|   const [activeSnippet, setActiveSnippet] = useState(true); | ||||
|  | ||||
|   const {apiRequest} = useRequest(); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     window.scrollTo(0, 0) | ||||
|   }, []); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     fetchGet({ | ||||
|       link: `${process.env.REACT_APP_API_URL}/api/profile/${candidateId}`, | ||||
|     apiRequest(`/profile/${candidateId}`,{ | ||||
|       params: Number(candidateId), | ||||
|       role, | ||||
|       logout: () => dispatch(auth(false)) | ||||
|     }).then((el) => dispatch(currentCandidate(el))) | ||||
|   }, [dispatch, candidateId]); | ||||
|  | ||||
|   | ||||
| @@ -12,33 +12,27 @@ import {getRole} from '../../redux/roleSlice' | ||||
| import {useRequest} from "../../hooks/useRequest"; | ||||
|  | ||||
|  | ||||
|  | ||||
| const Home = () => { | ||||
|  | ||||
|   const [isLoadingMore, setIsLoadingMore] = useState(false); | ||||
|   const [index, setIndex] = useState(4); | ||||
|  | ||||
|   const dispatch = useDispatch(); | ||||
|   const role = useSelector(getRole); | ||||
|  | ||||
|   const {apiRequest} = useRequest(); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     setIsLoadingMore(true); | ||||
|     apiRequest('/profile',{ | ||||
|       //Корс блокирует все фильтры в гет параметрах | ||||
|       params: {"offset": 1000}, | ||||
|       role, | ||||
|       // logout: () => dispatch(auth(false)) | ||||
|     apiRequest('/profile', { | ||||
|       params: {limit: 1000}, | ||||
|     }).then((profileArr) => { | ||||
|  | ||||
|       dispatch(profiles(profileArr)); | ||||
|       setIsLoadingMore(false) | ||||
|     }); | ||||
|  | ||||
|     apiRequest('/skills/skills-on-main-page',{ | ||||
|  | ||||
|       role, | ||||
|       // logout: () => dispatch(auth(false)) | ||||
|     apiRequest('/skills/skills-on-main-page', { | ||||
|     }).then((skills) => { | ||||
|       if (!skills) { | ||||
|         return [] | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|  | ||||
|   position: relative; | ||||
|   &:hover { | ||||
|     path { | ||||
|       fill: #6aaf5c; | ||||
|   | ||||
| @@ -1,43 +1,38 @@ | ||||
| import React from 'react' | ||||
| import OutsideClickHandler from 'react-outside-click-handler' | ||||
| import { useDispatch, useSelector } from 'react-redux' | ||||
| import {useDispatch, useSelector} from 'react-redux' | ||||
| import { | ||||
|   selectItems, | ||||
|   selectedItems, | ||||
|   filteredCandidates, | ||||
|   auth | ||||
| } from '../../redux/outstaffingSlice' | ||||
|  | ||||
| import { fetchGet } from '../../server/server' | ||||
|  | ||||
| import { getRole } from '../../redux/roleSlice' | ||||
| import {useRequest} from "../../hooks/useRequest"; | ||||
|  | ||||
| import './outstaffingBlock.scss' | ||||
|  | ||||
| const handlePositionClick = ({ | ||||
|   dispatch, | ||||
|   positionId, | ||||
|   isSelected, | ||||
|   onSelect, | ||||
|   role | ||||
| }) => { | ||||
|  | ||||
| const handlePositionClick = ( | ||||
|     { | ||||
|       dispatch, | ||||
|       positionId, | ||||
|       isSelected, | ||||
|       onSelect, | ||||
|       apiRequest | ||||
|     }) => { | ||||
|   if (isSelected) { | ||||
|     fetchGet({ | ||||
|       link: `${process.env.REACT_APP_API_URL}/api/profile?limit=`, | ||||
|       params: 4, | ||||
|       role, | ||||
|       logout: () => dispatch(auth(false)) | ||||
|     apiRequest('/profile', { | ||||
|       params: {limit: 1000}, | ||||
|     }).then((profileArr) => { | ||||
|       dispatch(filteredCandidates(profileArr)); | ||||
|       dispatch(selectedItems([])); | ||||
|       onSelect(positionId) | ||||
|     }) | ||||
|   } else { | ||||
|     fetchGet({ | ||||
|       link: `${process.env.REACT_APP_API_URL}/api/profile?position_id=`, | ||||
|       params: positionId, | ||||
|       role, | ||||
|       logout: () => dispatch(auth(false)) | ||||
|     apiRequest('/profile', { | ||||
|       params: { | ||||
|         limit: '1000', | ||||
|         position_id: positionId}, | ||||
|     }).then((el) => { | ||||
|       dispatch(filteredCandidates(el)); | ||||
|       dispatch(selectedItems([])); | ||||
| @@ -46,25 +41,27 @@ const handlePositionClick = ({ | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const OutstaffingBlock = ({ | ||||
|   dataTags = [], | ||||
|   selected, | ||||
|   img, | ||||
|   header, | ||||
|   positionId, | ||||
|   isSelected, | ||||
|   onSelect | ||||
| }) => { | ||||
| const OutstaffingBlock = ( | ||||
|     { | ||||
|       dataTags = [], | ||||
|       selected, | ||||
|       img, | ||||
|       header, | ||||
|       positionId, | ||||
|       isSelected, | ||||
|       onSelect | ||||
|     }) => { | ||||
|  | ||||
|   const role = useSelector(getRole); | ||||
|  | ||||
|   const dispatch = useDispatch(); | ||||
|  | ||||
|   const itemsArr = useSelector(selectItems); | ||||
|  | ||||
|   const {apiRequest} = useRequest(); | ||||
|  | ||||
|   const handleBlockClick = (item, id) => { | ||||
|     if (!itemsArr.find((el) => item === el.value)) { | ||||
|       dispatch(selectedItems([...itemsArr, { id, value: item, label: item }])) | ||||
|       dispatch(selectedItems([...itemsArr, {id, value: item, label: item}])) | ||||
|     } | ||||
|   }; | ||||
|  | ||||
| @@ -81,56 +78,56 @@ const OutstaffingBlock = ({ | ||||
|   }); | ||||
|  | ||||
|   return ( | ||||
|     <OutsideClickHandler | ||||
|       onOutsideClick={() => { | ||||
|         isSelected && onSelect(null) | ||||
|       }} | ||||
|     > | ||||
|       <div | ||||
|         className={`outstaffing-block${ | ||||
|           isSelected ? ' outstaffing-block__selected' : '' | ||||
|         }`} | ||||
|       <OutsideClickHandler | ||||
|           onOutsideClick={() => { | ||||
|             isSelected && onSelect(null) | ||||
|           }} | ||||
|       > | ||||
|         <div | ||||
|           className={`outstaffing-block__img ${ | ||||
|             selected ? ' outstaffing-block__border' : '' | ||||
|           }`} | ||||
|           onClick={() => | ||||
|             handlePositionClick({ | ||||
|               dispatch, | ||||
|               positionId, | ||||
|               isSelected, | ||||
|               onSelect, | ||||
|               role | ||||
|             }) | ||||
|           } | ||||
|             className={`outstaffing-block${ | ||||
|                 isSelected ? ' outstaffing-block__selected' : '' | ||||
|             }`} | ||||
|         > | ||||
|           <h3>{header}</h3> | ||||
|           <img className={classes} src={img} alt='img' /> | ||||
|           <div | ||||
|               className={`outstaffing-block__img ${ | ||||
|                   selected ? ' outstaffing-block__border' : '' | ||||
|               }`} | ||||
|               onClick={() => | ||||
|                   handlePositionClick({ | ||||
|                     dispatch, | ||||
|                     positionId, | ||||
|                     isSelected, | ||||
|                     onSelect, | ||||
|                     apiRequest | ||||
|                   }) | ||||
|               } | ||||
|           > | ||||
|             <h3>{header}</h3> | ||||
|             <img className={classes} src={img} alt='img'/> | ||||
|           </div> | ||||
|           <div | ||||
|               className={`${ | ||||
|                   selected | ||||
|                       ? 'outstaffing-block__mobile--block' | ||||
|                       : 'outstaffing-block__mobile--none' | ||||
|               }`} | ||||
|           > | ||||
|             <p className='outstaffing-block__text'># Популярный стек</p> | ||||
|             {dataTags && ( | ||||
|                 <ul className='outstaffing-block__items'> | ||||
|                   {dataTags.map((item) => ( | ||||
|                       <li | ||||
|                           key={item.id} | ||||
|                           onClick={() => handleBlockClick(item.value, item.id)} | ||||
|                       > | ||||
|                         {item.value} | ||||
|                       </li> | ||||
|                   ))} | ||||
|                 </ul> | ||||
|             )} | ||||
|           </div> | ||||
|         </div> | ||||
|         <div | ||||
|           className={`${ | ||||
|             selected | ||||
|               ? 'outstaffing-block__mobile--block' | ||||
|               : 'outstaffing-block__mobile--none' | ||||
|           }`} | ||||
|         > | ||||
|           <p className='outstaffing-block__text'># Популярный стек</p> | ||||
|           {dataTags && ( | ||||
|             <ul className='outstaffing-block__items'> | ||||
|               {dataTags.map((item) => ( | ||||
|                 <li | ||||
|                   key={item.id} | ||||
|                   onClick={() => handleBlockClick(item.value, item.id)} | ||||
|                 > | ||||
|                   {item.value} | ||||
|                 </li> | ||||
|               ))} | ||||
|             </ul> | ||||
|           )} | ||||
|         </div> | ||||
|       </div> | ||||
|     </OutsideClickHandler> | ||||
|       </OutsideClickHandler> | ||||
|   ) | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -2,7 +2,6 @@ import React, { useEffect, useState } from 'react' | ||||
| import {useDispatch, useSelector} from 'react-redux' | ||||
| import { getProfileInfo } from '../../redux/outstaffingSlice' | ||||
| import { setReportDate } from '../../redux/reportSlice'; | ||||
| import {fetchGet} from "../../server/server"; | ||||
| import arrow from "../../images/right-arrow.png"; | ||||
| import { Link } from 'react-router-dom' | ||||
| import moment from "moment"; | ||||
| @@ -12,40 +11,42 @@ import {ProfileCalendarComponent} from "./ProfileCalendarComponent"; | ||||
| import { Footer } from '../Footer/Footer' | ||||
|  | ||||
| import './profileCalendar.scss' | ||||
| import {useRequest} from "../../hooks/useRequest"; | ||||
| export const ProfileCalendar = () => { | ||||
|     const dispatch = useDispatch(); | ||||
|     const profileInfo = useSelector(getProfileInfo) | ||||
|     const [month, setMonth] = useState('') | ||||
|     const [reports, setReports] = useState([]) | ||||
|     const [totalHours, setTotalHours] = useState(0) | ||||
|     const [value, setValue] = useState(moment()) | ||||
|     const [requestDates, setRequestDates] = useState('') | ||||
|     const profileInfo = useSelector(getProfileInfo); | ||||
|     const [month, setMonth] = useState(''); | ||||
|     const [reports, setReports] = useState([]); | ||||
|     const [totalHours, setTotalHours] = useState(0); | ||||
|     const [value, setValue] = useState(moment()); | ||||
|     const [requestDates, setRequestDates] = useState(''); | ||||
|  | ||||
|     const {apiRequest} = useRequest(); | ||||
|  | ||||
|     useEffect(() => { | ||||
|         setRequestDates(getReports(value)) | ||||
|     }) | ||||
|     }); | ||||
|  | ||||
|     useEffect(async () => { | ||||
|         if (!requestDates) { | ||||
|             return | ||||
|         } | ||||
|         const response = await fetchGet({ | ||||
|             link: `${process.env.REACT_APP_API_URL}/api/reports/reports-by-date?${requestDates}&user_id=${localStorage.getItem('id')}`, | ||||
|         }).then((reports) => { | ||||
|             let spendTime = 0 | ||||
|             reports.map((report)=> { | ||||
|                 if (report.spendTime) { | ||||
|                     spendTime += Number(report.spendTime) | ||||
|                 } | ||||
|         apiRequest(`/reports/reports-by-date?${requestDates}&user_id=${localStorage.getItem('id')}`) | ||||
|             .then((reports) => { | ||||
|                 let spendTime = 0; | ||||
|                 reports.map((report) => { | ||||
|                     if (report.spendTime) { | ||||
|                         spendTime += Number(report.spendTime) | ||||
|                     } | ||||
|                 }); | ||||
|                 setTotalHours(spendTime); | ||||
|                 setReports(reports) | ||||
|             }) | ||||
|             setTotalHours(spendTime) | ||||
|             setReports(reports) | ||||
|         }) | ||||
|     },[requestDates]) | ||||
|     }, [requestDates]); | ||||
|  | ||||
|     useEffect(() => { | ||||
|         setMonth(currentMonth) | ||||
|     }, [month]) | ||||
|     }, [month]); | ||||
|  | ||||
|     return ( | ||||
|         <section className='calendar'> | ||||
|   | ||||
| @@ -28,7 +28,6 @@ const getCreatedDate = (day) => { | ||||
|  | ||||
| const ReportForm = () => { | ||||
|   const dispatch = useDispatch(); | ||||
|   const navigate = useNavigate(); | ||||
|   const reportDate = useSelector(getReportDate); | ||||
|   const role = useSelector(getRole); | ||||
|  | ||||
|   | ||||
| @@ -1,41 +1,39 @@ | ||||
| import React, { useState } from 'react' | ||||
| import { useSelector, useDispatch } from 'react-redux' | ||||
| import React, {useState} from 'react' | ||||
| import {useSelector, useDispatch} from 'react-redux' | ||||
| import Select from 'react-select' | ||||
| import { Loader } from '../Loader/Loader' | ||||
| import style from './TagSelect.module.css' | ||||
| import {Loader} from '../Loader/Loader' | ||||
| import {useRequest} from "../../hooks/useRequest"; | ||||
| import { | ||||
|   selectedItems, | ||||
|   selectItems, | ||||
|   selectTags, | ||||
|   filteredCandidates, | ||||
|   setPositionId, | ||||
|   auth | ||||
|   setPositionId | ||||
| } from '../../redux/outstaffingSlice' | ||||
| import { fetchGet } from '../../server/server' | ||||
|  | ||||
| import { getRole } from '../../redux/roleSlice' | ||||
| import style from './TagSelect.module.css' | ||||
|  | ||||
|  | ||||
| const TagSelect = () => { | ||||
|  | ||||
|   const role = useSelector(getRole); | ||||
|   const [searchLoading, setSearchLoading] = useState(false); | ||||
|   const dispatch = useDispatch(); | ||||
|  | ||||
|   const itemsArr = useSelector(selectItems); | ||||
|   const {apiRequest} = useRequest(); | ||||
|  | ||||
|   const itemsArr = useSelector(selectItems); | ||||
|   const tagsArr = useSelector(selectTags); | ||||
|  | ||||
|   const handleSubmit = ({ dispatch, setSearchLoading }) => { | ||||
|   const handleSubmit = ({dispatch, setSearchLoading}) => { | ||||
|     setSearchLoading(true); | ||||
|  | ||||
|     dispatch(setPositionId(null)); | ||||
|     const filterItemsId = itemsArr.map((item) => item.id).join(); | ||||
|     const params = filterItemsId ?  {skill: filterItemsId} : ''; | ||||
|  | ||||
|     fetchGet({ | ||||
|       link: `${process.env.REACT_APP_API_URL}/api/profile?skills=`, | ||||
|       params: filterItemsId, | ||||
|       role, | ||||
|       logout: () => dispatch(auth(false)) | ||||
|  | ||||
|     apiRequest('/profile', { | ||||
|       params: {...params, limit: 1000}, | ||||
|     }).then((el) => { | ||||
|       dispatch(filteredCandidates(el)); | ||||
|       setSearchLoading(false) | ||||
| @@ -45,44 +43,44 @@ const TagSelect = () => { | ||||
|   }; | ||||
|  | ||||
|   return ( | ||||
|     <> | ||||
|       <section className={style.search}> | ||||
|         <div className='row'> | ||||
|           <div className='col-12'> | ||||
|             <h2 className={style.search__title}> | ||||
|               Найти специалиста по навыкам | ||||
|             </h2> | ||||
|             <div className={style.search__box}> | ||||
|               <Select | ||||
|                 value={itemsArr} | ||||
|                 onChange={(value) => dispatch(selectedItems(value))} | ||||
|                 isMulti | ||||
|                 name='tags' | ||||
|                 className={style.select} | ||||
|                 classNamePrefix={style.select} | ||||
|                 options={ | ||||
|                   tagsArr && | ||||
|                   tagsArr.flat().map((item) => { | ||||
|                     return { | ||||
|                       id: item.id, | ||||
|                       value: item.value, | ||||
|                       label: item.value | ||||
|       <> | ||||
|         <section className={style.search}> | ||||
|           <div className='row'> | ||||
|             <div className='col-12'> | ||||
|               <h2 className={style.search__title}> | ||||
|                 Найти специалиста по навыкам | ||||
|               </h2> | ||||
|               <div className={style.search__box}> | ||||
|                 <Select | ||||
|                     value={itemsArr} | ||||
|                     onChange={(value) => {console.log(value) ;return dispatch(selectedItems(value))}} | ||||
|                     isMulti | ||||
|                     name='tags' | ||||
|                     className={style.select} | ||||
|                     classNamePrefix={style.select} | ||||
|                     options={ | ||||
|                       tagsArr && | ||||
|                       tagsArr.flat().map((item) => { | ||||
|                         return { | ||||
|                           id: item.id, | ||||
|                           value: item.value, | ||||
|                           label: item.value | ||||
|                         } | ||||
|                       }) | ||||
|                     } | ||||
|                   }) | ||||
|                 } | ||||
|               /> | ||||
|               <button | ||||
|                 onClick={() => handleSubmit({ dispatch, setSearchLoading })} | ||||
|                 type='submit' | ||||
|                 className={style.search__submit} | ||||
|               > | ||||
|                 {searchLoading ? <Loader width={30} height={30} /> : 'Поиск'} | ||||
|               </button> | ||||
|                 /> | ||||
|                 <button | ||||
|                     onClick={() => handleSubmit({dispatch, setSearchLoading})} | ||||
|                     type='submit' | ||||
|                     className={style.search__submit} | ||||
|                 > | ||||
|                   {searchLoading ? <Loader width={30} height={30}/> : 'Поиск'} | ||||
|                 </button> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </section> | ||||
|     </> | ||||
|         </section> | ||||
|       </> | ||||
|   ) | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -1,102 +1,101 @@ | ||||
| import React, { useEffect, useState } from 'react'; | ||||
| import { ContentTitle } from "../ContentTitle/ContentTitle" | ||||
| import { ContentButton } from "../ContentButton/ContentButton" | ||||
| import { BookkeepingFormField } from "../BookkeepingFormField/BookkeepingFormField" | ||||
| import { BookkepingSelect } from '../BookkepingSelect/BookkepingSelect'; | ||||
| import { BookkepingInput } from '../BookkepingInput/BookkepingInput'; | ||||
| import { fetchGet } from '../../../../server/server' | ||||
| import { Link } from "react-router-dom" | ||||
| import React, {useEffect, useState} from 'react'; | ||||
| import {Link} from "react-router-dom" | ||||
| import {ContentTitle} from "../ContentTitle/ContentTitle" | ||||
| import {ContentButton} from "../ContentButton/ContentButton" | ||||
| import {BookkeepingFormField} from "../BookkeepingFormField/BookkeepingFormField" | ||||
| import {BookkepingSelect} from '../BookkepingSelect/BookkepingSelect'; | ||||
| import {BookkepingInput} from '../BookkepingInput/BookkepingInput'; | ||||
|  | ||||
| import {useRequest} from "../../../../hooks/useRequest"; | ||||
|  | ||||
| import "./actContent.css" | ||||
|  | ||||
| export const ActContent = ()=> { | ||||
|       | ||||
|     const [templates, setTemplates] = useState([]) | ||||
|     const [selectedTemplate, setSelectedTemplate] = useState() | ||||
|     const [templatedFields, setTemplatedFields] = useState([]) | ||||
| export const ActContent = () => { | ||||
|  | ||||
|     useEffect(() => { | ||||
|         fetchGet({ | ||||
|           link: `${process.env.REACT_APP_API_URL}/api/template/get-template-list`, | ||||
|         }).then((res) => { | ||||
|             setTemplates(res) | ||||
|         }) | ||||
|       }, []) | ||||
|   const [templates, setTemplates] = useState([]); | ||||
|   const [selectedTemplate, setSelectedTemplate] = useState(); | ||||
|   const [templatedFields, setTemplatedFields] = useState([]); | ||||
|  | ||||
|       useEffect(() => { | ||||
|         if (selectedTemplate === undefined) { | ||||
|             return | ||||
|         } | ||||
|         fetchGet({ | ||||
|             link: `${process.env.REACT_APP_API_URL}/api/template/get-template-fields?template_id=${selectedTemplate}`, | ||||
|           }) | ||||
|           .then((res) => { | ||||
|             setTemplatedFields(res[0].templateDocumentFields) | ||||
|           }) | ||||
|       }, [selectedTemplate]) | ||||
|   const {apiRequest} = useRequest(); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     apiRequest('/template/get-template-list') | ||||
|         .then(res => setTemplates(res)) | ||||
|   }, []); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     if (selectedTemplate === undefined) { | ||||
|       return | ||||
|     } | ||||
|     apiRequest(`/template/get-template-fields?template_id=${selectedTemplate}`) | ||||
|         .then(res => setTemplatedFields(res[0].templateDocumentFields)) | ||||
|   }, [selectedTemplate]); | ||||
|  | ||||
|  | ||||
|        | ||||
|   return ( | ||||
|       <div> | ||||
|         <div className="content__info"> | ||||
|           <ContentTitle title="Создание акта" description="# Описание"/> | ||||
|           <div className="content__info-main"> | ||||
|             <form className='contract'> | ||||
|               <div className="contract__create"> | ||||
|                 <div className="contract__title">Создание акта №</div> | ||||
|                 <input type="text" className="contract__number" placeholder="#"/> | ||||
|                 <span>от</span> | ||||
|                 <input type="date" className="contract__date"/> | ||||
|               </div> | ||||
|  | ||||
|     return( | ||||
|         <div> | ||||
|             <div className="content__info"> | ||||
|             <ContentTitle title="Создание акта" description="# Описание" /> | ||||
|             <div className="content__info-main"> | ||||
|                 <form className='contract'> | ||||
|                     <div className="contract__create"> | ||||
|                         <div className="contract__title">Создание акта №</div> | ||||
|                         <input type="text" className="contract__number" placeholder="#" /> | ||||
|                         <span>от</span> | ||||
|                         <input type="date" className="contract__date" /> | ||||
|                     </div> | ||||
|               <BookkeepingFormField | ||||
|                   title="Шаблон документа" | ||||
|                   Component={BookkepingSelect} | ||||
|                   innerComponentProps={{ | ||||
|                     onSelect: setSelectedTemplate, | ||||
|                     textField: "title", | ||||
|                     options: templates, | ||||
|                     defaultIndexSelected: 0, | ||||
|                   }} | ||||
|                   action={{ | ||||
|                     text: "Добавить свой шаблон", | ||||
|                     method: () => { | ||||
|                     } | ||||
|                   }} | ||||
|               /> | ||||
|  | ||||
|                     <BookkeepingFormField title="Шаблон документа" | ||||
|                         Component={BookkepingSelect}  | ||||
|                         innerComponentProps={{ | ||||
|                             onSelect: setSelectedTemplate, | ||||
|                             textField: "title", | ||||
|                             options: templates, | ||||
|                             defaultIndexSelected: 0, | ||||
|                         }} | ||||
|                         action={{ | ||||
|                             text: "Добавить свой шаблон", | ||||
|                             method: () => {} | ||||
|                         }} | ||||
|                     /> | ||||
|                      | ||||
|                         {templatedFields.map((field, index ) =>  | ||||
|                             <BookkeepingFormField title={field.field.title} key={index} | ||||
|                             Component={BookkepingInput} | ||||
|                             innerComponentProps={{ | ||||
|                                 placeholder: "Введите данные", | ||||
|                             }} | ||||
|                         /> | ||||
|                         )} | ||||
|               {templatedFields.map((field, index) => | ||||
|                   <BookkeepingFormField | ||||
|                       title={field.field.title} key={index} | ||||
|                       Component={BookkepingInput} | ||||
|                       innerComponentProps={{ | ||||
|                         placeholder: "Введите данные", | ||||
|                       }} | ||||
|                   /> | ||||
|               )} | ||||
|  | ||||
|                      | ||||
|  | ||||
|                     <div className="content__btn-list"> | ||||
|                         <ContentButton styles={{ width: "290px", | ||||
|                         height: "75px", | ||||
|                         boxShadow: "6px 5px 20px rgba(182, 75, 62, 0.21)", | ||||
|                         borderRadius: "38px", | ||||
|                         backgroundColor: "#b64b3e", | ||||
|                         border: "none", | ||||
|                         color: "#ffffff", | ||||
|                         }}>Сохранить</ContentButton> | ||||
|                         <Link to="/documents" className="link-act-button"> | ||||
|                             <div className='act-Button'> | ||||
|                                 <ContentButton styles={{color: "#282828", | ||||
|                                 marginLeft: "40px", | ||||
|                                 background: "none", | ||||
|                                 border: "none" | ||||
|                                 }}>Отменить</ContentButton> | ||||
|                             </div> | ||||
|                         </Link> | ||||
|                     </div> | ||||
|                 </form> | ||||
|             </div> | ||||
|               <div className="content__btn-list"> | ||||
|                 <ContentButton styles={{ | ||||
|                   width: "290px", | ||||
|                   height: "75px", | ||||
|                   boxShadow: "6px 5px 20px rgba(182, 75, 62, 0.21)", | ||||
|                   borderRadius: "38px", | ||||
|                   backgroundColor: "#b64b3e", | ||||
|                   border: "none", | ||||
|                   color: "#ffffff", | ||||
|                 }}>Сохранить</ContentButton> | ||||
|                 <Link to="/documents" className="link-act-button"> | ||||
|                   <div className='act-Button'> | ||||
|                     <ContentButton styles={{ | ||||
|                       color: "#282828", | ||||
|                       marginLeft: "40px", | ||||
|                       background: "none", | ||||
|                       border: "none" | ||||
|                     }}>Отменить</ContentButton> | ||||
|                   </div> | ||||
|                 </Link> | ||||
|               </div> | ||||
|             </form> | ||||
|           </div> | ||||
|         </div> | ||||
|         </div> | ||||
|     ) | ||||
| } | ||||
|       </div> | ||||
|   ) | ||||
| }; | ||||
| @@ -1,97 +1,98 @@ | ||||
| import React, { useEffect, useState } from "react"; | ||||
| import { ContentTitle } from "../ContentTitle/ContentTitle" | ||||
| import { ContentButton } from "../ContentButton/ContentButton" | ||||
| import { BookkeepingFormField } from "../BookkeepingFormField/BookkeepingFormField" | ||||
| import { BookkepingSelect } from '../BookkepingSelect/BookkepingSelect'; | ||||
| import { BookkepingInput } from '../BookkepingInput/BookkepingInput'; | ||||
| import { fetchGet } from '../../../../server/server' | ||||
| import { Link } from "react-router-dom" | ||||
| import React, {useEffect, useState} from "react"; | ||||
| import {ContentTitle} from "../ContentTitle/ContentTitle" | ||||
| import {ContentButton} from "../ContentButton/ContentButton" | ||||
| import {BookkeepingFormField} from "../BookkeepingFormField/BookkeepingFormField" | ||||
| import {BookkepingSelect} from '../BookkepingSelect/BookkepingSelect'; | ||||
| import {BookkepingInput} from '../BookkepingInput/BookkepingInput'; | ||||
| import {Link} from "react-router-dom" | ||||
| import {useRequest} from "../../../../hooks/useRequest"; | ||||
|  | ||||
| export const ContractContent = () => { | ||||
|  | ||||
|     const [templates, setTemplates] = useState([]) | ||||
|     const [selectedTemplate, setSelectedTemplate] = useState() | ||||
|     const [templatedFields, setTemplatedFields] = useState([]) | ||||
|      | ||||
|     useEffect(() => { | ||||
|         fetchGet({ | ||||
|           link: `${process.env.REACT_APP_API_URL}/api/document/get-document-list`, | ||||
|         }).then((res) => { | ||||
|             setTemplates(res) | ||||
|         }) | ||||
|       }, []) | ||||
|   const [templates, setTemplates] = useState([]); | ||||
|   const [selectedTemplate, setSelectedTemplate] = useState(); | ||||
|   const [templatedFields, setTemplatedFields] = useState([]); | ||||
|  | ||||
|       useEffect(() => { | ||||
|         if (selectedTemplate === undefined) { | ||||
|             return | ||||
|         } | ||||
|         fetchGet({ | ||||
|             link: `${process.env.REACT_APP_API_URL}/api/document/get-document?document_id=${selectedTemplate}`, | ||||
|           }) | ||||
|           .then((res) => { | ||||
|             setTemplatedFields(res[0].templateDocumentFields) | ||||
|           }) | ||||
|       }, [selectedTemplate]) | ||||
|   const {apiRequest} = useRequest(); | ||||
|  | ||||
|     return ( | ||||
|         <div> | ||||
|             <div className="content__info"> | ||||
|             <ContentTitle  title="Создание договора" description="# Описание" /> | ||||
|             <div className="content__info-main"> | ||||
|                  | ||||
|   useEffect(() => { | ||||
|     apiRequest(`/document/get-document-list`) | ||||
|         .then(res => setTemplates(res)) | ||||
|   }, []); | ||||
|  | ||||
|                 <form className='contract'> | ||||
|                     <div className="contract__create"> | ||||
|                         <div className="contract__title">Создание договора №</div> | ||||
|                         <input type="text" className="contract__number" placeholder="#" /> | ||||
|                         <span>от</span> | ||||
|                         <input type="date" className="contract__date" /> | ||||
|                     </div> | ||||
|                     <BookkeepingFormField title="Шаблон документа" | ||||
|                         Component={BookkepingSelect}  | ||||
|                         innerComponentProps={{ | ||||
|                             onSelect: setSelectedTemplate, | ||||
|                             textField: "title", | ||||
|                             options: templates, | ||||
|                             defaultIndexSelected: 0, | ||||
|                         }} | ||||
|                         action={{ | ||||
|                             text: "Добавить свой шаблон", | ||||
|                             method: () => {} | ||||
|                         }} | ||||
|                     /> | ||||
|                      | ||||
|                     {templatedFields.map((field, index ) =>  | ||||
|                             <BookkeepingFormField title={field.field.title} key={index} | ||||
|                             Component={BookkepingInput} | ||||
|                             innerComponentProps={{ | ||||
|                                 placeholder: "Введите данные", | ||||
|                             }} | ||||
|                         /> | ||||
|                         )} | ||||
|   useEffect(() => { | ||||
|     if (selectedTemplate === undefined) { | ||||
|       return | ||||
|     } | ||||
|     apiRequest(`/document/get-document?document_id=${selectedTemplate}`) | ||||
|         .then(res => setTemplatedFields(res[0].templateDocumentFields) | ||||
|         ) | ||||
|   }, [selectedTemplate]); | ||||
|  | ||||
|                     <div className="content__btn-list"> | ||||
|                         <ContentButton styles={{ width: "290px", | ||||
|                         height: "75px", | ||||
|                         boxShadow: "6px 5px 20px rgba(182, 75, 62, 0.21)", | ||||
|                         borderRadius: "38px", | ||||
|                         backgroundColor: "#b64b3e", | ||||
|                         border: "none", | ||||
|                         color: "#ffffff", | ||||
|                         }}>Сохранить</ContentButton> | ||||
|                         <Link to="/documents" className="link-act-button"> | ||||
|                             <div className='act-Button'> | ||||
|                                 <ContentButton styles={{color: "#282828", | ||||
|                                 marginLeft: "40px", | ||||
|                                 background: "none", | ||||
|                                 border: "none" | ||||
|                                 }}>Отменить</ContentButton> | ||||
|                             </div> | ||||
|                         </Link> | ||||
|                     </div> | ||||
|                 </form> | ||||
|             </div> | ||||
|   return ( | ||||
|       <div> | ||||
|         <div className="content__info"> | ||||
|           <ContentTitle title="Создание договора" description="# Описание"/> | ||||
|           <div className="content__info-main"> | ||||
|  | ||||
|  | ||||
|             <form className='contract'> | ||||
|               <div className="contract__create"> | ||||
|                 <div className="contract__title">Создание договора №</div> | ||||
|                 <input type="text" className="contract__number" placeholder="#"/> | ||||
|                 <span>от</span> | ||||
|                 <input type="date" className="contract__date"/> | ||||
|               </div> | ||||
|               <BookkeepingFormField | ||||
|                   title="Шаблон документа" | ||||
|                   Component={BookkepingSelect} | ||||
|                   innerComponentProps={{ | ||||
|                     onSelect: setSelectedTemplate, | ||||
|                     textField: "title", | ||||
|                     options: templates, | ||||
|                     defaultIndexSelected: 0, | ||||
|                   }} | ||||
|                   action={{ | ||||
|                     text: "Добавить свой шаблон", | ||||
|                     method: () => { | ||||
|                     } | ||||
|                   }} | ||||
|               /> | ||||
|  | ||||
|               {templatedFields.map((field, index) => | ||||
|                   <BookkeepingFormField | ||||
|                       title={field.field.title} key={index} | ||||
|                       Component={BookkepingInput} | ||||
|                       innerComponentProps={{ | ||||
|                         placeholder: "Введите данные", | ||||
|                       }} | ||||
|                   /> | ||||
|               )} | ||||
|  | ||||
|               <div className="content__btn-list"> | ||||
|                 <ContentButton styles={{ | ||||
|                   width: "290px", | ||||
|                   height: "75px", | ||||
|                   boxShadow: "6px 5px 20px rgba(182, 75, 62, 0.21)", | ||||
|                   borderRadius: "38px", | ||||
|                   backgroundColor: "#b64b3e", | ||||
|                   border: "none", | ||||
|                   color: "#ffffff", | ||||
|                 }}>Сохранить</ContentButton> | ||||
|                 <Link to="/documents" className="link-act-button"> | ||||
|                   <div className='act-Button'> | ||||
|                     <ContentButton styles={{ | ||||
|                       color: "#282828", | ||||
|                       marginLeft: "40px", | ||||
|                       background: "none", | ||||
|                       border: "none" | ||||
|                     }}>Отменить</ContentButton> | ||||
|                   </div> | ||||
|                 </Link> | ||||
|               </div> | ||||
|             </form> | ||||
|           </div> | ||||
|         </div> | ||||
|         </div> | ||||
|     ) | ||||
| }  | ||||
|       </div> | ||||
|   ) | ||||
| }; | ||||
| @@ -1,50 +1,46 @@ | ||||
| import {useEffect} from 'react' | ||||
| import {useDispatch} from 'react-redux' | ||||
| import {useSelector} from 'react-redux' | ||||
| import {fetchGet} from '../../../server/server' | ||||
| import React, {useEffect} from 'react' | ||||
| import {useDispatch, useSelector} from 'react-redux' | ||||
| import {selectUserInfo, setQuestionnairesList, setUserInfo} from "../../../redux/quizSlice"; | ||||
| import {useRequest} from "../../../hooks/useRequest"; | ||||
| import './quiz.scss' | ||||
| import {selectUserInfo, setQuestionnairesList, setUserInfo,} from "../../../redux/quizSlice"; | ||||
|  | ||||
| export const HeaderQuiz = ({header}) => { | ||||
|  | ||||
|    const dispatch = useDispatch() | ||||
|    const userId = localStorage.getItem('id'); | ||||
|    const userInfo = useSelector(selectUserInfo); | ||||
|   const dispatch = useDispatch(); | ||||
|   const userId = localStorage.getItem('id'); | ||||
|   const userInfo = useSelector(selectUserInfo); | ||||
|  | ||||
|    useEffect(() => { | ||||
|       dispatch(setUserInfo(userId)) | ||||
|    }, [dispatch]) | ||||
|   const {apiRequest} = useRequest(); | ||||
|  | ||||
|    useEffect(() => { | ||||
|       fetchGet({ | ||||
|            link: `${process.env.REACT_APP_API_URL}/api/user-questionnaire/questionnaires-list?user_id=${userId}`, | ||||
|            Origin: `${process.env.REACT_APP_BASE_URL}`, | ||||
|         } | ||||
|       ).then(response => { | ||||
|          dispatch(setQuestionnairesList(response)) | ||||
|       }) | ||||
|    }, [dispatch]) | ||||
|   useEffect(() => { | ||||
|     dispatch(setUserInfo(userId)) | ||||
|   }, [dispatch]); | ||||
|  | ||||
|    return ( | ||||
|        <div> | ||||
|        { userInfo?.status === 500 ? <div className="error-msg">{userInfo.message}</div> : | ||||
|          <div className="header-quiz"> | ||||
|             <div className="header-quiz__container"> | ||||
|                {!userInfo ? <h2>Loading...</h2> : | ||||
|                  <> | ||||
|                     {header && <h2 className={'header-quiz__title-main'}>Добрый день, {userInfo.fio}</h2>} | ||||
|                     <div className="header-quiz__body header-quiz__body_interjacent"> | ||||
|                        <div className="header-quiz__avatar"> | ||||
|   useEffect(() => { | ||||
|     apiRequest(`/user-questionnaire/questionnaires-list?user_id=${userId}`) | ||||
|         .then(res => dispatch(setQuestionnairesList(res))) | ||||
|   }, [dispatch]); | ||||
|  | ||||
|   return ( | ||||
|       <div> | ||||
|         {userInfo?.status === 500 ? <div className="error-msg">{userInfo.message}</div> : | ||||
|             <div className="header-quiz"> | ||||
|               <div className="header-quiz__container"> | ||||
|                 {!userInfo ? <h2>Loading...</h2> : | ||||
|                     <> | ||||
|                       {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}/> | ||||
|                        </div> | ||||
|                        <div className="header-quiz__name-user">{userInfo.fio}</div> | ||||
|                        <div className="header-quiz__title">{userInfo.position_name}</div> | ||||
|                     </div> | ||||
|                  </> | ||||
|                } | ||||
|                         </div> | ||||
|                         <div className="header-quiz__name-user">{userInfo.fio}</div> | ||||
|                         <div className="header-quiz__title">{userInfo.position_name}</div> | ||||
|                       </div> | ||||
|                     </> | ||||
|                 } | ||||
|               </div> | ||||
|             </div> | ||||
|          </div> | ||||
|        } | ||||
|        </div> | ||||
|    ) | ||||
| } | ||||
|         } | ||||
|       </div> | ||||
|   ) | ||||
| }; | ||||
|   | ||||
| @@ -5,23 +5,26 @@ import './quiz.scss' | ||||
| import {useEffect, useState} from "react"; | ||||
| import {useSelector} from "react-redux"; | ||||
| import {selectedTest} from "../../../redux/quizSlice"; | ||||
| import {fetchGet} from "../../../server/server"; | ||||
|  | ||||
| import {useRequest} from "../../../hooks/useRequest"; | ||||
|  | ||||
| export const Instruction = () => { | ||||
|  | ||||
|    const [countQuestions, setCountQuestions] = useState(null) | ||||
|    const test = useSelector(selectedTest) | ||||
|    const [countQuestions, setCountQuestions] = useState(null); | ||||
|    const test = useSelector(selectedTest); | ||||
|  | ||||
|    useEffect(async () => { | ||||
|   const {apiRequest} = useRequest(); | ||||
|  | ||||
|       const response = await fetchGet({ | ||||
|            link: `${process.env.REACT_APP_API_URL}/api/user-questionnaire/get-question-number?user_questionnaire_uuid=${test.uuid}`, | ||||
|            Origin: `${process.env.REACT_APP_BASE_URL}`, | ||||
|         } | ||||
|       ) | ||||
|       setCountQuestions(response.question_number) | ||||
|    useEffect( () => { | ||||
|  | ||||
|    }, []) | ||||
|      apiRequest('/user-questionnaire/get-question-number', { | ||||
|            params: {user_questionnaire_uuid: test.uuid}, | ||||
|  | ||||
|          } | ||||
|      ).then((res)=> setCountQuestions(res.question_number)) | ||||
|  | ||||
|  | ||||
|    }, []); | ||||
|  | ||||
|    return ( | ||||
|      <div className="instruction"> | ||||
| @@ -49,5 +52,5 @@ export const Instruction = () => { | ||||
|         </div> | ||||
|      </div> | ||||
|    ) | ||||
| } | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -1,37 +1,35 @@ | ||||
| import React, {useEffect, useState} from 'react'; | ||||
| import {useDispatch, useSelector} from "react-redux"; | ||||
| import {fetchResultTest, selectedTest, selectResult} from "../../../redux/quizSlice"; | ||||
| import {fetchGet} from "../../../server/server"; | ||||
| import {useRequest} from "../../../hooks/useRequest"; | ||||
|  | ||||
|  | ||||
| export const Results = () => { | ||||
|    const result = useSelector(selectResult); | ||||
|    const test = useSelector(selectedTest); | ||||
|    const [maxScore, setMaxScore] = useState(''); | ||||
|    const dispatch = useDispatch(); | ||||
|   const result = useSelector(selectResult); | ||||
|   const test = useSelector(selectedTest); | ||||
|   const [maxScore, setMaxScore] = useState(''); | ||||
|   const dispatch = useDispatch(); | ||||
|   const {apiRequest} = useRequest(); | ||||
|  | ||||
|    useEffect(async () => { | ||||
|       dispatch(fetchResultTest(test.uuid)); | ||||
|       const response = await fetchGet({ | ||||
|            link: `${process.env.REACT_APP_API_URL}/api/user-questionnaire/get-points-number?user_questionnaire_uuid=${test.uuid}`, | ||||
|            Origin: `${process.env.REACT_APP_BASE_URL}`, | ||||
|         } | ||||
|       ); | ||||
|       setMaxScore(response.sum_point) | ||||
|    }, []); | ||||
|   useEffect(async () => { | ||||
|     dispatch(fetchResultTest(test.uuid)); | ||||
|     apiRequest(`/user-questionnaire/get-points-number?user_questionnaire_uuid=${test.uuid}`) | ||||
|         .then((res) => setMaxScore(res.sum_point)); | ||||
|  | ||||
|    return ( | ||||
|      <div className={'result _container'}> | ||||
|   }, []); | ||||
|  | ||||
|   return ( | ||||
|       <div className={'result _container'}> | ||||
|         { | ||||
|            !result ? <h1 style={{display: "block"}}>Ожидайте результата...</h1> : | ||||
|           !result ? <h1 style={{display: "block"}}>Ожидайте результата...</h1> : | ||||
|  | ||||
|              <div className="result__body"> | ||||
|               <div className="result__body"> | ||||
|                 <div className="result__text">Благодарим за прохождение теста</div> | ||||
|                 <div className="result__text">Ваш Результат: <span | ||||
|                   className="result__score">{result.score}</span> из {maxScore} </div> | ||||
|              </div> | ||||
|                     className="result__score">{result.score}</span> из {maxScore} </div> | ||||
|               </div> | ||||
|         } | ||||
|      </div> | ||||
|    ); | ||||
|       </div> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| import React, {useEffect, useState} from 'react' | ||||
| import { useNavigate} from "react-router-dom" | ||||
| import {useNavigate} from "react-router-dom" | ||||
| import {useSelector, useDispatch} from 'react-redux' | ||||
|  | ||||
| import { | ||||
|    fetchGetAnswers, | ||||
|    selectAnswer, | ||||
|    selectedTest | ||||
|   fetchGetAnswers, | ||||
|   selectAnswer, | ||||
|   selectedTest | ||||
| } from '../../../redux/quizSlice' | ||||
|  | ||||
| import {Progressbar} from './ProgressbarQuiz' | ||||
| @@ -13,140 +13,141 @@ import {GetOptionTask} from './GetOptionTask' | ||||
|  | ||||
| import {fetchUserAnswersMany, fetchUserAnswerOne} from './../../../redux/quizSlice' | ||||
|  | ||||
| import {fetchGet} from "../../../server/server"; | ||||
|  | ||||
| import './quiz.scss' | ||||
| import {useRequest} from "../../../hooks/useRequest"; | ||||
|  | ||||
| export const TaskQuiz = () => { | ||||
|  | ||||
|    const navigate = useNavigate(); | ||||
|    const dispatch = useDispatch(); | ||||
|   const navigate = useNavigate(); | ||||
|   const dispatch = useDispatch(); | ||||
|  | ||||
|    const listAnswers = useSelector(selectAnswer); | ||||
|    const dataTest = useSelector(selectedTest); | ||||
|   const listAnswers = useSelector(selectAnswer); | ||||
|   const dataTest = useSelector(selectedTest); | ||||
|  | ||||
|    const [index, setIndex] = useState(0); | ||||
|    const [checkedValues, setCheckedValues] = useState([]); | ||||
|    const [stripValue, setStripValue] = useState(0); | ||||
|    const [inputValue, setInputValue] = useState(''); | ||||
|    const [questions, setQuestions] = useState([]); | ||||
|   const [index, setIndex] = useState(0); | ||||
|   const [checkedValues, setCheckedValues] = useState([]); | ||||
|   const [stripValue, setStripValue] = useState(0); | ||||
|   const [inputValue, setInputValue] = useState(''); | ||||
|   const [questions, setQuestions] = useState([]); | ||||
|  | ||||
|    const id = localStorage.getItem('id'); | ||||
|   const {apiRequest} = useRequest(); | ||||
|  | ||||
|    useEffect( () => { | ||||
|       const response = fetchGet({ | ||||
|            link: `${process.env.REACT_APP_API_URL}/api/question/get-questions?uuid=${dataTest.uuid}`, | ||||
|            Origin: `${process.env.REACT_APP_BASE_URL}`, | ||||
|         } | ||||
|       ); | ||||
|       setQuestions(response); | ||||
|       dispatch(fetchGetAnswers(response[0].id)); | ||||
|       setStripValue((+index + 1) * 100 / response.length) | ||||
|    }, [dispatch]); | ||||
|   const id = localStorage.getItem('id'); | ||||
|  | ||||
|    const nextQuestion = async (e) => { | ||||
|       e.preventDefault(); | ||||
|   useEffect(() => { | ||||
|     apiRequest(`/question/get-questions?uuid=${dataTest.uuid}`) | ||||
|         .then((response) => { | ||||
|           setQuestions(response); | ||||
|           dispatch(fetchGetAnswers(response[0].id)); | ||||
|           setStripValue((+index + 1) * 100 / response.length) | ||||
|         }) | ||||
|   }, [dispatch]); | ||||
|  | ||||
|       //Проверка на валидацию ответов | ||||
|       if (checkedValues.length || inputValue) { | ||||
|          switch (questions[index].question_type_id) { | ||||
|             case '3': | ||||
|                dispatch(fetchUserAnswersMany(checkedValues)); | ||||
|                break; | ||||
|             case '2': | ||||
|             case '1': | ||||
|             case '4': | ||||
|                dispatch(fetchUserAnswerOne(checkedValues)); | ||||
|                break; | ||||
|             default: | ||||
|                break; | ||||
|          } | ||||
|   const nextQuestion = async (e) => { | ||||
|     e.preventDefault(); | ||||
|  | ||||
|          //Проверка на существование следующего запроса | ||||
|          if (index < questions.length - 1) { | ||||
|             await dispatch(fetchGetAnswers(questions[index + 1].id)); | ||||
|             setIndex(prev => prev >= questions.length - 1 ? prev : prev + 1); | ||||
|             setStripValue((prev => prev + (100 / questions.length))); | ||||
|             setCheckedValues([]); | ||||
|             setInputValue('') | ||||
|          } else { | ||||
|             navigate(`/quiz-result`); | ||||
|             alert("Тест пройден!") | ||||
|          } | ||||
|  | ||||
|       } else { | ||||
|          alert("Вы не ответили на вопрос") | ||||
|       } | ||||
|    }; | ||||
|  | ||||
|    const handleChange = (e) => { | ||||
|       const checked = e.target.checked; | ||||
|     //Проверка на валидацию ответов | ||||
|     if (checkedValues.length || inputValue) { | ||||
|       switch (questions[index].question_type_id) { | ||||
|          case '3': | ||||
|             checked ? setCheckedValues(prev => [...prev, { | ||||
|                  user_id: id, | ||||
|                  user_questionnaire_uuid: dataTest.uuid, | ||||
|                  question_id: questions[index].id, | ||||
|                  response_body: e.target.value | ||||
|               }]) : | ||||
|               setCheckedValues(prev => [...prev.filter(item => item.response_body !== e.target.value)]); | ||||
|             break; | ||||
|          case '1': | ||||
|          case '2': | ||||
|          case '4': | ||||
|             setCheckedValues([{ | ||||
|                user_id: id, | ||||
|                user_questionnaire_uuid: dataTest.uuid, | ||||
|                question_id: questions[index].id, | ||||
|                response_body: e.target.value | ||||
|             }]) | ||||
|         case '3': | ||||
|           dispatch(fetchUserAnswersMany(checkedValues)); | ||||
|           break; | ||||
|         case '2': | ||||
|         case '1': | ||||
|         case '4': | ||||
|           dispatch(fetchUserAnswerOne(checkedValues)); | ||||
|           break; | ||||
|         default: | ||||
|           break; | ||||
|       } | ||||
|    }; | ||||
|  | ||||
|       //Проверка на существование следующего запроса | ||||
|       if (index < questions.length - 1) { | ||||
|         await dispatch(fetchGetAnswers(questions[index + 1].id)); | ||||
|         setIndex(prev => prev >= questions.length - 1 ? prev : prev + 1); | ||||
|         setStripValue((prev => prev + (100 / questions.length))); | ||||
|         setCheckedValues([]); | ||||
|         setInputValue('') | ||||
|       } else { | ||||
|         navigate(`/quiz-result`); | ||||
|         alert("Тест пройден!") | ||||
|       } | ||||
|  | ||||
|     } else { | ||||
|       alert("Вы не ответили на вопрос") | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   const handleChange = (e) => { | ||||
|     const checked = e.target.checked; | ||||
|     switch (questions[index].question_type_id) { | ||||
|       case '3': | ||||
|         checked ? setCheckedValues(prev => [...prev, { | ||||
|               user_id: id, | ||||
|               user_questionnaire_uuid: dataTest.uuid, | ||||
|               question_id: questions[index].id, | ||||
|               response_body: e.target.value | ||||
|             }]) : | ||||
|             setCheckedValues(prev => [...prev.filter(item => item.response_body !== e.target.value)]); | ||||
|         break; | ||||
|       case '1': | ||||
|       case '2': | ||||
|       case '4': | ||||
|         setCheckedValues([{ | ||||
|           user_id: id, | ||||
|           user_questionnaire_uuid: dataTest.uuid, | ||||
|           question_id: questions[index].id, | ||||
|           response_body: e.target.value | ||||
|         }]) | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|  | ||||
|    return ( | ||||
|      <React.StrictMode> | ||||
|   return ( | ||||
|       <React.StrictMode> | ||||
|         <Progressbar indexQuestion={index + 1} width={stripValue}/> | ||||
|         <div className="task"> | ||||
|            {!questions.length || !stripValue || !listAnswers.length ? | ||||
|              <h1 className={'_container'} style={{display: "block"}}>Loading....</h1> | ||||
|              : | ||||
|              <div className="task__container"> | ||||
|           {!questions.length || !stripValue || !listAnswers.length ? | ||||
|               <h1 className={'_container'} style={{display: "block"}}>Loading....</h1> | ||||
|               : | ||||
|               <div className="task__container"> | ||||
|                 <div className="task__code code"> | ||||
|                    {/* <CodeSnippetlighter /> */} | ||||
|                   {/* <CodeSnippetlighter /> */} | ||||
|                 </div> | ||||
|                 <h3 className="task__title quiz-title_h3">{questions[index].question_body}</h3> | ||||
|                 <div className="task__body"> | ||||
|                    <form className='task__form form-task'> | ||||
|                       { | ||||
|                          questions[index].question_type_id === 1 ? | ||||
|                            <GetOptionTask | ||||
|                              type={1} | ||||
|                              inputValue={checkedValues.length ? checkedValues[0].response_body : ''} | ||||
|                              handleChange={handleChange} | ||||
|                            /> | ||||
|                            : | ||||
|                            listAnswers.map((answer) => ( | ||||
|                              <GetOptionTask | ||||
|                                key={answer.id} | ||||
|                                type={questions[index].question_type_id} | ||||
|                                handleChange={handleChange} | ||||
|                                answer={answer} | ||||
|                              /> | ||||
|                            )) | ||||
|                       } | ||||
|                       <div className="form-task__buttons"> | ||||
|                          {questions.length !== index + 1 && | ||||
|                          <button type='submit' className='quiz-btn' | ||||
|                                  onClick={(e) => nextQuestion(e)}>Далее</button>} | ||||
|                          {questions.length === index + 1 && <button onClick={(e) => nextQuestion(e)} | ||||
|                                                                     className='quiz-btn quiz-btn_dark-green'>Завершить</button>} | ||||
|                       </div> | ||||
|                    </form> | ||||
|                   <form className='task__form form-task'> | ||||
|                     { | ||||
|                       questions[index].question_type_id === 1 ? | ||||
|                           <GetOptionTask | ||||
|                               type={1} | ||||
|                               inputValue={checkedValues.length ? checkedValues[0].response_body : ''} | ||||
|                               handleChange={handleChange} | ||||
|                           /> | ||||
|                           : | ||||
|                           listAnswers.map((answer) => ( | ||||
|                               <GetOptionTask | ||||
|                                   key={answer.id} | ||||
|                                   type={questions[index].question_type_id} | ||||
|                                   handleChange={handleChange} | ||||
|                                   answer={answer} | ||||
|                               /> | ||||
|                           )) | ||||
|                     } | ||||
|                     <div className="form-task__buttons"> | ||||
|                       {questions.length !== index + 1 && | ||||
|                       <button type='submit' className='quiz-btn' | ||||
|                               onClick={(e) => nextQuestion(e)}>Далее</button>} | ||||
|                       {questions.length === index + 1 && | ||||
|                       <button onClick={(e) => nextQuestion(e)} | ||||
|                               className='quiz-btn quiz-btn_dark-green'>Завершить</button>} | ||||
|                     </div> | ||||
|                   </form> | ||||
|                 </div> | ||||
|              </div> | ||||
|            } | ||||
|               </div> | ||||
|           } | ||||
|         </div> | ||||
|      </React.StrictMode> | ||||
|    ) | ||||
|       </React.StrictMode> | ||||
|   ) | ||||
| }; | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| import React from "react"; | ||||
| import {useDispatch, useSelector} from "react-redux"; | ||||
| import {getRole} from "../redux/roleSlice"; | ||||
| import {useNavigate} from "react-router-dom"; | ||||
| @@ -12,7 +11,6 @@ export const useLogout = () => { | ||||
|   const logout = () => { | ||||
|     localStorage.clear(); | ||||
|     dispatch(auth(false)); | ||||
|     console.log('logout') | ||||
|     navigate(userRole === 'ROLE_DEV' ? '/authdev' : '/auth') | ||||
|   }; | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
| import React from "react"; | ||||
| import axios from 'axios'; | ||||
| import {getToken, urlHasParams} from "../helper"; | ||||
| import {useNavigate} from "react-router"; | ||||
| import {useLogout} from "./useLogout"; | ||||
|  | ||||
|  | ||||
| @@ -38,7 +36,6 @@ export const useRequest = () => { | ||||
|         }) | ||||
|         .then(response => new Promise(resolve => { | ||||
|           if (response.data.redirect || response.status === 401) { | ||||
|             console.log(response, 'LOGUTATAT') | ||||
|             logout() | ||||
|           } | ||||
|           return resolve(response) | ||||
|   | ||||
| @@ -4,13 +4,11 @@ import {useParams, useNavigate} from 'react-router-dom' | ||||
| import { | ||||
|   currentCandidate, | ||||
|   selectCurrentCandidate, | ||||
|   auth | ||||
| } 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 {fetchGet} from '../server/server' | ||||
| import {Footer} from '../components/Footer/Footer' | ||||
|  | ||||
| import arrow from '../images/right-arrow.png' | ||||
| @@ -18,7 +16,7 @@ import rectangle from '../images/rectangle_secondPage.png' | ||||
| import telegramIcon from '../images/telegram-icon.svg' | ||||
|  | ||||
| import './formPage.scss' | ||||
| import {getRole} from '../redux/roleSlice' | ||||
| import {useRequest} from "../hooks/useRequest"; | ||||
|  | ||||
|  | ||||
| const FormPage = () => { | ||||
| @@ -26,20 +24,19 @@ const FormPage = () => { | ||||
|   const navigate = useNavigate(); | ||||
|   const dispatch = useDispatch(); | ||||
|   const candidate = useSelector(selectCurrentCandidate); | ||||
|   const role = useSelector(getRole); | ||||
|  | ||||
|  | ||||
|   const {apiRequest} = useRequest(); | ||||
|  | ||||
|   const goBack = () => { | ||||
|     navigate(-1) | ||||
|   }; | ||||
|  | ||||
|   if (!candidate.id) { | ||||
|     fetchGet({ | ||||
|       link: `${process.env.REACT_APP_API_URL}/api/profile/`, | ||||
|       params: Number(params.id), | ||||
|       navigate, | ||||
|       role, | ||||
|       logout: () => dispatch(auth(false)) | ||||
|     }).then((el) => dispatch(currentCandidate(el))) | ||||
|     apiRequest('/api/profile', { | ||||
|       params: Number(params.id) | ||||
|     }) | ||||
|         .then((el) => dispatch(currentCandidate(el))) | ||||
|   } | ||||
|  | ||||
|   return ( | ||||
|   | ||||
| @@ -1,104 +1,101 @@ | ||||
| import React, {useEffect, useState} from 'react'; | ||||
| import {useSelector} from "react-redux"; | ||||
| import {ProfileHeader} from "../../components/ProfileHeader/ProfileHeader"; | ||||
| import {getProfileInfo} from "../../redux/outstaffingSlice"; | ||||
| import {useSelector} from "react-redux"; | ||||
| import {transformHtml} from "../../helper"; | ||||
| import {Footer} from '../../components/Footer/Footer' | ||||
| import {transformHtml} from "../../helper"; | ||||
|  | ||||
| import {useRequest} from "../../hooks/useRequest"; | ||||
|  | ||||
| import arrow from "../../images/right-arrow.png"; | ||||
| import rightArrow from "../../images/arrowRight.png" | ||||
| import gitImgItem from "../../images/gitItemImg.png" | ||||
|  | ||||
| import {fetchGet} from "../../server/server"; | ||||
|  | ||||
| import './summary.scss' | ||||
|  | ||||
|  | ||||
|  | ||||
| export const Summary = () => { | ||||
|     const profileInfo = useSelector(getProfileInfo); | ||||
|     const [openGit, setOpenGit] = useState(false); | ||||
|     const [gitInfo, setGitInfo] = useState([]); | ||||
|     useEffect(() => { | ||||
|         fetchGet({ | ||||
|             link: `${process.env.REACT_APP_API_URL}/api/profile/portfolio-projects?card_id=${localStorage.getItem('cardId')}`, | ||||
|         }).then((responseGit) => { | ||||
|             setGitInfo(responseGit) | ||||
|         }) | ||||
|     }, []); | ||||
|     return( | ||||
|         <div className='summary'> | ||||
|             <ProfileHeader/> | ||||
|             <div className='container'> | ||||
|                 <div className='summary__content'> | ||||
|                     <h2 className='summary__title'>Ваше резюме {openGit &&  <span>- Git</span>}</h2> | ||||
|                     {openGit && <div className='summary__back' onClick={() => setOpenGit(false)}> | ||||
|                         <img src={arrow} alt='arrow'/> | ||||
|                         <p>Вернуться</p> | ||||
|                     </div>} | ||||
|                     <div className='summary__info'> | ||||
|                         <div className='summary__person'> | ||||
|                             <img src={profileInfo.photo} className='summary__avatar' alt='avatar'/> | ||||
|                             <p className='summary__name'>{profileInfo.fio} {profileInfo.specification}</p> | ||||
|                         </div> | ||||
|                         {!openGit && | ||||
|                         <button className='summary__git' onClick={()=> setOpenGit(true)}>Git</button> | ||||
|                         } | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 {!openGit && | ||||
|                     <div className='summary__skills skills__section'> | ||||
|                         <div className='summary__sections__head'> | ||||
|                             <h3>Основной стек</h3> | ||||
|                             <button>Редактировать раздел</button> | ||||
|                         </div> | ||||
|                         <div className='skills__section__items'> | ||||
|                             <div className='skills__section__items__wrapper'> | ||||
|                                 {profileInfo.skillValues && profileInfo.skillValues.map((skill) => { | ||||
|                                     return <span key={skill.id} className='skill_item'>{skill.skill.name}</span> | ||||
|                                 })} | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 } | ||||
|                 {profileInfo.vc_text && !openGit && | ||||
|                     <div className='summary__experience' dangerouslySetInnerHTML={transformHtml(profileInfo.vc_text)}> | ||||
|                     </div> | ||||
|                 } | ||||
|                 {openGit && | ||||
|                     <div className='summary__sectionGit'> | ||||
|                         <div className='summary__sections__head'> | ||||
|                             <h3>Страница портфолио кода разработчика</h3> | ||||
|                             <button>Редактировать раздел</button> | ||||
|                         </div> | ||||
|                         <div className='summary__sectionGitItems'> | ||||
|                             {gitInfo.length && gitInfo.map((itemGit) => { | ||||
|                                 return <div key={itemGit.id} className='summary__sectionGitItem gitItem'> | ||||
|                                             <div className='gitItem__info'> | ||||
|                                                 <div className='gitItem__info__about'> | ||||
|                                                     <img src={gitImgItem} alt='gitImg' /> | ||||
|                                                     <div className='gitItem__info__name'> | ||||
|                                                         <h4>{itemGit.title}</h4> | ||||
|                                                         <p>{itemGit.description}</p> | ||||
|                                                     </div> | ||||
|                                                 </div> | ||||
|                                                 <div className='gitItem__info__specification'> | ||||
|                                                     <span className='gitItem__lineSkill'/> | ||||
|                                                     <p>{itemGit.main_stack}</p> | ||||
|                                                 </div> | ||||
|                                             </div> | ||||
|                                             <a className='gitItem__link' href={itemGit.link} target="_blank" rel="noreferrer"> | ||||
|                                                 <img src={rightArrow} alt='arrowRight' /> | ||||
|                                             </a> | ||||
|                                         </div> | ||||
|                                 }) | ||||
|                             } | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 } | ||||
|   const profileInfo = useSelector(getProfileInfo); | ||||
|   const [openGit, setOpenGit] = useState(false); | ||||
|   const [gitInfo, setGitInfo] = useState([]); | ||||
|  | ||||
|   const {apiRequest} = useRequest(); | ||||
|   useEffect(() => { | ||||
|     apiRequest(`/profile/portfolio-projects?card_id=${localStorage.getItem('cardId')}`) | ||||
|         .then(responseGit => setGitInfo(responseGit)) | ||||
|   }, [apiRequest]); | ||||
|   return ( | ||||
|       <div className='summary'> | ||||
|         <ProfileHeader/> | ||||
|         <div className='container'> | ||||
|           <div className='summary__content'> | ||||
|             <h2 className='summary__title'>Ваше резюме {openGit && <span>- Git</span>}</h2> | ||||
|             {openGit && <div className='summary__back' onClick={() => setOpenGit(false)}> | ||||
|               <img src={arrow} alt='arrow'/> | ||||
|               <p>Вернуться</p> | ||||
|             </div>} | ||||
|             <div className='summary__info'> | ||||
|               <div className='summary__person'> | ||||
|                 <img src={profileInfo.photo} className='summary__avatar' alt='avatar'/> | ||||
|                 <p className='summary__name'>{profileInfo.fio} {profileInfo.specification}</p> | ||||
|               </div> | ||||
|               {!openGit && | ||||
|               <button className='summary__git' onClick={() => setOpenGit(true)}>Git</button> | ||||
|               } | ||||
|             </div> | ||||
|             <Footer/> | ||||
|           </div> | ||||
|           {!openGit && | ||||
|           <div className='summary__skills skills__section'> | ||||
|             <div className='summary__sections__head'> | ||||
|               <h3>Основной стек</h3> | ||||
|               <button>Редактировать раздел</button> | ||||
|             </div> | ||||
|             <div className='skills__section__items'> | ||||
|               <div className='skills__section__items__wrapper'> | ||||
|                 {profileInfo.skillValues && profileInfo.skillValues.map((skill) => | ||||
|                     <span key={skill.id} className='skill_item'>{skill.skill.name}</span> | ||||
|                 )} | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|           } | ||||
|           {profileInfo.vc_text && !openGit && | ||||
|           <div className='summary__experience' dangerouslySetInnerHTML={transformHtml(profileInfo.vc_text)}> | ||||
|           </div> | ||||
|           } | ||||
|           {openGit && | ||||
|           <div className='summary__sectionGit'> | ||||
|             <div className='summary__sections__head'> | ||||
|               <h3>Страница портфолио кода разработчика</h3> | ||||
|               <button>Редактировать раздел</button> | ||||
|             </div> | ||||
|             <div className='summary__sectionGitItems'> | ||||
|               {gitInfo.length && gitInfo.map((itemGit) => { | ||||
|                 return <div key={itemGit.id} className='summary__sectionGitItem gitItem'> | ||||
|                   <div className='gitItem__info'> | ||||
|                     <div className='gitItem__info__about'> | ||||
|                       <img src={gitImgItem} alt='gitImg'/> | ||||
|                       <div className='gitItem__info__name'> | ||||
|                         <h4>{itemGit.title}</h4> | ||||
|                         <p>{itemGit.description}</p> | ||||
|                       </div> | ||||
|                     </div> | ||||
|                     <div className='gitItem__info__specification'> | ||||
|                       <span className='gitItem__lineSkill'/> | ||||
|                       <p>{itemGit.main_stack}</p> | ||||
|                     </div> | ||||
|                   </div> | ||||
|                   <a className='gitItem__link' href={itemGit.link} target="_blank" rel="noreferrer"> | ||||
|                     <img src={rightArrow} alt='arrowRight'/> | ||||
|                   </a> | ||||
|                 </div> | ||||
|               }) | ||||
|               } | ||||
|             </div> | ||||
|           </div> | ||||
|           } | ||||
|         </div> | ||||
|     ) | ||||
|         <Footer/> | ||||
|       </div> | ||||
|   ) | ||||
| }; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user