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