Merge branch 'main' of https://github.com/apuc/outstaffing-react into fix-tracker-and-statistics
This commit is contained in:
commit
b226ee88bd
@ -243,6 +243,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selectDays {
|
||||||
|
border-style: dashed !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #edf1ff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectedDay {
|
||||||
|
background-color: #edf1ff !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #edf1ff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.disable {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.before {
|
.before {
|
||||||
background-color: #e5f9b6 !important;
|
background-color: #e5f9b6 !important;
|
||||||
}
|
}
|
||||||
@ -272,66 +292,6 @@
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
position: relative;
|
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 {
|
.select {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
border: 1px solid #c4c4c4;
|
border: 1px solid #c4c4c4;
|
||||||
@ -341,4 +301,11 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
min-width: 350px;
|
min-width: 350px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 8px;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -536,9 +536,6 @@ export const TicketFullScreen = () => {
|
|||||||
></TrackerModal>
|
></TrackerModal>
|
||||||
|
|
||||||
<div className="tasks__head__persons">
|
<div className="tasks__head__persons">
|
||||||
{projectInfo.projectUsers?.length > 3 && (
|
|
||||||
<span className="countPersons">+1...</span>
|
|
||||||
)}
|
|
||||||
<div className="projectPersons">
|
<div className="projectPersons">
|
||||||
{projectInfo.projectUsers?.length &&
|
{projectInfo.projectUsers?.length &&
|
||||||
projectInfo.projectUsers.slice(0, 3).map((person) => {
|
projectInfo.projectUsers.slice(0, 3).map((person) => {
|
||||||
@ -555,6 +552,9 @@ export const TicketFullScreen = () => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
{projectInfo.projectUsers?.length > 3 && (
|
||||||
|
<span className="countPersons">+1</span>
|
||||||
|
)}
|
||||||
<span
|
<span
|
||||||
className="addPerson"
|
className="addPerson"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -541,7 +541,7 @@
|
|||||||
.exit {
|
.exit {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 15px;
|
top: 36px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 13px;
|
height: 13px;
|
||||||
|
@ -36,11 +36,16 @@ export const ProfileCalendar = () => {
|
|||||||
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);
|
||||||
|
const [startRangeDays, setStartRangeDays] = useState(false);
|
||||||
|
|
||||||
function setValueHandler(value) {
|
function setValueHandler(value) {
|
||||||
setValue(value);
|
setValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleStartRangeDays() {
|
||||||
|
setStartRangeDays(!startRangeDays);
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(setRequestDate(getReports(moment())));
|
dispatch(setRequestDate(getReports(moment())));
|
||||||
}, []);
|
}, []);
|
||||||
@ -115,6 +120,8 @@ export const ProfileCalendar = () => {
|
|||||||
value={value}
|
value={value}
|
||||||
reports={reports}
|
reports={reports}
|
||||||
totalHours={totalHours}
|
totalHours={totalHours}
|
||||||
|
startRangeDays={startRangeDays}
|
||||||
|
toggleRangeDays={toggleStartRangeDays}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
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";
|
||||||
|
|
||||||
@ -29,26 +26,38 @@ import ShortReport from "@components/ShortReport/ShortReport";
|
|||||||
|
|
||||||
import arrow from "assets/icons/arrows/arrowCalendar.png";
|
import arrow from "assets/icons/arrows/arrowCalendar.png";
|
||||||
import calendarIcon from "assets/icons/calendar.svg";
|
import calendarIcon from "assets/icons/calendar.svg";
|
||||||
|
import close from "assets/icons/closeProjectPersons.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,
|
||||||
|
startRangeDays,
|
||||||
|
toggleRangeDays,
|
||||||
|
}) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const [currentDay] = useState(moment());
|
const [currentDay] = useState(moment());
|
||||||
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 [startDate, setStartDate] = useState(null);
|
||||||
const [endDate, setEndDate] = useState(null);
|
const [endDate, setEndDate] = useState(null);
|
||||||
const [datePickerOpen, setDatePickerOpen] = useState(false);
|
|
||||||
const [totalRangeHours, setTotalRangeHours] = useState(0);
|
const [totalRangeHours, setTotalRangeHours] = useState(0);
|
||||||
|
const [selectedRangeDays, setSelectedRangeDays] = useState({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCalendar(calendarHelper(value));
|
setCalendar(calendarHelper(value));
|
||||||
|
calendarHelper(value).map((array) => {
|
||||||
|
setSelectedRangeDays((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
[array[0]]: false,
|
||||||
|
}));
|
||||||
|
});
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -103,10 +112,10 @@ export const ProfileCalendarComponent = React.memo(
|
|||||||
return value.clone().add(1, "month");
|
return value.clone().add(1, "month");
|
||||||
}
|
}
|
||||||
|
|
||||||
function reportsByDate(start, end) {
|
function reportsByDate(endDay) {
|
||||||
const requestDates = `fromDate=${getCorrectYYMMDD(
|
const requestDates = `fromDate=${getCorrectYYMMDD(
|
||||||
start
|
startDate._d
|
||||||
)}&toDate=${getCorrectYYMMDD(end)}`;
|
)}&toDate=${getCorrectYYMMDD(endDay._d)}`;
|
||||||
apiRequest(
|
apiRequest(
|
||||||
`/reports/reports-by-date?${requestDates}&user_card_id=${localStorage.getItem(
|
`/reports/reports-by-date?${requestDates}&user_card_id=${localStorage.getItem(
|
||||||
"cardId"
|
"cardId"
|
||||||
@ -124,6 +133,43 @@ export const ProfileCalendarComponent = React.memo(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function rangeDays(day) {
|
||||||
|
if (!startDate) {
|
||||||
|
setStartDate(day);
|
||||||
|
} else {
|
||||||
|
setEndDate(day);
|
||||||
|
reportsByDate(day);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseRangeDays(day) {
|
||||||
|
let selectRange = {};
|
||||||
|
for (let curDay in selectedRangeDays) {
|
||||||
|
if (
|
||||||
|
day > startDate &&
|
||||||
|
new Date(curDay) > startDate &&
|
||||||
|
new Date(curDay) < day
|
||||||
|
) {
|
||||||
|
selectRange[curDay] = true;
|
||||||
|
} else {
|
||||||
|
selectRange[curDay] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setSelectedRangeDays(selectRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetRangeDays() {
|
||||||
|
setStartDate(null);
|
||||||
|
setEndDate(null);
|
||||||
|
setTotalRangeHours(0);
|
||||||
|
calendarHelper(value).map((array) => {
|
||||||
|
setSelectedRangeDays((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
[array[0]]: false,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="calendar-component">
|
<div className="calendar-component">
|
||||||
<div className="calendar-component__header">
|
<div className="calendar-component__header">
|
||||||
@ -183,16 +229,35 @@ export const ProfileCalendarComponent = React.memo(
|
|||||||
week.map((day) => (
|
week.map((day) => (
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
if (startRangeDays) {
|
||||||
|
rangeDays(day);
|
||||||
|
} else {
|
||||||
dispatch(setReportDate(day));
|
dispatch(setReportDate(day));
|
||||||
setShortReport(true);
|
setShortReport(true);
|
||||||
dispatch(setSendRequest(true));
|
dispatch(setSendRequest(true));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
if (startRangeDays && startDate && !endDate) {
|
||||||
|
onMouseRangeDays(day);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
key={day}
|
key={day}
|
||||||
className={dayStyles(day)}
|
className={
|
||||||
|
startRangeDays
|
||||||
|
? `selectDays ${
|
||||||
|
startDate === day || endDate === day
|
||||||
|
? "selectedDay"
|
||||||
|
: ""
|
||||||
|
} ${endDate ? "disable" : ""} ${
|
||||||
|
selectedRangeDays[day] ? "selectedDay" : ""
|
||||||
|
}`
|
||||||
|
: dayStyles(day)
|
||||||
|
}
|
||||||
name={day.format("dddd")}
|
name={day.format("dddd")}
|
||||||
id="btn"
|
id="btn"
|
||||||
>
|
>
|
||||||
<Link to={correctRoute(day)}>
|
<Link to={startRangeDays ? "#" : correctRoute(day)}>
|
||||||
<img
|
<img
|
||||||
className={"calendar__icon"}
|
className={"calendar__icon"}
|
||||||
src={calendarIcon}
|
src={calendarIcon}
|
||||||
@ -209,35 +274,29 @@ export const ProfileCalendarComponent = React.memo(
|
|||||||
<span
|
<span
|
||||||
className="select"
|
className="select"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDatePickerOpen(!datePickerOpen);
|
if (startRangeDays) resetRangeDays();
|
||||||
|
toggleRangeDays();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{endDate
|
{endDate
|
||||||
? `${getCorrectDate(startDate)} - ${getCorrectDate(endDate)}`
|
? `${getCorrectDate(startDate)} - ${getCorrectDate(endDate)}`
|
||||||
: "Выбрать диапазон"}
|
: "Выбрать диапазон"}
|
||||||
</span>
|
</span>
|
||||||
<DatePicker
|
|
||||||
selected={startDate}
|
|
||||||
open={datePickerOpen}
|
|
||||||
locale="ru"
|
|
||||||
startDate={startDate}
|
|
||||||
endDate={endDate}
|
|
||||||
onChange={(dates) => {
|
|
||||||
const [start, end] = dates;
|
|
||||||
setStartDate(start);
|
|
||||||
setEndDate(end);
|
|
||||||
if (end) {
|
|
||||||
setDatePickerOpen(false);
|
|
||||||
reportsByDate(start, end);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
selectsRange
|
|
||||||
/>
|
|
||||||
<span>
|
<span>
|
||||||
{totalRangeHours
|
{totalRangeHours
|
||||||
? `${totalRangeHours} ${hourOfNum(totalRangeHours)}`
|
? `${totalRangeHours} ${hourOfNum(totalRangeHours)}`
|
||||||
: "0 часов"}
|
: "0 часов"}
|
||||||
</span>
|
</span>
|
||||||
|
{endDate && (
|
||||||
|
<img
|
||||||
|
className="close"
|
||||||
|
src={close}
|
||||||
|
alt="close"
|
||||||
|
onClick={() => {
|
||||||
|
resetRangeDays();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{shortReport && <ShortReport />}
|
{shortReport && <ShortReport />}
|
||||||
</div>
|
</div>
|
||||||
|
@ -368,9 +368,6 @@ export const ProjectTracker = () => {
|
|||||||
: "tasks__head__persons noProjectUsers"
|
: "tasks__head__persons noProjectUsers"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{projectBoard.projectUsers?.length > 3 && (
|
|
||||||
<span className="countPersons">+1...</span>
|
|
||||||
)}
|
|
||||||
{Boolean(projectBoard.projectUsers?.length) && (
|
{Boolean(projectBoard.projectUsers?.length) && (
|
||||||
<div className="projectPersons">
|
<div className="projectPersons">
|
||||||
{projectBoard.projectUsers.slice(0, 3).map((person) => {
|
{projectBoard.projectUsers.slice(0, 3).map((person) => {
|
||||||
@ -388,6 +385,9 @@ export const ProjectTracker = () => {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{projectBoard.projectUsers?.length > 3 && (
|
||||||
|
<span className="countPersons">+1</span>
|
||||||
|
)}
|
||||||
<span
|
<span
|
||||||
className="addPerson"
|
className="addPerson"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -71,8 +71,8 @@ export const Tracker = () => {
|
|||||||
apiRequest(
|
apiRequest(
|
||||||
`/task/get-user-tasks?user_id=${localStorage.getItem("id")}`
|
`/task/get-user-tasks?user_id=${localStorage.getItem("id")}`
|
||||||
).then((el) => {
|
).then((el) => {
|
||||||
const allTasks = el.filter((item) => item.status !== 0);
|
const allTasks = el ? el.filter((item) => item.status !== 0) : [];
|
||||||
const completedTasks = el.filter((item) => item.status === 0);
|
const completedTasks = el ? el.filter((item) => item.status === 0) : [];
|
||||||
setAllTasks(allTasks);
|
setAllTasks(allTasks);
|
||||||
setFilteredAllTasks(allTasks);
|
setFilteredAllTasks(allTasks);
|
||||||
setAllCompletedTasks(completedTasks);
|
setAllCompletedTasks(completedTasks);
|
||||||
@ -179,7 +179,8 @@ export const Tracker = () => {
|
|||||||
|
|
||||||
{loader && <Loader style="green" />}
|
{loader && <Loader style="green" />}
|
||||||
|
|
||||||
{Boolean(projects.length) &&
|
{projects &&
|
||||||
|
Boolean(projects.length) &&
|
||||||
!loader &&
|
!loader &&
|
||||||
projects.map((project, index) => {
|
projects.map((project, index) => {
|
||||||
return project.status !== 10 ? (
|
return project.status !== 10 ? (
|
||||||
@ -188,7 +189,8 @@ export const Tracker = () => {
|
|||||||
""
|
""
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{(!Boolean(projects.length) ||
|
{typeof projects === "object" &&
|
||||||
|
(!Boolean(projects.length) ||
|
||||||
!Boolean(
|
!Boolean(
|
||||||
projects.filter((project) => project.status !== 10).length
|
projects.filter((project) => project.status !== 10).length
|
||||||
)) &&
|
)) &&
|
||||||
@ -216,7 +218,7 @@ export const Tracker = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{Boolean(projects.length) && !loader && (
|
{projects && Boolean(projects.length) && !loader && (
|
||||||
<>
|
<>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
styles="createProjectBtn"
|
styles="createProjectBtn"
|
||||||
|
@ -321,7 +321,7 @@
|
|||||||
.projectPersons {
|
.projectPersons {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
left: -10px;
|
left: 5px;
|
||||||
img {
|
img {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -358,7 +358,7 @@
|
|||||||
color: #252c32;
|
color: #252c32;
|
||||||
border: 1px solid #dde2e4;
|
border: 1px solid #dde2e4;
|
||||||
background: white;
|
background: white;
|
||||||
left: -6px;
|
left: -20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.addPerson {
|
.addPerson {
|
||||||
|
@ -65,9 +65,9 @@ export function getCorrectRequestDate(date) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getCorrectYYMMDD(date) {
|
export function getCorrectYYMMDD(date) {
|
||||||
const yyyy = String(date.getUTCFullYear());
|
const yyyy = String(date.getFullYear());
|
||||||
const mm = String(date.getUTCMonth() + 1).padStart(2, "0");
|
const mm = String(date.getMonth() + 1).padStart(2, "0");
|
||||||
const dd = String(date.getUTCDate()).padStart(2, "0");
|
const dd = String(date.getDate()).padStart(2, "0");
|
||||||
return `${yyyy}-${mm}-${dd}`;
|
return `${yyyy}-${mm}-${dd}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user