| @@ -18,6 +18,7 @@ import {InstructionPage} from './pages/quiz/InstructionPage' | ||||
| import {ResultPage} from './pages/quiz/ResultPage' | ||||
| import {Profile} from './pages/Profile/Profile.js' | ||||
| import {Summary} from './pages/Summary/Summary' | ||||
| import {ViewReport} from './pages/ViewReport/ViewReport' | ||||
|  | ||||
| import './fonts/stylesheet.css' | ||||
| import 'bootstrap/dist/css/bootstrap.min.css' | ||||
| @@ -55,6 +56,7 @@ const App = () => { | ||||
|               <Route index element={<Profile/>}/> | ||||
|               <Route exact path='calendar' element={<ProfileCalendar/>}/> | ||||
|               <Route exact path='summary' element={<Summary/>}/> | ||||
|               <Route exact path='view' element={<ViewReport/>}/> | ||||
|             </Route> | ||||
|  | ||||
|             <Route path="*" element={<Navigate to="/" replace/>}/> | ||||
|   | ||||
| @@ -33,14 +33,16 @@ export const ProfileCalendar = () => { | ||||
|         if (!requestDates) { | ||||
|             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) => { | ||||
|                 let spendTime = 0; | ||||
|                 reports.map((report) => { | ||||
|                     if (report.spendTime) { | ||||
|                         spendTime += Number(report.spendTime) | ||||
|                     } | ||||
|                 }); | ||||
|                 for (const report of reports) { | ||||
|                     report.task.map((task) => { | ||||
|                         if(task.hours_spent) { | ||||
|                             spendTime += Number(task.hours_spent) | ||||
|                         } | ||||
|                     }) | ||||
|                 } | ||||
|                 setTotalHours(spendTime); | ||||
|                 setReports(reports) | ||||
|             }) | ||||
|   | ||||
| @@ -37,7 +37,7 @@ export const ProfileCalendarComponent = ({reportsDates}) => { | ||||
|     function dayStyles(day) { | ||||
|         if (value < day) return `block` | ||||
|         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` | ||||
|             } | ||||
|         } | ||||
| @@ -48,8 +48,8 @@ export const ProfileCalendarComponent = ({reportsDates}) => { | ||||
|  | ||||
|     function correctRoute(day) { | ||||
|         for (const date of reportsDates) { | ||||
|             if (`${new Date(day).getFullYear()}-${correctDay(new Date(day).getMonth() + 1)}-${correctDay(new Date(day).getDate())}` === date.date) { | ||||
|                 return `../../view/report` | ||||
|             if (`${new Date(day).getFullYear()}-${correctDay(new Date(day).getMonth() + 1)}-${correctDay(new Date(day).getDate())}` === date.created_at) { | ||||
|                 return `../view` | ||||
|             } | ||||
|         } | ||||
|         return '../../report' | ||||
|   | ||||
							
								
								
									
										3
									
								
								src/images/arrowViewReport.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/images/arrowViewReport.svg
									
									
									
									
									
										Normal 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 | 
| @@ -69,7 +69,7 @@ export const Summary = () => { | ||||
|               <button>Редактировать раздел</button> | ||||
|             </div> | ||||
|             <div className='summary__sectionGitItems'> | ||||
|               {gitInfo.length && gitInfo.map((itemGit) => { | ||||
|               {Boolean(gitInfo.length) && gitInfo.map((itemGit) => { | ||||
|                 return <div key={itemGit.id} className='summary__sectionGitItem gitItem'> | ||||
|                   <div className='gitItem__info'> | ||||
|                     <div className='gitItem__info__about'> | ||||
|   | ||||
							
								
								
									
										168
									
								
								src/pages/ViewReport/ViewReport.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								src/pages/ViewReport/ViewReport.js
									
									
									
									
									
										Normal 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> | ||||
|     ) | ||||
| }; | ||||
							
								
								
									
										296
									
								
								src/pages/ViewReport/viewReport.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								src/pages/ViewReport/viewReport.scss
									
									
									
									
									
										Normal 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; | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 NikoM1k
					NikoM1k