Merge pull request #88 from apuc/fix-report-page

Fixed report page and calendar component
This commit is contained in:
MaxOvs19 2023-05-18 19:53:48 +03:00 committed by GitHub
commit 9932720fd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 781 additions and 435 deletions

View File

@ -88,8 +88,9 @@ const App = () => {
<Route index element={<Profile />} /> <Route index element={<Profile />} />
<Route exact path="catalog" element={<Home />} /> <Route exact path="catalog" element={<Home />} />
<Route exact path="calendar" element={<ProfileCalendar />} /> <Route exact path="calendar" element={<ProfileCalendar />} />
<Route exact path="calendar/view/" element={<ProfileCalendar />} />
<Route exact path="summary" element={<Summary />} /> <Route exact path="summary" element={<Summary />} />
<Route exact path="view" element={<ViewReport />} /> <Route exact path="view/:id" element={<ViewReport />} />
<Route exact path="tracker" element={<Tracker />} /> <Route exact path="tracker" element={<Tracker />} />
<Route exact path="payouts" element={<Payouts />} /> <Route exact path="payouts" element={<Payouts />} />
<Route exact path="settings" element={<PartnerSettings />} /> <Route exact path="settings" element={<PartnerSettings />} />

View File

@ -7,7 +7,7 @@
padding-right: 54px; padding-right: 54px;
padding-top: 48px; padding-top: 48px;
padding-bottom: 40px; padding-bottom: 40px;
font-family: 'LabGrotesque', sans-serif; font-family: "LabGrotesque", sans-serif;
&__header { &__header {
display: flex; display: flex;
@ -56,7 +56,6 @@
} }
h3 { h3 {
font-size: 2.5em; font-size: 2.5em;
font-weight: 400; font-weight: 400;
font-style: normal; font-style: normal;
@ -133,6 +132,8 @@
text-align: center; text-align: center;
} }
} }
margin-bottom: 60px;
} }
&__form { &__form {
@ -142,8 +143,8 @@
button { button {
margin: 0 auto; margin: 0 auto;
//width: 125px; width: 125px;
//height: 42px; height: 42px;
padding: 0 5px; padding: 0 5px;
box-shadow: 0 0 59px rgba(44, 44, 44, 0.05); box-shadow: 0 0 59px rgba(44, 44, 44, 0.05);
border-radius: 5px; border-radius: 5px;
@ -158,18 +159,21 @@
text-align: center; text-align: center;
a { a {
display: flex; color: black;
align-items: center; }
justify-content: center;
width: 115px;
height: 42px;
text-decoration: none;
color: #000000;
img { img {
width: 16px; width: 16px;
height: 16px; height: 16px;
margin: 0 10px 0 0; margin: 0 10px 0 0;
@media (max-width: 968px) {
margin-right: 2px;
@media (max-width: 610px) {
display: none;
}
}
} }
@media (max-width: 1200px) { @media (max-width: 1200px) {
@ -182,15 +186,7 @@
height: 40px; height: 40px;
font-size: 10px; font-size: 10px;
img {
margin-right: 2px;
}
}
@media (max-width: 610px) { @media (max-width: 610px) {
img {
display: none;
}
width: auto; width: auto;
height: auto; height: auto;
} }

View File

@ -1,19 +1,23 @@
import moment from 'moment'; import moment from "moment";
import 'moment/locale/ru'; import "moment/locale/ru";
export function calendarHelper(value) { export function calendarHelper(value) {
const startDay = value.clone().startOf('month').startOf('week').startOf('day'); const startDay = value
const endDay = value.clone().endOf('month').endOf('week'); .clone()
.startOf("month")
.startOf("week")
.startOf("day");
const endDay = value.clone().endOf("month").endOf("week");
const day = startDay.clone().subtract(1, 'day'); const day = startDay.clone().subtract(1, "day");
const calendar = []; const calendar = [];
while (day.isBefore(endDay, 'day')) { while (day.isBefore(endDay, "day")) {
calendar.push( calendar.push(
Array(1) Array(1)
.fill(0) .fill(0)
.map(() => day.add(1, 'day').clone()) .map(() => day.add(1, "day").clone())
); );
} }
@ -21,48 +25,84 @@ export function calendarHelper(value) {
} }
export function getReports(value) { export function getReports(value) {
const startDay = value.clone().startOf('month').startOf('week').startOf('day'); const startDay = value
const reportsStart = `${new Date(startDay).getFullYear()}-${new Date(startDay).getMonth() + 1}-${new Date(startDay).getDate()}` .clone()
const endDay = value.clone().endOf('month').endOf('week'); .startOf("month")
const reportsEnd = `${new Date(endDay).getFullYear()}-${new Date(endDay).getMonth() + 1}-${new Date(endDay).getDate()}` .startOf("week")
const getReports = `fromDate=${reportsStart}&toDate=${reportsEnd}` .startOf("day");
const reportsStart = `${new Date(startDay).getFullYear()}-${
new Date(startDay).getMonth() + 1
}-${new Date(startDay).getDate()}`;
const endDay = value.clone().endOf("month").endOf("week");
const reportsEnd = `${new Date(endDay).getFullYear()}-${
new Date(endDay).getMonth() + 1
}-${new Date(endDay).getDate()}`;
const getReports = `fromDate=${reportsStart}&toDate=${reportsEnd}`;
return getReports; return getReports;
} }
export function getCreatedDate(day) { export function getCreatedDate(day) {
if (day) { if (day) {
return `${new Date(day).getFullYear()}-${new Date(day).getMonth() + 1}-${new Date(day).getDate()}` return `${new Date(day).getFullYear()}-${correctDay(
new Date(day).getMonth() + 1
)}-${correctDay(new Date(day).getDate())}`;
} else { } else {
const date = new Date(); const date = new Date();
const dd = String(date.getDate()).padStart(2, '0'); const dd = String(date.getDate()).padStart(2, "0");
const mm = String(date.getMonth() + 1).padStart(2, '0'); const mm = String(date.getMonth() + 1).padStart(2, "0");
const yyyy = date.getFullYear(); const yyyy = date.getFullYear();
return `${yyyy}-${mm}-${dd}` return `${yyyy}-${mm}-${dd}`;
} }
} }
export function correctDay(day) {
if (day < 10) {
return `0${day}`;
}
return day;
}
export function currentMonth() { export function currentMonth() {
const currentMonth = moment().format('MMMM'); const currentMonth = moment().format("MMMM");
return currentMonth.charAt(0).toUpperCase() + currentMonth.slice(1); return currentMonth.charAt(0).toUpperCase() + currentMonth.slice(1);
} }
export function currentMonthAndDay(day) { export function currentMonthAndDay(day) {
return day.format('D MMMM'); return day.format("D MMMM");
} }
export function getCorrectDate(day) { export function getCorrectDate(day) {
const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря'] const months = [
return `${new Date(day).getDate()} ${months[new Date(day).getMonth()]} ${new Date(day).getFullYear()} года` "января",
}; "февраля",
"марта",
"апреля",
"мая",
"июня",
"июля",
"августа",
"сентября",
"октября",
"ноября",
"декабря",
];
return `${new Date(day).getDate()} ${
months[new Date(day).getMonth()]
} ${new Date(day).getFullYear()} года`;
}
export function currentMonthAndDayReportPage() { export function currentMonthAndDayReportPage() {
return moment().format('D MMMM'); return moment().format("D MMMM");
} }
export function hourOfNum(number) { export function hourOfNum(number) {
const hours = [' час', ' часа', ' часов']; const hours = [" час", " часа", " часов"];
const cases = [2, 0, 1, 1, 1, 2]; const cases = [2, 0, 1, 1, 1, 2];
return hours[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]]; return hours[
number % 100 > 4 && number % 100 < 20
? 2
: cases[number % 10 < 5 ? number % 10 : 5]
];
} }

View File

@ -1,99 +1,127 @@
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 {getReports} from '../Calendar/calendarHelper' import { getReports } from "../Calendar/calendarHelper";
import {Link, Navigate} from 'react-router-dom' import { Link, Navigate } from "react-router-dom";
import moment from "moment"; import moment from "moment";
import {ProfileCalendarComponent} from "./ProfileCalendarComponent"; import { ProfileCalendarComponent } from "./ProfileCalendarComponent";
import {Loader} from "../Loader/Loader"; import { Loader } from "../Loader/Loader";
import {ProfileHeader} from "../ProfileHeader/ProfileHeader"; import { ProfileHeader } from "../ProfileHeader/ProfileHeader";
import {ProfileBreadcrumbs} from "../../components/ProfileBreadcrumbs/ProfileBreadcrumbs" import { ProfileBreadcrumbs } from "../../components/ProfileBreadcrumbs/ProfileBreadcrumbs";
import { Footer } from '../Footer/Footer' import { Footer } from "../Footer/Footer";
import { Navigation } from "../Navigation/Navigation";
import { ViewReport } from "../../pages/ViewReport/ViewReport";
import {urlForLocal} from "../../helper"; import { urlForLocal } from "../../helper";
import {apiRequest} from "../../api/request"; import { apiRequest } from "../../api/request";
import { getProfileInfo } from '../../redux/outstaffingSlice' import { getProfileInfo } from "../../redux/outstaffingSlice";
import {getRequestDates, setReportDate, setRequestDate} from "../../redux/reportSlice"; import {
getRequestDates,
import 'moment/locale/ru' setReportDate,
import './profileCalendar.scss' setRequestDate,
import { Navigation } from '../Navigation/Navigation'; } from "../../redux/reportSlice";
import "moment/locale/ru";
import "./profileCalendar.scss";
export const ProfileCalendar = () => { export const ProfileCalendar = () => {
if(localStorage.getItem('role_status') === '18') { if (localStorage.getItem("role_status") === "18") {
return <Navigate to="/profile" replace/> return <Navigate to="/profile" replace />;
} }
const dispatch = useDispatch(); const dispatch = useDispatch();
const profileInfo = useSelector(getProfileInfo) const profileInfo = useSelector(getProfileInfo);
const requestDates = useSelector(getRequestDates) const requestDates = useSelector(getRequestDates);
const [value, setValue] = useState(moment()) const [value, setValue] = useState(moment());
const [reports, setReports] = useState([]); const [reports, setReports] = useState([]);
const [totalHours, setTotalHours] = useState(0); const [totalHours, setTotalHours] = useState(0);
const [loader, setLoader] = useState(true) const [loader, setLoader] = useState(true);
function setValueHandler (value) { function setValueHandler(value) {
setValue(value) setValue(value);
} }
useEffect(() => { useEffect(() => {
dispatch(setRequestDate(getReports(moment()))) dispatch(setRequestDate(getReports(moment())));
},[]); }, []);
useEffect( () => { useEffect(() => {
setLoader(true) setLoader(true);
if (!requestDates) { if (!requestDates) {
return return;
} }
apiRequest(`/reports/reports-by-date?${requestDates}&user_card_id=${localStorage.getItem('cardId')}`) apiRequest(
.then((reports) => { `/reports/reports-by-date?${requestDates}&user_card_id=${localStorage.getItem(
"cardId"
)}`
).then((reports) => {
let spendTime = 0; let spendTime = 0;
for (const report of reports) { for (const report of reports) {
report.task.map((task) => { report.task.map((task) => {
if(task.hours_spent) { if (task.hours_spent) {
spendTime += Number(task.hours_spent) spendTime += Number(task.hours_spent);
} }
}) });
} }
setTotalHours(spendTime); setTotalHours(spendTime);
setReports(reports) setReports(reports);
setLoader(false) setLoader(false);
}) });
}, [requestDates]); }, [requestDates]);
return ( return (
<div className='profile__calendar'> <div className="profile__calendar">
<ProfileHeader/> <ProfileHeader />
<Navigation /> <Navigation />
<div className='container'> <div className="container">
<ProfileBreadcrumbs links={[{name: 'Главная', link: '/profile'},{name: 'Ваша отчетность', link: '/profile/calendar'}]} /> <ProfileBreadcrumbs
<h2 className='summary__title'>Ваши отчеты</h2> links={[
<div className='summary__info'> { name: "Главная", link: "/profile" },
<div className='summary__person'> { name: "Ваша отчетность", link: "/profile/calendar" },
<img src={urlForLocal(profileInfo.photo)} className='summary__avatar' alt='avatar'/> ]}
<p className='summary__name'>{profileInfo.fio}, {profileInfo.specification} разработчик</p> />
<h2 className="summary__title">Ваши отчеты</h2>
<div className="summary__info">
<div className="summary__person">
<img
src={urlForLocal(profileInfo.photo)}
className="summary__avatar"
alt="avatar"
/>
<p className="summary__name">
{profileInfo.fio}, {profileInfo.specification} разработчик
</p>
</div> </div>
<Link to='/report'> <Link to="/report">
<button className="calendar__btn" onClick={() => { <button
dispatch(setReportDate('')) className="calendar__btn"
}}>Заполнить отчет за день</button> onClick={() => {
dispatch(setReportDate(""));
}}
>
Заполнить отчет за день
</button>
</Link> </Link>
</div> </div>
{loader ? {loader ? (
<div className='loader__wrapper'> <div className="loader__wrapper">
<Loader height={80} width={80} /> <Loader height={80} width={80} />
</div> </div>
: ) : (
<div className='row calendar__wrapper'> <div className="row calendar__wrapper">
<div className='col-12 col-xl-12'> <div className="col-12 col-xl-12">
<ProfileCalendarComponent setValueHandler={setValueHandler} value={value} reports={reports} totalHours={totalHours} /> <ProfileCalendarComponent
setValueHandler={setValueHandler}
value={value}
reports={reports}
totalHours={totalHours}
/>
</div> </div>
</div> </div>
} )}
</div> </div>
<Footer /> <Footer />
</div> </div>
) );
}; };

View File

@ -1,109 +1,135 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from "react";
import arrow from '../../images/arrowCalendar.png' import arrow from "../../images/arrowCalendar.png";
import rectangle from '../../images/rectangle__calendar.png' import rectangle from "../../images/rectangle__calendar.png";
import calendarIcon from '../../images/calendar_icon.png' import calendarIcon from "../../images/calendar_icon.png";
import moment from 'moment' import moment from "moment";
import {calendarHelper, currentMonthAndDay, getReports, hourOfNum} from '../Calendar/calendarHelper' import {
import {setReportDate, setRequestDate} from '../../redux/reportSlice'; calendarHelper,
import {useDispatch} from "react-redux"; currentMonthAndDay,
import {Link} from "react-router-dom"; getReports,
hourOfNum,
} from "../Calendar/calendarHelper";
import {
setReportDate,
setRequestDate,
setSendRequest,
} from "../../redux/reportSlice";
import { useDispatch } from "react-redux";
import { Link } from "react-router-dom";
import ShortReport from "../ShortReport/ShortReport";
import 'moment/locale/ru' import "moment/locale/ru";
import './../Calendar/calendarComponent.scss' import "./../Calendar/calendarComponent.scss";
export const ProfileCalendarComponent = React.memo(({value, setValueHandler, reports, totalHours}) => { export const ProfileCalendarComponent = React.memo(
({ value, setValueHandler, reports, totalHours }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [currentDay] = useState(moment())
const [calendar, setCalendar] = useState([]) const [currentDay] = useState(moment());
const [month, setMonth] = useState(''); const [calendar, setCalendar] = useState([]);
const [month, setMonth] = useState("");
const [shortReport, setShortReport] = useState(false);
useEffect(() => { useEffect(() => {
setCalendar(calendarHelper(value)) setCalendar(calendarHelper(value));
}, [value]) }, [value]);
useEffect(() => { useEffect(() => {
setMonth(value.format('MMMM')) setMonth(value.format("MMMM"));
}, [month]); }, [month]);
function isToday(day) { function isToday(day) {
return day.isSame(new Date(), 'day') return day.isSame(new Date(), "day");
} }
function correctDay(day) { function correctDay(day) {
if (day < 10) { if (day < 10) {
return `0${day}` return `0${day}`;
} return day }
return day;
} }
function dayStyles(day) { function dayStyles(day) {
if (currentDay < day) return `block` if (currentDay < day) return `block`;
for (const date of reports) { for (const date of reports) {
if (`${new Date(day).getFullYear()}-${correctDay(new Date(day).getMonth() + 1)}-${correctDay(new Date(day).getDate())}` === date.created_at) { if (
return `before` `${new Date(day).getFullYear()}-${correctDay(
new Date(day).getMonth() + 1
)}-${correctDay(new Date(day).getDate())}` === date.created_at
) {
return `before`;
} }
} }
if (day.day() === 6 || day.day() === 0) return `selected` if (day.day() === 6 || day.day() === 0) return `selected`;
if (isToday(day)) return `today` if (isToday(day)) return `today`;
return 'pass' return "pass";
} }
function correctRoute(day) { function correctRoute(day) {
for (const date of reports) { for (const date of reports) {
if (`${new Date(day).getFullYear()}-${correctDay(new Date(day).getMonth() + 1)}-${correctDay(new Date(day).getDate())}` === date.created_at) { if (
return `../view` `${new Date(day).getFullYear()}-${correctDay(
new Date(day).getMonth() + 1
)}-${correctDay(new Date(day).getDate())}` === date.created_at
) {
return;
} }
} }
return '../../report' return "../../report";
} }
function prevMonth() { function prevMonth() {
return value.clone().subtract(1, 'month') return value.clone().subtract(1, "month");
} }
function nextMonth() { function nextMonth() {
return value.clone().add(1, 'month'); return value.clone().add(1, "month");
} }
return ( return (
<div className='calendar-component'> <div className="calendar-component">
<div className='calendar-component__header'> <div className="calendar-component__header">
<div className='calendar-component__header-info'> <div className="calendar-component__header-info">
<h3>Мои отчеты:</h3> <h3>Мои отчеты:</h3>
<p className='calendar__hours'> <p className="calendar__hours">
{month}&nbsp;<span>{totalHours} {hourOfNum(totalHours)} </span> {month}&nbsp;
<span>
{totalHours} {hourOfNum(totalHours)}{" "}
</span>
</p> </p>
</div> </div>
<div className='calendar-component__header-switcher'> <div className="calendar-component__header-switcher">
<div className='calendar-component__header-box' onClick={() => { <div
setValueHandler(prevMonth()) className="calendar-component__header-box"
dispatch(setRequestDate(getReports(prevMonth()))) onClick={() => {
}}> setValueHandler(prevMonth());
<img src={arrow} alt='' /> dispatch(setRequestDate(getReports(prevMonth())));
<span> }}
{prevMonth().format('MMMM')} >
</span> <img src={arrow} alt="" />
<span>{prevMonth().format("MMMM")}</span>
</div> </div>
<div className='calendar-component__header-box'> <div className="calendar-component__header-box">
<span>{value.format('YYYY')}</span> <span>{value.format("YYYY")}</span>
</div> </div>
<div className='calendar-component__header-box' onClick={() => { <div
setValueHandler(nextMonth()) className="calendar-component__header-box"
dispatch(setRequestDate(getReports(nextMonth()))) onClick={() => {
setValueHandler(nextMonth());
}}> dispatch(setRequestDate(getReports(nextMonth())));
<span> }}
{nextMonth().format('MMMM')} >
</span> <span>{nextMonth().format("MMMM")}</span>
<img src={arrow} alt='' /> <img src={arrow} alt="" />
</div> </div>
</div> </div>
</div> </div>
<div className='calendar-component__rectangle'> <div className="calendar-component__rectangle">
<img src={rectangle} alt='' /> <img src={rectangle} alt="" />
</div> </div>
<div className='calendar-component__body'> <div className="calendar-component__body">
<div> <div>
<p>Пн</p> <p>Пн</p>
<p>Вт</p> <p>Вт</p>
@ -114,20 +140,26 @@ export const ProfileCalendarComponent = React.memo(({value, setValueHandler, rep
<p>Вс</p> <p>Вс</p>
</div> </div>
<div className='calendar-component__form'> <div className="calendar-component__form">
{calendar.map((week) => {calendar.map((week) =>
week.map((day) => ( week.map((day) => (
<button <button
onClick={() => { onClick={() => {
dispatch(setReportDate(day)) dispatch(setReportDate(day));
setShortReport(true);
dispatch(setSendRequest(true));
}} }}
key={day} key={day}
className={dayStyles(day)} className={dayStyles(day)}
name={day.format('dddd')} name={day.format("dddd")}
id='btn' id="btn"
> >
<Link to={correctRoute(day)}> <Link to={correctRoute(day)}>
<img className={'calendar__icon'} src={calendarIcon} alt='' /> <img
className={"calendar__icon"}
src={calendarIcon}
alt=""
/>
{currentMonthAndDay(day)} {currentMonthAndDay(day)}
</Link> </Link>
</button> </button>
@ -135,7 +167,9 @@ export const ProfileCalendarComponent = React.memo(({value, setValueHandler, rep
)} )}
</div> </div>
</div> </div>
</div>
)
})
{shortReport && <ShortReport />}
</div>
);
}
);

View File

@ -1,5 +1,5 @@
.profile__calendar { .profile__calendar {
background: #F1F1F1; background: #f1f1f1;
height: 100%; height: 100%;
min-height: 100vh; min-height: 100vh;
font-family: "LabGrotesque", sans-serif; font-family: "LabGrotesque", sans-serif;
@ -32,7 +32,6 @@
} }
} }
.calendar__wrapper { .calendar__wrapper {
min-height: 719px; min-height: 719px;

View File

@ -0,0 +1,176 @@
import React, { useEffect, useState } from "react";
import { apiRequest } from "../../api/request";
import {
getCorrectDate,
getCreatedDate,
hourOfNum,
} from "../../components/Calendar/calendarHelper";
import {
getReportDate,
getSendRequest,
setSendRequest,
} from "../../redux/reportSlice";
import { useDispatch, useSelector } from "react-redux";
import { Link } from "react-router-dom";
import { Loader } from "../Loader/Loader";
import "./shortReport.scss";
export const ShortReport = ({}) => {
const reportDate = useSelector(getReportDate);
const sendReport = useSelector(getSendRequest);
const dispatch = useDispatch();
const [taskText, setTaskText] = useState([]);
const [difficulties, setDifficulties] = useState([]);
const [tomorrowTask, setTomorrowTask] = useState([]);
const [totalHours, setTotalHours] = useState(0);
const [loader, setLoader] = useState(false);
const [dateCreate, setDateCreate] = useState("");
function getReportFromDate(day) {
setLoader(true);
setTaskText([]);
setDifficulties([]);
setTomorrowTask([]);
setTotalHours(0);
apiRequest(
`reports/find-by-date?user_card_id=${localStorage.getItem(
"cardId"
)}&date=${day}`
).then((res) => {
let spendTime = 0;
for (const item of res) {
setDateCreate(item.created_at);
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);
setLoader(false);
});
}
if (sendReport) {
dispatch(setSendRequest(false));
getReportFromDate(getCreatedDate(reportDate));
}
return (
<div>
<div className="viewReport__info short-report">
<div className="viewReport__title-box">
<h2 className="viewReport__title">
Ваши отчеты - <span>просмотр отчета за день</span>
</h2>
<Link to={`../view/${dateCreate}`}>
Посмотреть подробнее об отчете
</Link>
</div>
<div className="viewReport__bar">
<h3 className="viewReport__bar__date">
{getCorrectDate(reportDate)}
</h3>
<p className="viewReport__bar__hours">
Вами потрачено на работу :{" "}
<span>
{totalHours} {hourOfNum(totalHours)}
</span>
</p>
</div>
</div>
{loader && <Loader style="green" />}
{Boolean(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, index) => {
return (
<tr key={task.id}>
<td>
<p>
{index + 1}. {task.task}
</p>
</td>
<td>
<div className="viewReport__done__hours__item">
<span>{task.hours}</span>
<p className="hours">
{hourOfNum(task.hours)} на задачу
</p>
</div>
</td>
</tr>
);
})}
<tr>
<td></td>
<td>
<span>
Всего: {totalHours} {hourOfNum(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>
)}
{!Boolean(taskText.length) && !loader && (
<div className="viewReport__noTask">
<p>
В этот день вы <span>не заполняли</span> отчет
</p>
</div>
)}
</div>
);
};
export default ShortReport;

View File

@ -0,0 +1,15 @@
.short-report {
margin-bottom: 30px;
}
.viewReport {
&__title-box {
display: flex;
align-items: center;
justify-content: space-between;
a {
font-size: 16px;
}
}
}

View File

@ -1,175 +0,0 @@
import React, {useEffect, useState} from 'react'
import {Link, Navigate} from "react-router-dom";
import {useSelector} from "react-redux";
import {getReportDate} from "../../redux/reportSlice";
import {Loader} from "../../components/Loader/Loader"
import {ProfileHeader} from "../../components/ProfileHeader/ProfileHeader";
import {ProfileBreadcrumbs} from "../../components/ProfileBreadcrumbs/ProfileBreadcrumbs"
import {Footer} from "../../components/Footer/Footer";
import {apiRequest} from "../../api/request";
import {getCorrectDate, getCreatedDate, hourOfNum} from '../../components/Calendar/calendarHelper'
import arrow from "../../images/right-arrow.png";
import arrowSwitchDate from "../../images/arrowViewReport.png";
import './viewReport.scss'
import { Navigation } from '../../components/Navigation/Navigation';
export const ViewReport = () => {
if(localStorage.getItem('role_status') === '18') {
return <Navigate to="/profile" replace/>
}
const reportDate = useSelector(getReportDate);
const [taskText, setTaskText] = useState([]);
const [difficulties, setDifficulties] = useState([]);
const [tomorrowTask, setTomorrowTask] = useState([]);
const [totalHours, setTotalHours] = useState(0);
const [reportDay] = useState(new Date (getCreatedDate(reportDate)));
const [currentDay] = useState(new Date ());
const [loader, setLoader] = useState(false);
function getReportFromDate(day) {
setLoader(true);
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);
setLoader(false)
})
}
function nextDay() {
reportDay.setDate(reportDay.getDate() + 1);
getReportFromDate(getCreatedDate(reportDay))
}
function previousDay() {
reportDay.setDate(reportDay.getDate() - 1);
getReportFromDate(getCreatedDate(reportDay))
}
useEffect(() => {
getReportFromDate(getCreatedDate(reportDate))
}, []);
return (
<div className='viewReport'>
<ProfileHeader/>
<Navigation />
<div className='container'>
<div className='viewReport__info'>
<ProfileBreadcrumbs links={[{name: 'Главная', link: '/profile'},
{name: 'Ваша отчетность', link: '/profile/calendar'},
{name: 'Просмотр отчета за день', link: '/profile/view'}]}
/>
<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'>{getCorrectDate(reportDay)}</h3>
<p className='viewReport__bar__hours'>Вами потрачено на работу : <span>{totalHours} {hourOfNum(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>{getCorrectDate(reportDay)}</p>
<div className={`viewReport__switchDate__next switchDate ${getCreatedDate(currentDay) === getCreatedDate(reportDay) ? 'disable' : ''}`} onClick={() => nextDay()}>
<img src={arrowSwitchDate} alt='arrow'/>
</div>
</div>
{loader &&
<Loader width={75} height={75}/>
}
{Boolean(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, index) => {
return <tr key={task.id}>
<td>
<p>{index + 1}. {task.task}</p>
</td>
<td>
<div className='viewReport__done__hours__item'>
<span>{task.hours}</span>
<p className='hours'>{hourOfNum(task.hours)} на задачу</p>
</div>
</td>
</tr>
})}
<tr>
<td></td>
<td><span>Всего: {totalHours} {hourOfNum(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>
}
{!Boolean(taskText.length) && !loader &&
<div className='viewReport__noTask'>
<p>В этот день вы <span>не заполняли</span> отчет</p>
</div>
}
<Footer />
</div>
</div>
)
};

View File

@ -0,0 +1,225 @@
import React, { useEffect, useState } from "react";
import { Link, Navigate, useParams } from "react-router-dom";
import { Loader } from "../../components/Loader/Loader";
import { ProfileHeader } from "../../components/ProfileHeader/ProfileHeader";
import { ProfileBreadcrumbs } from "../../components/ProfileBreadcrumbs/ProfileBreadcrumbs";
import { Footer } from "../../components/Footer/Footer";
import { Navigation } from "../../components/Navigation/Navigation";
import { apiRequest } from "../../api/request";
import {
getCorrectDate,
getCreatedDate,
hourOfNum,
} from "../../components/Calendar/calendarHelper";
import arrow from "../../images/right-arrow.png";
import arrowSwitchDate from "../../images/arrowViewReport.png";
import "./viewReport.scss";
export const ViewReport = () => {
if (localStorage.getItem("role_status") === "18") {
return <Navigate to="/profile" replace />;
}
const dateReport = useParams();
const [previousReportDay] = useState(new Date(dateReport.id));
const [nextReportDay] = useState(new Date(dateReport.id));
const [taskText, setTaskText] = useState([]);
const [difficulties, setDifficulties] = useState([]);
const [tomorrowTask, setTomorrowTask] = useState([]);
const [totalHours, setTotalHours] = useState(0);
const [currentDay] = useState(new Date());
const [loader, setLoader] = useState(false);
function getReportFromDate(day) {
setLoader(true);
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);
setLoader(false);
});
previousReportDay.setDate(previousReportDay.getDate() - 1);
nextReportDay.setDate(nextReportDay.getDate() + 1);
}
function nextDay() {
getReportFromDate(getCreatedDate(nextReportDay));
previousReportDay.setDate(previousReportDay.getDate() + 2);
}
function previousDay() {
getReportFromDate(getCreatedDate(previousReportDay));
nextReportDay.setDate(nextReportDay.getDate() - 2);
}
useEffect(() => {
getReportFromDate(dateReport.id);
}, []);
return (
<div className="viewReport">
<ProfileHeader />
<Navigation />
<div className="container">
<div className="viewReport__info">
<ProfileBreadcrumbs
links={[
{ name: "Главная", link: "/profile" },
{ name: "Ваша отчетность", link: "/profile/calendar" },
{ name: "Просмотр отчета за день", link: "/profile/view" },
]}
/>
<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">
{getCorrectDate(dateReport.id)}
</h3>
<p className="viewReport__bar__hours">
Вами потрачено на работу :{" "}
<span>
{totalHours} {hourOfNum(totalHours)}
</span>
</p>
</div>
</div>
<div className="viewReport__switchDate">
<div
onClick={() => {
previousDay();
}}
>
<Link to={`../view/${getCreatedDate(previousReportDay)}`}>
<div className="viewReport__switchDate__prev switchDate">
<img src={arrowSwitchDate} alt="arrow" />
</div>
</Link>
</div>
<p>{getCorrectDate(dateReport.id)}</p>
<div
onClick={() => nextDay()}
className={`${
getCreatedDate(currentDay) === dateReport.id ? "disable" : ""
}`}
>
<Link to={`../view/${getCreatedDate(nextReportDay)}`}>
<div className={`viewReport__switchDate__next switchDate`}>
<img src={arrowSwitchDate} alt="arrow" />
</div>
</Link>
</div>
</div>
{loader && <Loader width={75} height={75} />}
{Boolean(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, index) => {
return (
<tr key={task.id}>
<td>
<p>
{index + 1}. {task.task}
</p>
</td>
<td>
<div className="viewReport__done__hours__item">
<span>{task.hours}</span>
<p className="hours">
{hourOfNum(task.hours)} на задачу
</p>
</div>
</td>
</tr>
);
})}
<tr>
<td></td>
<td>
<span>
Всего: {totalHours} {hourOfNum(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>
)}
{!Boolean(taskText.length) && !loader && (
<div className="viewReport__noTask">
<p>
В этот день вы <span>не заполняли</span> отчет
</p>
</div>
)}
<Footer />
</div>
</div>
);
};

View File

@ -1,13 +1,14 @@
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from "@reduxjs/toolkit";
const initialState = { const initialState = {
dateSelected: '', dateSelected: "",
reportDate: '', reportDate: "",
requestDates: '' requestDates: "",
sendRequest: "",
}; };
export const reportSlice = createSlice({ export const reportSlice = createSlice({
name: 'report', name: "report",
initialState, initialState,
reducers: { reducers: {
dateSelected: (state, action) => { dateSelected: (state, action) => {
@ -17,17 +18,23 @@ export const reportSlice = createSlice({
state.reportDate = action.payload; state.reportDate = action.payload;
}, },
setRequestDate: (state, action) => { setRequestDate: (state, action) => {
state.requestDates = action.payload state.requestDates = action.payload;
} },
setSendRequest: (state, action) => {
state.sendRequest = action.payload;
},
}, },
}); });
export const { dateSelected, setReportDate, setRequestDate} = reportSlice.actions; export const { dateSelected, setReportDate, setRequestDate, setSendRequest } =
reportSlice.actions;
export const selectDate = (state) => state.report.dateSelected; export const selectDate = (state) => state.report.dateSelected;
export const getReportDate = (state) => state.report.reportDate; export const getReportDate = (state) => state.report.reportDate;
export const getRequestDates = (state) => state.report.requestDates export const getRequestDates = (state) => state.report.requestDates;
export const getSendRequest = (state) => state.report.sendRequest;
export default reportSlice.reducer; export default reportSlice.reducer;