Merge pull request #42 from apuc/viewReportPage

View report page
This commit is contained in:
NikoM1k 2023-01-23 22:52:05 +02:00 committed by GitHub
commit da75e68af9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 481 additions and 10 deletions

View File

@ -18,6 +18,7 @@ import {InstructionPage} from './pages/quiz/InstructionPage'
import {ResultPage} from './pages/quiz/ResultPage' import {ResultPage} from './pages/quiz/ResultPage'
import {Profile} from './pages/Profile/Profile.js' import {Profile} from './pages/Profile/Profile.js'
import {Summary} from './pages/Summary/Summary' import {Summary} from './pages/Summary/Summary'
import {ViewReport} from './pages/ViewReport/ViewReport'
import './fonts/stylesheet.css' import './fonts/stylesheet.css'
import 'bootstrap/dist/css/bootstrap.min.css' import 'bootstrap/dist/css/bootstrap.min.css'
@ -55,6 +56,7 @@ const App = () => {
<Route index element={<Profile/>}/> <Route index element={<Profile/>}/>
<Route exact path='calendar' element={<ProfileCalendar/>}/> <Route exact path='calendar' element={<ProfileCalendar/>}/>
<Route exact path='summary' element={<Summary/>}/> <Route exact path='summary' element={<Summary/>}/>
<Route exact path='view' element={<ViewReport/>}/>
</Route> </Route>
<Route path="*" element={<Navigate to="/" replace/>}/> <Route path="*" element={<Navigate to="/" replace/>}/>

View File

@ -33,14 +33,16 @@ export const ProfileCalendar = () => {
if (!requestDates) { if (!requestDates) {
return return
} }
apiRequest(`/reports/reports-by-date?${requestDates}&user_id=${localStorage.getItem('id')}`) apiRequest(`/reports/reports-by-date?${requestDates}&user_card_id=${localStorage.getItem('cardId')}`)
.then((reports) => { .then((reports) => {
let spendTime = 0; let spendTime = 0;
reports.map((report) => { for (const report of reports) {
if (report.spendTime) { report.task.map((task) => {
spendTime += Number(report.spendTime) if(task.hours_spent) {
spendTime += Number(task.hours_spent)
}
})
} }
});
setTotalHours(spendTime); setTotalHours(spendTime);
setReports(reports) setReports(reports)
}) })

View File

@ -37,7 +37,7 @@ export const ProfileCalendarComponent = ({reportsDates}) => {
function dayStyles(day) { function dayStyles(day) {
if (value < day) return `block` if (value < day) return `block`
for (const date of reportsDates) { for (const date of reportsDates) {
if (`${new Date(day).getFullYear()}-${correctDay(new Date(day).getMonth() + 1)}-${correctDay(new Date(day).getDate())}` === date.date) { if (`${new Date(day).getFullYear()}-${correctDay(new Date(day).getMonth() + 1)}-${correctDay(new Date(day).getDate())}` === date.created_at) {
return `before` return `before`
} }
} }
@ -48,8 +48,8 @@ export const ProfileCalendarComponent = ({reportsDates}) => {
function correctRoute(day) { function correctRoute(day) {
for (const date of reportsDates) { for (const date of reportsDates) {
if (`${new Date(day).getFullYear()}-${correctDay(new Date(day).getMonth() + 1)}-${correctDay(new Date(day).getDate())}` === date.date) { if (`${new Date(day).getFullYear()}-${correctDay(new Date(day).getMonth() + 1)}-${correctDay(new Date(day).getDate())}` === date.created_at) {
return `../../view/report` return `../view`
} }
} }
return '../../report' return '../../report'

View File

@ -0,0 +1,3 @@
<svg width="9" height="16" viewBox="0 0 9 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.00008 1L8.00008 8L1.00008 15" stroke="white" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 226 B

View File

@ -69,7 +69,7 @@ export const Summary = () => {
<button>Редактировать раздел</button> <button>Редактировать раздел</button>
</div> </div>
<div className='summary__sectionGitItems'> <div className='summary__sectionGitItems'>
{gitInfo.length && gitInfo.map((itemGit) => { {Boolean(gitInfo.length) && gitInfo.map((itemGit) => {
return <div key={itemGit.id} className='summary__sectionGitItem gitItem'> return <div key={itemGit.id} className='summary__sectionGitItem gitItem'>
<div className='gitItem__info'> <div className='gitItem__info'>
<div className='gitItem__info__about'> <div className='gitItem__info__about'>

View File

@ -0,0 +1,168 @@
import React, {useEffect, useState} from 'react'
import {Link} from "react-router-dom";
import {useRequest} from "../../hooks/useRequest";
import {useSelector} from "react-redux";
import {getReportDate} from "../../redux/reportSlice";
import {currentMonthAndDay} from "../../components/Calendar/calendarHelper";
import {ProfileHeader} from "../../components/ProfileHeader/ProfileHeader";
import {Footer} from "../../components/Footer/Footer";
import arrow from "../../images/right-arrow.png";
import arrowSwitchDate from "../../images/arrowViewReport.svg";
import './viewReport.scss'
export const ViewReport = () => {
const getCreatedDate = (day) => {
if (day) {
return `${new Date(day).getFullYear()}-${new Date(day).getMonth() + 1}-${new Date(day).getDate()}`
} else {
const date = new Date();
const dd = String(date.getDate()).padStart(2, '0');
const mm = String(date.getMonth() + 1).padStart(2, '0');
const yyyy = date.getFullYear();
return `${yyyy}-${mm}-${dd}`
}
};
const {apiRequest} = useRequest();
const reportDate = useSelector(getReportDate);
const [taskText, setTaskText] = useState([]);
const [difficulties, setDifficulties] = useState([])
const [tomorrowTask, setTomorrowTask] = useState([])
const [totalHours, setTotalHours] = useState(0);
const [reportDay, setReportDay] = useState(new Date (getCreatedDate(reportDate)))
const [currentDay, setCurrentDay] = useState(new Date ())
function getReportFromDate(day) {
setTaskText([])
setDifficulties([])
setTomorrowTask([])
apiRequest(`reports/find-by-date?user_card_id=${localStorage.getItem('cardId')}&date=${day}`)
.then(res => {
let spendTime = 0
for (const item of res) {
if(item.difficulties) {
setDifficulties(prevArray => [...prevArray, item.difficulties])
}
if(item.tomorrow) {
setTomorrowTask(prevArray => [...prevArray, item.tomorrow])
}
item.task.map((task) => {
const taskInfo = {
hours: task.hours_spent,
task: task.task,
id: task.id
}
if(task.hours_spent) {
spendTime += Number(task.hours_spent)
}
setTaskText(prevArray => [...prevArray, taskInfo])
})
}
setTotalHours(spendTime)
})
}
function nextDay() {
reportDay.setDate(reportDay.getDate() + 1);
getCreatedDate(reportDay)
getReportFromDate(getCreatedDate(reportDay))
}
function previousDay() {
reportDay.setDate(reportDay.getDate() - 1);
getReportFromDate(getCreatedDate(reportDay))
}
useEffect(() => {
getReportFromDate(getCreatedDate(reportDate))
}, []);
return (
<div className='viewReport'>
<ProfileHeader/>
<div className='container'>
<div className='viewReport__info'>
<h2 className='viewReport__title'>Ваши отчеты - <span>просмотр отчета за день</span></h2>
<Link className='viewReport__back' to={`/profile/calendar`}>
<img src={arrow} alt='arrow'/><p>Вернуться</p>
</Link>
<div className='viewReport__bar'>
<h3 className='viewReport__bar__date'>{getCreatedDate(reportDay)}</h3>
<p className='viewReport__bar__hours'>Вами потрачено на работу : <span>{totalHours} часов</span></p>
{/*<div className='viewReport__bar__progressBar'>*/}
{/* <span></span>*/}
{/*</div>*/}
{/*<p className='viewReport__bar__total'>122 часа из 160</p>*/}
</div>
</div>
<div className='viewReport__switchDate'>
<div className='viewReport__switchDate__prev switchDate' onClick={() => previousDay()}>
<img src={arrowSwitchDate} alt='arrow'/>
</div>
<p>{getCreatedDate(reportDay)}</p>
<div className={`viewReport__switchDate__next switchDate ${getCreatedDate(currentDay) === getCreatedDate(reportDay) || getCreatedDate(currentDay) < getCreatedDate(reportDay) ? 'disable' : ''}`} onClick={() => nextDay()}>
<img src={arrowSwitchDate} alt='arrow'/>
</div>
</div>
{taskText.length ?
<div className='viewReport__content'>
<div className='table__container'>
<table className='viewReport__done'>
<thead>
<tr>
<th><p>Какие задачи были выполнены?</p></th>
<th><p>Время</p></th>
</tr>
</thead>
<tbody>
{taskText.length && taskText.map((task) => {
return <tr key={task.id}>
<td>
<p>{task.task}</p>
</td>
<td>
<div className='viewReport__done__hours__item'>
<span>{task.hours}</span>
<p>часа на задачу</p>
</div>
</td>
</tr>
})}
<tr>
<td></td>
<td><span>Всего: {totalHours} часов</span></td>
</tr>
</tbody>
</table>
</div>
{Boolean(difficulties.length) &&
<div className='viewReport__item'>
<h3>Какие сложности возникли?</h3>
{difficulties.map((item, index) => {
return <p key={index}>{item}</p>
}
)}
</div>
}
{Boolean(tomorrowTask.length) &&
<div className='viewReport__item'>
<h3>Что планируется сделать завтра?</h3>
{tomorrowTask.map((item, index) => {
return <p key={index}>{item}</p>
}
)}
</div>
}
</div>
:
<div className='viewReport__noTask'>
<p>В этот день вы <span>не заполняли</span> отчет</p>
</div>
}
<Footer />
</div>
</div>
)
};

View File

@ -0,0 +1,296 @@
.viewReport {
background: #F1F1F1;
height: 100%;
min-height: 100vh;
font-family: 'LabGrotesque', sans-serif;
.container {
max-width: 1160px;
margin-top: 23px;
@media (max-width: 570px) {
margin-top: 0;
}
}
&__info {
display: flex;
flex-direction: column;
margin-top: 23px;
}
&__title {
font-weight: 700;
font-size: 22px;
line-height: 32px;
color: #000000;
span {
color: #52B709;
}
}
&__back {
display: flex;
align-items: center;
column-gap: 30px;
margin-top: 20px;
cursor: pointer;
&:hover {
text-decoration: none;
}
p {
margin-bottom: 0;
font-weight: 400;
font-size: 14px;
line-height: 32px;
color: #000000;
text-decoration: none;
}
}
&__bar {
display: flex;
margin-top: 20px;
background: #FFFFFF;
border-radius: 12px;
padding: 20px 33px;
align-items: center;
column-gap: 60px;
height: 72px;
justify-content: space-between;
&__date {
font-weight: 500;
font-size: 22px;
line-height: 32px;
color: #000000;
}
&__hours {
font-weight: 400;
font-size: 12px;
line-height: 32px;
color: #000000;
span {
color: #52B709;
font-weight: 700;
}
}
&__progressBar {
max-width: 390px;
width: 100%;
background: #F1F1F1;
border-radius: 12px;
height: 8px;
position: relative;
span {
position: absolute;
height: 100%;
left: 0;
width: 60%;
background: #52B709;
border-radius: 12px;
}
}
&__total {
font-weight: 400;
font-size: 12px;
line-height: 32px;
}
}
h3 {
margin-bottom: 0;
}
p {
margin-bottom: 0;
}
&__switchDate {
display: flex;
margin: 30px 0;
justify-content: center;
column-gap: 140px;
align-items: center;
p {
font-weight: 400;
font-size: 18px;
line-height: 32px;
color: #000000;
}
.switchDate {
width: 48px;
height: 48px;
background: #8DC63F;
border-radius: 50px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
&__prev {
transform: rotate(180deg);
}
}
.disable {
pointer-events: none;
opacity: 0.5;
}
.table__container {
margin: 0 -28px;
overflow: hidden;
position: relative;
}
&__done {
width: 100%;
border-collapse: separate;
border-spacing: 28px 0;
th {
padding: 32px 40px;
background: white;
border-radius: 12px 12px 0 0;
font-weight: 500;
font-size: 22px;
line-height: 32px;
color: #000000;
}
td {
padding: 15px 40px;
background: white;
p {
font-weight: 400;
font-size: 12px;
line-height: 24px;
color: #000000;
}
}
tr:last-child {
td {
border-radius: 0 0 12px 12px;
}
td:last-child {
font-weight: 500;
font-size: 17px;
line-height: 32px;
color: #000000;
}
}
&__hours {
width: 25%;
background: #FFFFFF;
border-radius: 12px;
padding: 32px 40px 18px;
display: flex;
flex-direction: column;
row-gap: 30px;
h3 {
font-weight: 500;
font-size: 22px;
line-height: 32px;
color: #000000;
}
&__item {
display: flex;
column-gap: 25px;
align-items: center;
min-width: 155px;
span {
width: 48px;
height: 48px;
background: #8DC63F;
border-radius: 50px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 22px;
line-height: 32px;
color: #000000;
}
p {
font-weight: 400;
font-size: 12px;
line-height: 32px;
}
}
&__total {
font-weight: 500;
font-size: 17px;
line-height: 32px;
}
}
}
&__item {
display: flex;
flex-direction: column;
row-gap: 22px;
background: #FFFFFF;
border-radius: 12px;
margin: 25px 0;
padding: 25px 35px;
h3 {
font-weight: 500;
font-size: 22px;
line-height: 32px;
}
p {
font-weight: 400;
font-size: 12px;
line-height: 24px;
}
}
&__item:last-child {
margin-bottom: 0;
}
&__noTask {
padding: 25px 10px;
background: #FFFFFF;
border-radius: 12px;
text-align: center;
p {
font-weight: 400;
font-size: 22px;
line-height: 32px;
color: #000000;
span {
color: #8BCC60;
font-weight: 500;
}
}
}
footer {
margin-top: 70px;
}
}