add ModalTicketToReport and add OpenRequest, fix

LandingTracker, fix url ModalTicket
This commit is contained in:
Никита Губарь 2024-07-04 16:54:34 +03:00
parent b396201cdf
commit a367f8b09c
14 changed files with 1499 additions and 1155 deletions

View File

@ -5,7 +5,7 @@ import React, { useEffect, useState } from "react";
import DatePicker, { registerLocale } from "react-datepicker"; import DatePicker, { registerLocale } from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css"; import "react-datepicker/dist/react-datepicker.css";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { Link } from "react-router-dom"; import { Link, useLocation } from "react-router-dom";
import { getProfileInfo } from "@redux/outstaffingSlice"; import { getProfileInfo } from "@redux/outstaffingSlice";
import { setProjectBoardFetch } from "@redux/projectsTrackerSlice"; import { setProjectBoardFetch } from "@redux/projectsTrackerSlice";
@ -44,6 +44,7 @@ import watch from "assets/icons/watch.svg";
import avatarMok from "assets/images/avatarMok.webp"; import avatarMok from "assets/images/avatarMok.webp";
import { getCorrectDate } from "../../../../utils/calendarHelper"; import { getCorrectDate } from "../../../../utils/calendarHelper";
import ModalTicketToReport from "../ModalTicketToReport/ModalTicketToReport";
import "./modalTicket.scss"; import "./modalTicket.scss";
registerLocale("ru", ru); registerLocale("ru", ru);
@ -59,6 +60,8 @@ export const ModalTiсket = ({
projectMarks projectMarks
}) => { }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const location = useLocation();
const [addSubtask, setAddSubtask] = useState(false); const [addSubtask, setAddSubtask] = useState(false);
const [editOpen, setEditOpen] = useState(false); const [editOpen, setEditOpen] = useState(false);
const [inputsValue, setInputsValue] = useState({ const [inputsValue, setInputsValue] = useState({
@ -87,6 +90,12 @@ export const ModalTiсket = ({
minute: 0, minute: 0,
seconds: 0 seconds: 0
}); });
const additionalData = {
id: task.id,
title: inputsValue.title,
link: null,
nameProject: projectName
};
const [timerId, setTimerId] = useState(null); const [timerId, setTimerId] = useState(null);
const [taskFiles, setTaskFiles] = useState([]); const [taskFiles, setTaskFiles] = useState([]);
const [correctProjectUsers, setCorrectProjectUsers] = useState(projectUsers); const [correctProjectUsers, setCorrectProjectUsers] = useState(projectUsers);
@ -98,9 +107,21 @@ export const ModalTiсket = ({
const [selectPriorityOpen, setSelectPriorityOpen] = useState(false); const [selectPriorityOpen, setSelectPriorityOpen] = useState(false);
const { showNotification } = useNotification(); const { showNotification } = useNotification();
const [commentSendDisable, setCommentSendDisable] = useState(false); const [commentSendDisable, setCommentSendDisable] = useState(false);
const [showModalToReport, setShowModalToReport] = useState(false);
const openModalToReport = () => {
setShowModalToReport(!showModalToReport);
};
const closeModalToReport = () => {
setShowModalToReport(!showModalToReport);
};
const closeModal = () => { const closeModal = () => {
setActive(false); setActive(false);
const currentUrl = window.location.pathname;
const newUrl = currentUrl.replace(/\/task\/\d+$/, "");
window.history.replaceState({}, "", newUrl);
// Восстанавливаем скролл при закрытии модального окна // Восстанавливаем скролл при закрытии модального окна
document.body.style.overflow = "auto"; document.body.style.overflow = "auto";
}; };
@ -1072,7 +1093,7 @@ export const ModalTiсket = ({
</div> </div>
<div className="workers_box-bottom"> <div className="workers_box-bottom">
<div <div
className={editOpen ? "edit" : ""} className={`bottom-button ${editOpen ? "edit" : ""}`}
onClick={() => { onClick={() => {
if (editOpen) { if (editOpen) {
editTask(); editTask();
@ -1084,30 +1105,39 @@ export const ModalTiсket = ({
<img src={edit}></img> <img src={edit}></img>
<p>{editOpen ? "сохранить" : "редактировать"}</p> <p>{editOpen ? "сохранить" : "редактировать"}</p>
</div> </div>
<div> <div className="bottom-button">
<img src={link}></img> <img src={link}></img>
<p onClick={copyTicketLink}>ссылка на задачу</p> <p onClick={copyTicketLink}>ссылка на задачу</p>
</div> </div>
<div className="bottom-button">
<img src={link}></img>
<p onClick={openModalToReport}>выгрузка в отчет</p>
<ModalTicketToReport
show={showModalToReport}
onClose={closeModalToReport}
additionalData={additionalData}
></ModalTicketToReport>
</div>
<div <div
onClick={archiveTask} onClick={archiveTask}
className={ className={`bottom-button ${
profileInfo.id_user === projectOwnerId || profileInfo.id_user === projectOwnerId ||
profileInfo.id_user === task.user_id profileInfo.id_user === task.user_id
? "" ? ""
: "disable" : "disable"
} }`}
> >
<img src={archive}></img> <img src={archive}></img>
<p>в архив</p> <p>в архив</p>
</div> </div>
<div <div
onClick={deleteTask} onClick={deleteTask}
className={ className={`bottom-button ${
profileInfo.id_user === projectOwnerId || profileInfo.id_user === projectOwnerId ||
profileInfo.id_user === task.user_id profileInfo.id_user === task.user_id
? "" ? ""
: "disable" : "disable"
} }`}
> >
<img src={del}></img> <img src={del}></img>
<p>удалить</p> <p>удалить</p>

View File

@ -1178,7 +1178,8 @@
font-size: 14px; font-size: 14px;
line-height: 32px; line-height: 32px;
div { .bottom {
&-button {
display: flex; display: flex;
cursor: pointer; cursor: pointer;
align-items: center; align-items: center;
@ -1191,9 +1192,8 @@
p { p {
margin: 0 0 0 5px; margin: 0 0 0 5px;
} }
}
.edit { &.edit {
background: #52b709; background: #52b709;
border-radius: 50px; border-radius: 50px;
width: fit-content; width: fit-content;
@ -1209,6 +1209,8 @@
} }
} }
} }
}
}
} }
.subtask { .subtask {

View File

@ -0,0 +1,69 @@
import axios from "axios";
import React, { useState } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import BaseButton from "@components/Common/BaseButton/BaseButton";
import "./modalTicketToReport.scss";
const ModalTicketToReport = ({ show, onClose, additionalData }) => {
const [date, setDate] = useState(new Date());
const handleSubmit = async () => {
const data = {
date,
...additionalData
};
try {
await axios.post(
"https://itguild.info/profile/calendar/reports/create",
data
);
} catch (error) {
console.error("Error:", error);
}
};
return (
<div
className={`modal-report-backdrop ${show ? "show" : ""}`}
onClick={onClose}
>
<div
className="modal-report-content"
onClick={(e) => e.stopPropagation()}
>
<div className="modal-report-close" onClick={onClose}></div>
<h2>Выгрузка в отчет</h2>
<div className="modal-report-date-picker">
<DatePicker
className="datePicker"
locale="ru"
selected={date}
onChange={(date) => setDate(date)}
dateFormat="dd/MM/yyyy"
/>
</div>
<div className="modal-report__buttons">
<BaseButton
styles={"button-add add-person-btn "}
onClick={handleSubmit}
>
Выгрузить в отчет
</BaseButton>
<BaseButton
styles={`button-add add-person-btn ${show ? "" : "disable"}`}
onClick={handleSubmit}
>
Выгрузить и перейти в отчет
</BaseButton>
</div>
</div>
</div>
);
};
export default ModalTicketToReport;

View File

@ -0,0 +1,167 @@
.modal-report {
&-backdrop {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
align-items: center;
justify-content: center;
z-index: 1000;
display: none;
&.show {
display: flex;
}
}
&-content {
cursor: auto;
background: white;
padding: 20px;
border-radius: 5px;
position: relative;
max-width: 500px;
height: 500px;
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
&-close {
cursor: pointer;
position: absolute;
top: 15px;
right: 15px;
width: 13px;
height: 13px;
display: flex;
align-items: center;
justify-content: center;
&::after {
content: "";
position: absolute;
width: 16px;
height: 2px;
background: #263238;
transform: rotate(-45deg);
}
&::before {
content: "";
position: absolute;
width: 16px;
height: 2px;
background: #263238;
transform: rotate(45deg);
}
}
&-date-picker {
// .datePicker {
// visibility: hidden;
// height: 0;
// padding: 0;
// width: 0;
// position: absolute;
// }
.react-datepicker-wrapper {
// position: absolute;
}
.react-datepicker {
border: 1px solid #e8ede4;
border-radius: 8px;
}
.react-datepicker-popper {
top: -150px !important;
left: 180px !important;
z-index: 10;
@media (max-width: 880px) {
left: 0 !important;
top: -15px !important;
}
}
.react-datepicker__current-month {
font-size: 18px;
text-transform: capitalize;
}
.react-datepicker__navigation-icon {
width: 20px;
height: 20px;
border-radius: 50px;
border: 2px solid #cbd1d2;
display: flex;
justify-content: center;
align-items: center;
font-size: 0;
&:hover {
background-color: white;
}
}
.react-datepicker__navigation-icon--next::before {
border-width: 2px 2px 0 0;
top: auto;
left: 4px;
height: 6px;
width: 6px;
}
.react-datepicker__navigation-icon--previous::before {
border-width: 2px 2px 0 0;
top: auto;
left: 6px;
height: 6px;
width: 6px;
}
.react-datepicker__header {
padding: 5px 0 10px;
border-bottom: 1px solid #baacc0;
}
.react-datepicker__day {
font-size: 16px;
width: 35px;
border-radius: 50px;
padding: 7px;
}
.react-datepicker__day-name {
font-size: 18px;
width: 35px;
font-weight: 500;
}
.react-datepicker__triangle {
display: none;
// left: 85px !important;
// &:before {
// border: 1px solid #e8ede4;
// }
}
}
&__buttons {
display: flex;
justify-content: center;
column-gap: 100px;
margin: 30px 0;
.button {
height: 47px;
font-size: 15px;
line-height: 16px;
}
}
}

View File

@ -106,14 +106,7 @@ const TrackerCardTask = ({
onDrop={(e) => dragDropTaskHandler(e, task, column)} onDrop={(e) => dragDropTaskHandler(e, task, column)}
onClick={(e) => openTicket(e, task)} onClick={(e) => openTicket(e, task)}
> >
<div <div className="tasks__board__item__title">
className="tasks__board__item__title"
onClick={() => {
if (window.innerWidth < 985) {
window.location.replace(`/tracker/task/${task.id}`);
}
}}
>
<p className="task__board__item__title">{task.title}</p> <p className="task__board__item__title">{task.title}</p>
</div> </div>
<p <p

View File

@ -84,7 +84,9 @@ export const LandingTracker = () => {
<h3> <h3>
ITGu <br /> ild ITGu <br /> ild
</h3> </h3>
<img className="intro-logo__cup" src={trackerCup} alt="" /> <div className="intro-logo__cup">
<img src={trackerCup} alt="" />
</div>
</div> </div>
<div className="intro-content"> <div className="intro-content">
<div className="intro-content__sublogo"> <div className="intro-content__sublogo">

View File

@ -57,6 +57,32 @@
position: absolute; position: absolute;
bottom: -85px; bottom: -85px;
right: -150px; right: -150px;
&::before {
content: "Не нужно заваривать мышь";
display: flex;
align-items: center;
position: relative;
top: 100px;
left: -80px;
width: 182px;
height: 106px;
border-radius: 8px;
border: 0.5px solid #ffffff;
background: linear-gradient(
110.06deg,
rgba(255, 255, 255, 0.34) 0%,
rgba(199, 206, 198, 0.34) 99.25%
);
backdrop-filter: blur(8.6999998093px);
box-shadow: 10px 9px 14px 0 rgba(0, 0, 0, 0.06);
padding: 0 15px;
font-size: 17px;
font-weight: 700;
line-height: 19.72px;
letter-spacing: 0.01em;
text-align: center;
}
} }
} }

View File

@ -0,0 +1,32 @@
import React from "react";
import { Footer } from "@components/Common/Footer/Footer";
import { Navigation } from "@components/Navigation/Navigation";
import { ProfileBreadcrumbs } from "@components/ProfileBreadcrumbs/ProfileBreadcrumbs";
import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader";
import "./OpenRequest.scss";
export const OpenRequest = () => {
return (
<div className="open-request">
<ProfileHeader />
<Navigation />
<div className="container">
<div className="open-request-content">
<ProfileBreadcrumbs
links={[
{ name: "Главная", link: "/profile" },
{
name: "Работа в IT открытые запросы",
link: "/profile/open-request"
}
]}
/>
<h2 className="summary__title">Работа в IT открытые запросы</h2>
</div>
</div>
<Footer />
</div>
);
};

View File

View File

@ -29,7 +29,7 @@ export const Profile = () => {
const [profileItemsInfo] = useState({ const [profileItemsInfo] = useState({
developer: [ developer: [
{ {
path: "profile", path: "profile/open-requests",
img: paymentIcon, img: paymentIcon,
title: "Работа в IT <br/>открытые запросы", title: "Работа в IT <br/>открытые запросы",
description: "Перейдите чтобы посмотреть <br/>открытые позиции" description: "Перейдите чтобы посмотреть <br/>открытые позиции"

View File

@ -1,7 +1,7 @@
import moment from "moment"; import moment from "moment";
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { Link, useParams } from "react-router-dom"; import { Link, useLocation, useNavigate, useParams } from "react-router-dom";
import { import {
activeLoader, activeLoader,
@ -51,6 +51,8 @@ import avatarMok from "assets/images/avatarMok.webp";
export const ProjectTracker = () => { export const ProjectTracker = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const projectId = useParams(); const projectId = useParams();
const location = useLocation();
const navigate = useNavigate();
const [openColumnSelect, setOpenColumnSelect] = useState({}); const [openColumnSelect, setOpenColumnSelect] = useState({});
const [selectedTab, setSelectedTab] = useState(0); const [selectedTab, setSelectedTab] = useState(0);
@ -97,6 +99,24 @@ export const ProjectTracker = () => {
} else { } else {
setFilteredNoTasks(false); setFilteredNoTasks(false);
} }
const path = location.pathname;
const match = path.match(/\/task\/(\d+)/);
console.log(match);
if (match) {
const extractedTaskId = match[1];
console.log(extractedTaskId);
// Убираем /task/id из URL
const newUrl = path.replace(/\/task\/\d+/, "");
navigate(newUrl, { replace: true });
// Открываем тикет
console.log("asd", projectBoard);
const Dtask = tasks.find((task) => task.id === extractedTaskId);
console.log("asd", Dtask);
// openTicket(extractedTaskId);
}
}, [projectBoard]); }, [projectBoard]);
function dragOverHandler(e) { function dragOverHandler(e) {
@ -148,9 +168,16 @@ export const ProjectTracker = () => {
function openTicket(e, task) { function openTicket(e, task) {
setSelectedTicket(task); setSelectedTicket(task);
setModalActiveTicket(true); setModalActiveTicket(true);
const currentUrl = window.location.pathname;
const newUrl = `${currentUrl}/task/${task.id}`;
window.history.pushState({}, "", newUrl);
document.body.style.overflow = "hidden"; document.body.style.overflow = "hidden";
} }
// useEffect(() => {
// }, [location]);
function deleteColumn(column) { function deleteColumn(column) {
const priorityColumns = []; const priorityColumns = [];
apiRequest("/project-column/update-column", { apiRequest("/project-column/update-column", {

View File

@ -1,6 +1,7 @@
import React from "react"; import React from "react";
import { Navigate, Route, Routes } from "react-router-dom"; import { Route, Routes } from "react-router-dom";
import { OpenRequest } from "@pages/OpenRequests/openRequest";
import { PartnerSettings } from "@pages/PartnerSettings/PartnerSettings"; import { PartnerSettings } from "@pages/PartnerSettings/PartnerSettings";
import { PartnerTreaties } from "@pages/PartnerTreaties/PartnerTreaties"; import { PartnerTreaties } from "@pages/PartnerTreaties/PartnerTreaties";
import { Payouts } from "@pages/Payouts/Payouts"; import { Payouts } from "@pages/Payouts/Payouts";
@ -14,7 +15,6 @@ import { Summary } from "@pages/Summary/Summary";
import { Tracker } from "@pages/Tracker/Tracker"; import { Tracker } from "@pages/Tracker/Tracker";
import { ViewReport } from "@pages/ViewReport/ViewReport"; import { ViewReport } from "@pages/ViewReport/ViewReport";
import { TicketFullScreen } from "@components/Modal/Tracker/TicketFullScreen/TicketFullScreen";
import { ProfileCalendar } from "@components/ProfileCalendar/ProfileCalendar"; import { ProfileCalendar } from "@components/ProfileCalendar/ProfileCalendar";
import { ReportForm } from "@components/ReportForm/ReportForm"; import { ReportForm } from "@components/ReportForm/ReportForm";
@ -23,9 +23,10 @@ export const DeveloperPage = () => {
<Routes> <Routes>
<Route <Route
exact exact
path="/tracker/task/:id" path="/tracker/project/:id/task/:taskId"
element={<TicketFullScreen />} element={<ProjectTracker />}
></Route> />
<Route exact path="/tracker/project/:id" element={<ProjectTracker />} /> <Route exact path="/tracker/project/:id" element={<ProjectTracker />} />
<Route exact path="profile"> <Route exact path="profile">
@ -33,6 +34,7 @@ export const DeveloperPage = () => {
<Route exact path="calendar" element={<ProfileCalendar />} /> <Route exact path="calendar" element={<ProfileCalendar />} />
<Route exact path="calendar/report" element={<ReportForm />} /> <Route exact path="calendar/report" element={<ReportForm />} />
<Route exact path="calendar/view/:date/:id" element={<ViewReport />} /> <Route exact path="calendar/view/:date/:id" element={<ViewReport />} />
<Route exact path="open-requests" element={<OpenRequest />} />
<Route exact path="summary" element={<Summary />} /> <Route exact path="summary" element={<Summary />} />
<Route exact path="tracker" element={<Tracker />} /> <Route exact path="tracker" element={<Tracker />} />
<Route exact path="statistics/:id" element={<Statistics />} /> <Route exact path="statistics/:id" element={<Statistics />} />
@ -45,7 +47,7 @@ export const DeveloperPage = () => {
<Route exact path="report/:uuid" element={<QuizReportPage />} /> <Route exact path="report/:uuid" element={<QuizReportPage />} />
</Route> </Route>
</Route> </Route>
<Route path="*" element={<Navigate to="/profile" replace />} /> {/* <Route path="*" element={<Navigate to="/profile" replace />} /> */}
</Routes> </Routes>
); );
}; };

View File

@ -19,7 +19,6 @@ import { ViewReport } from "@pages/ViewReport/ViewReport";
import { Calendar } from "@components/Calendar/Calendar"; import { Calendar } from "@components/Calendar/Calendar";
import { Candidate } from "@components/Candidate/Candidate"; import { Candidate } from "@components/Candidate/Candidate";
import { TicketFullScreen } from "@components/Modal/Tracker/TicketFullScreen/TicketFullScreen";
export const PartnerPage = () => { export const PartnerPage = () => {
return ( return (
@ -28,11 +27,6 @@ export const PartnerPage = () => {
<Route exact path="/candidate/:id/form" element={<FormPage />} /> <Route exact path="/candidate/:id/form" element={<FormPage />} />
<Route path="/:userId/calendar" element={<Calendar />} /> <Route path="/:userId/calendar" element={<Calendar />} />
<Route
exact
path="/tracker/task/:id"
element={<TicketFullScreen />}
></Route>
<Route exact path="/tracker/project/:id" element={<ProjectTracker />} /> <Route exact path="/tracker/project/:id" element={<ProjectTracker />} />
<Route exact path="profile"> <Route exact path="profile">