Merge pull request #129 from apuc/reports-date-range
Reports date range
This commit is contained in:
commit
3f7bfc40f9
@ -263,3 +263,82 @@
|
|||||||
.block {
|
.block {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selectDateRange {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.react-datepicker-wrapper {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-datepicker__tab-loop {
|
||||||
|
position: absolute;
|
||||||
|
top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-datepicker-popper {
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.datePicker {
|
||||||
|
visibility: hidden;
|
||||||
|
height: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-datepicker {
|
||||||
|
border: 1px solid #398208;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-datepicker-popper {
|
||||||
|
top: -15px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-datepicker__current-month {
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: "LabGrotesque", sans-serif;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-datepicker__header {
|
||||||
|
padding: 5px 0 10px;
|
||||||
|
border-bottom: 1px solid #398208;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-datepicker__day {
|
||||||
|
font-size: 14px;
|
||||||
|
width: 35px;
|
||||||
|
font-family: "LabGrotesque", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-datepicker__day-name {
|
||||||
|
font-size: 14px;
|
||||||
|
width: 35px;
|
||||||
|
font-family: "LabGrotesque", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-datepicker__triangle {
|
||||||
|
transform: translate(140px, 0px) !important;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
border-bottom-color: #398208 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select {
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #c4c4c4;
|
||||||
|
box-shadow: 0 0 59px rgba(44, 44, 44, 0.05);
|
||||||
|
padding: 5px 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
min-width: 350px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
|
import ru from "date-fns/locale/ru";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import "moment/locale/ru";
|
import "moment/locale/ru";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
import DatePicker, { registerLocale } from "react-datepicker";
|
||||||
|
import "react-datepicker/dist/react-datepicker.css";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
@ -10,10 +13,15 @@ import {
|
|||||||
setSendRequest,
|
setSendRequest,
|
||||||
} from "@redux/reportSlice";
|
} from "@redux/reportSlice";
|
||||||
|
|
||||||
|
import { getCorrectYYMMDD } from "@utils/helper";
|
||||||
|
|
||||||
|
import { apiRequest } from "@api/request";
|
||||||
|
|
||||||
import "@components/Calendar/calendarComponent.scss";
|
import "@components/Calendar/calendarComponent.scss";
|
||||||
import {
|
import {
|
||||||
calendarHelper,
|
calendarHelper,
|
||||||
currentMonthAndDay,
|
currentMonthAndDay,
|
||||||
|
getCorrectDate,
|
||||||
getReports,
|
getReports,
|
||||||
hourOfNum,
|
hourOfNum,
|
||||||
} from "@components/Calendar/calendarHelper";
|
} from "@components/Calendar/calendarHelper";
|
||||||
@ -23,6 +31,8 @@ import arrow from "assets/icons/arrows/arrowCalendar.png";
|
|||||||
import calendarIcon from "assets/icons/calendar.svg";
|
import calendarIcon from "assets/icons/calendar.svg";
|
||||||
import rectangle from "assets/images/rectangle__calendar.png";
|
import rectangle from "assets/images/rectangle__calendar.png";
|
||||||
|
|
||||||
|
registerLocale("ru", ru);
|
||||||
|
|
||||||
// eslint-disable-next-line react/display-name
|
// eslint-disable-next-line react/display-name
|
||||||
export const ProfileCalendarComponent = React.memo(
|
export const ProfileCalendarComponent = React.memo(
|
||||||
({ value, setValueHandler, reports, totalHours }) => {
|
({ value, setValueHandler, reports, totalHours }) => {
|
||||||
@ -32,6 +42,10 @@ export const ProfileCalendarComponent = React.memo(
|
|||||||
const [calendar, setCalendar] = useState([]);
|
const [calendar, setCalendar] = useState([]);
|
||||||
const [month, setMonth] = useState("");
|
const [month, setMonth] = useState("");
|
||||||
const [shortReport, setShortReport] = useState(false);
|
const [shortReport, setShortReport] = useState(false);
|
||||||
|
const [startDate, setStartDate] = useState(new Date());
|
||||||
|
const [endDate, setEndDate] = useState(null);
|
||||||
|
const [datePickerOpen, setDatePickerOpen] = useState(false);
|
||||||
|
const [totalRangeHours, setTotalRangeHours] = useState(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCalendar(calendarHelper(value));
|
setCalendar(calendarHelper(value));
|
||||||
@ -89,6 +103,27 @@ export const ProfileCalendarComponent = React.memo(
|
|||||||
return value.clone().add(1, "month");
|
return value.clone().add(1, "month");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reportsByDate(start, end) {
|
||||||
|
const requestDates = `fromDate=${getCorrectYYMMDD(
|
||||||
|
start
|
||||||
|
)}&toDate=${getCorrectYYMMDD(end)}`;
|
||||||
|
apiRequest(
|
||||||
|
`/reports/reports-by-date?${requestDates}&user_card_id=${localStorage.getItem(
|
||||||
|
"cardId"
|
||||||
|
)}`
|
||||||
|
).then((reports) => {
|
||||||
|
let spendTime = 0;
|
||||||
|
for (const report of reports) {
|
||||||
|
report.task.map((task) => {
|
||||||
|
if (task.hours_spent) {
|
||||||
|
spendTime += Number(task.hours_spent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setTotalRangeHours(spendTime);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="calendar-component">
|
<div className="calendar-component">
|
||||||
<div className="calendar-component__header">
|
<div className="calendar-component__header">
|
||||||
@ -170,7 +205,39 @@ export const ProfileCalendarComponent = React.memo(
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="selectDateRange">
|
||||||
|
<span
|
||||||
|
className="select"
|
||||||
|
onClick={() => {
|
||||||
|
setDatePickerOpen(!datePickerOpen);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{endDate
|
||||||
|
? `${getCorrectDate(startDate)} - ${getCorrectDate(endDate)}`
|
||||||
|
: "Выбрать диапазон"}
|
||||||
|
</span>
|
||||||
|
<DatePicker
|
||||||
|
selected={startDate}
|
||||||
|
open={datePickerOpen}
|
||||||
|
startDate={startDate}
|
||||||
|
endDate={endDate}
|
||||||
|
onChange={(dates) => {
|
||||||
|
const [start, end] = dates;
|
||||||
|
setStartDate(start);
|
||||||
|
setEndDate(end);
|
||||||
|
if (end) {
|
||||||
|
setDatePickerOpen(false);
|
||||||
|
reportsByDate(start, end);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
selectsRange
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
{totalRangeHours
|
||||||
|
? `${totalRangeHours} ${hourOfNum(totalRangeHours)}`
|
||||||
|
: "0 часов"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
{shortReport && <ShortReport />}
|
{shortReport && <ShortReport />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -2,25 +2,25 @@ export function createMarkup(text) {
|
|||||||
return { __html: text.split("</p>").join("</p>") };
|
return { __html: text.split("</p>").join("</p>") };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transformHtml(text) {
|
// export function transformHtml(text) {
|
||||||
let startHtml = {
|
// let startHtml = {
|
||||||
__html: text.split("<h3> || <h2>").join("<br><h2>").split("<br>"),
|
// __html: text.split("<h3> || <h2>").join("<br><h2>").split("<br>"),
|
||||||
};
|
// };
|
||||||
startHtml = startHtml.__html.filter(
|
// startHtml = startHtml.__html.filter(
|
||||||
(el) => (el !== null && el !== "") || el === 0
|
// (el) => (el !== null && el !== "") || el === 0
|
||||||
);
|
// );
|
||||||
const finalHtml = startHtml.map(
|
// const finalHtml = startHtml.map(
|
||||||
(item) =>
|
// (item) =>
|
||||||
`<div class='experience__block'>
|
// `<div class='experience__block'>
|
||||||
<div class="summary__sections__head">
|
// <div class="summary__sections__head">
|
||||||
<h3>Описание опыта работы</h3>
|
// <h3>Описание опыта работы</h3>
|
||||||
<button>Редактировать раздел</button>
|
// <button>Редактировать раздел</button>
|
||||||
</div>
|
// </div>
|
||||||
<div class="experience__content">${item.split("<h3>")[0]}</div>
|
// <div class="experience__content">${item.split("<h3>")[0]}</div>
|
||||||
</div>`
|
// </div>`
|
||||||
);
|
// );
|
||||||
return { __html: finalHtml.join("") };
|
// return { __html: finalHtml.join("") };
|
||||||
}
|
// }
|
||||||
//
|
//
|
||||||
// export const setToken = () => {
|
// export const setToken = () => {
|
||||||
// const url = new URL(window.location.href);
|
// const url = new URL(window.location.href);
|
||||||
@ -64,6 +64,13 @@ export function getCorrectRequestDate(date) {
|
|||||||
return `${yyyy}-${mm}-${dd} ${hh}:${min}:${sec}`;
|
return `${yyyy}-${mm}-${dd} ${hh}:${min}:${sec}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCorrectYYMMDD(date) {
|
||||||
|
const yyyy = String(date.getUTCFullYear());
|
||||||
|
const mm = String(date.getUTCMonth() + 1).padStart(2, "0");
|
||||||
|
const dd = String(date.getUTCDate()).padStart(2, "0");
|
||||||
|
return `${yyyy}-${mm}-${dd}`;
|
||||||
|
}
|
||||||
|
|
||||||
export function caseOfNum(number, type) {
|
export function caseOfNum(number, type) {
|
||||||
const allTypes = {
|
const allTypes = {
|
||||||
comments: ["коментарий", "комментария", " коментариев"],
|
comments: ["коментарий", "комментария", " коментариев"],
|
||||||
|
Loading…
Reference in New Issue
Block a user