Compare commits
3 Commits
104f538e3a
...
ca0a509077
Author | SHA1 | Date | |
---|---|---|---|
ca0a509077 | |||
7e64150378 | |||
911b827e41 |
BIN
src/assets/images/landingTracker/target.webp
Normal file
BIN
src/assets/images/landingTracker/target.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
@ -122,15 +122,6 @@ export const ModalTiсket = ({
|
||||
setShowModalToReport(!showModalToReport);
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
setActive(false);
|
||||
const currentUrl = window.location.pathname;
|
||||
const newUrl = currentUrl.replace(/\/task\/\d+$/, "");
|
||||
window.history.replaceState({}, "", newUrl);
|
||||
document.body.style.overflow = "auto";
|
||||
console.log(task);
|
||||
};
|
||||
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
const toggleModalSize = () => {
|
||||
@ -310,6 +301,17 @@ export const ModalTiсket = ({
|
||||
});
|
||||
}
|
||||
|
||||
const closeModal = () => {
|
||||
if (timerStart) {
|
||||
stopTaskTimer();
|
||||
}
|
||||
setActive(false);
|
||||
const currentUrl = window.location.pathname;
|
||||
const newUrl = currentUrl.replace(/\/task\/\d+$/, "");
|
||||
window.history.replaceState({}, "", newUrl);
|
||||
document.body.style.overflow = "auto";
|
||||
};
|
||||
|
||||
function taskExecutor(person) {
|
||||
apiRequest("/task/update-task", {
|
||||
method: "PUT",
|
||||
@ -380,82 +382,111 @@ export const ModalTiсket = ({
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
initListeners();
|
||||
apiRequest(
|
||||
`/comment/get-by-entity?entity_type=2&entity_id=${task.id}`
|
||||
).then((res) => {
|
||||
const comments = res.reduce((acc, cur) => {
|
||||
if (!cur.parent_id) {
|
||||
acc.push({ ...cur, subComments: [] });
|
||||
} else {
|
||||
acc.forEach((item) => {
|
||||
if (item.id === cur.parent_id) item.subComments.push(cur);
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
setComments(comments);
|
||||
});
|
||||
apiRequest(`/timer/get-by-entity?entity_type=2&entity_id=${task.id}`).then(
|
||||
(res) => {
|
||||
let timerSeconds = 0;
|
||||
res.length &&
|
||||
res.forEach((time) => {
|
||||
timerSeconds += time.deltaSeconds;
|
||||
setCurrentTimerCount({
|
||||
hours: Math.floor(timerSeconds / 60 / 60),
|
||||
minute: Math.floor((timerSeconds / 60) % 60),
|
||||
seconds: timerSeconds % 60
|
||||
if (active) {
|
||||
setStartDate(task.dead_line ? new Date(task.dead_line) : new Date());
|
||||
setTaskPriority(task.execution_priority);
|
||||
setMembers(task.taskUsers);
|
||||
setTaskTags(task.mark);
|
||||
setExecutorId(task.executor_id);
|
||||
setDeadLine(task.dead_line);
|
||||
setExecutor(task.executor);
|
||||
setInputsValue({
|
||||
title: task.title,
|
||||
description: task.description,
|
||||
comment: ""
|
||||
});
|
||||
|
||||
initListeners();
|
||||
|
||||
apiRequest(
|
||||
`/comment/get-by-entity?entity_type=2&entity_id=${task.id}`
|
||||
).then((res) => {
|
||||
const comments = res.reduce((acc, cur) => {
|
||||
if (!cur.parent_id) {
|
||||
acc.push({ ...cur, subComments: [] });
|
||||
} else {
|
||||
acc.forEach((item) => {
|
||||
if (item.id === cur.parent_id) item.subComments.push(cur);
|
||||
});
|
||||
updateTimerHours = Math.floor(timerSeconds / 60 / 60);
|
||||
updateTimerMinute = Math.floor((timerSeconds / 60) % 60);
|
||||
updateTimerSec = timerSeconds % 60;
|
||||
if (!time.stopped_at) {
|
||||
setTimerStart(true);
|
||||
startTimer();
|
||||
setTimerInfo(time);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
setComments(comments);
|
||||
});
|
||||
|
||||
apiRequest(`/file/get-by-entity?entity_type=2&entity_id=${task.id}`).then(
|
||||
(res) => {
|
||||
apiRequest(
|
||||
`/timer/get-by-entity?entity_type=2&entity_id=${task.id}`
|
||||
).then((res) => {
|
||||
if (Array.isArray(res)) {
|
||||
setTaskFiles(res);
|
||||
}
|
||||
}
|
||||
);
|
||||
let timerSeconds = 0;
|
||||
res.length &&
|
||||
res.forEach((time) => {
|
||||
timerSeconds += time.deltaSeconds;
|
||||
setCurrentTimerCount({
|
||||
hours: Math.floor(timerSeconds / 60 / 60),
|
||||
minute: Math.floor((timerSeconds / 60) % 60),
|
||||
seconds: timerSeconds % 60
|
||||
});
|
||||
updateTimerHours = Math.floor(timerSeconds / 60 / 60);
|
||||
updateTimerMinute = Math.floor((timerSeconds / 60) % 60);
|
||||
updateTimerSec = timerSeconds % 60;
|
||||
|
||||
if (
|
||||
localStorage.getItem("role_status") !== "18" &&
|
||||
Boolean(
|
||||
if (!time.stopped_at) {
|
||||
setTimerStart(true);
|
||||
startTimer();
|
||||
setTimerInfo(time);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setCurrentTimerCount({
|
||||
hours: 0,
|
||||
minute: 0,
|
||||
seconds: 0
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
apiRequest(`/file/get-by-entity?entity_type=2&entity_id=${task.id}`).then(
|
||||
(res) => {
|
||||
if (Array.isArray(res)) {
|
||||
setTaskFiles(res);
|
||||
} else {
|
||||
setTaskFiles([]);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (
|
||||
localStorage.getItem("role_status") !== "18" &&
|
||||
Array.isArray(correctProjectUsers) &&
|
||||
!correctProjectUsers.find(
|
||||
(item) => item.user_id === profileInfo.id_user
|
||||
)
|
||||
)
|
||||
) {
|
||||
setCorrectProjectUsers((prevState) => [
|
||||
...prevState,
|
||||
{
|
||||
user: {
|
||||
avatar: profileInfo.photo,
|
||||
fio: profileInfo.fio
|
||||
},
|
||||
user_id: profileInfo.id_user
|
||||
}
|
||||
]);
|
||||
) {
|
||||
setCorrectProjectUsers((prevState) => [
|
||||
...prevState,
|
||||
{
|
||||
user: {
|
||||
avatar: profileInfo.photo,
|
||||
fio: profileInfo.fio
|
||||
},
|
||||
user_id: profileInfo.id_user
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
}, [active]);
|
||||
|
||||
useEffect(() => {
|
||||
let tagIds = taskTags.map((tag) => tag.id);
|
||||
setCorrectProjectTags(
|
||||
projectMarks.reduce((acc, cur) => {
|
||||
if (!tagIds.includes(cur.id)) acc.push(cur);
|
||||
return acc;
|
||||
}, [])
|
||||
);
|
||||
if (Array.isArray(taskTags)) {
|
||||
const tagIds = taskTags.map((tag) => tag.id);
|
||||
setCorrectProjectTags(
|
||||
projectMarks.reduce((acc, cur) => {
|
||||
if (!tagIds.includes(cur.id)) acc.push(cur);
|
||||
return acc;
|
||||
}, [])
|
||||
);
|
||||
}
|
||||
}, [taskTags]);
|
||||
|
||||
async function handleUpload(event) {
|
||||
@ -534,13 +565,15 @@ export const ModalTiсket = ({
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let ids = members.map((user) => user.user_id);
|
||||
setUsers(
|
||||
projectUsers.reduce((acc, cur) => {
|
||||
if (!ids.includes(cur.user_id)) acc.push(cur);
|
||||
return acc;
|
||||
}, [])
|
||||
);
|
||||
if (Array.isArray(members)) {
|
||||
const ids = members.map((user) => user.user_id);
|
||||
setUsers(
|
||||
projectUsers.reduce((acc, cur) => {
|
||||
if (!ids.includes(cur.user_id)) acc.push(cur);
|
||||
return acc;
|
||||
}, [])
|
||||
);
|
||||
}
|
||||
}, [members]);
|
||||
|
||||
function copyTicketLink() {
|
||||
@ -717,7 +750,7 @@ export const ModalTiсket = ({
|
||||
)}
|
||||
{/*<img src={taskImg} className="image-task"></img>*/}
|
||||
</div>
|
||||
{Boolean(taskFiles.length) && (
|
||||
{Boolean(taskFiles?.length) && (
|
||||
<div className="task__files">
|
||||
{taskFiles.map((file) => {
|
||||
return (
|
||||
@ -877,7 +910,7 @@ export const ModalTiсket = ({
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{Boolean(members.length) && (
|
||||
{Boolean(members?.length) && (
|
||||
<div className="members">
|
||||
<h5>Участники:</h5>
|
||||
<div className="members__list">
|
||||
@ -1009,23 +1042,24 @@ export const ModalTiсket = ({
|
||||
<div className="workers_box-tag">
|
||||
<div className="tags">
|
||||
<div className="tags__selected">
|
||||
{taskTags.map((tag) => {
|
||||
return (
|
||||
<div
|
||||
className="tags__selected__item"
|
||||
key={tag.id}
|
||||
style={{ background: tag.color }}
|
||||
>
|
||||
<p>{tag.slug}</p>
|
||||
<img
|
||||
src={crossWhite}
|
||||
className="delete"
|
||||
alt="delete"
|
||||
onClick={() => deleteTagFromTask(tag.id)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{Array.isArray(taskTags) &&
|
||||
taskTags.map((tag) => {
|
||||
return (
|
||||
<div
|
||||
className="tags__selected__item"
|
||||
key={tag.id}
|
||||
style={{ background: tag.color }}
|
||||
>
|
||||
<p>{tag.slug}</p>
|
||||
<img
|
||||
src={crossWhite}
|
||||
className="delete"
|
||||
alt="delete"
|
||||
onClick={() => deleteTagFromTask(tag.id)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div
|
||||
className="tags__select"
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { forwardRef, useEffect, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
import { movePositionProjectTask } from "@redux/projectsTrackerSlice";
|
||||
@ -14,173 +14,181 @@ import avatarMok from "assets/images/avatarMok.webp";
|
||||
|
||||
import "./trackerCardTask.scss";
|
||||
|
||||
const TrackerCardTask = ({
|
||||
task,
|
||||
projectBoard,
|
||||
titleColor,
|
||||
column,
|
||||
openTicket,
|
||||
startWrapperIndexTest,
|
||||
setWrapperHover
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [taskHover, setTaskHover] = useState({});
|
||||
const TrackerCardTask = forwardRef(
|
||||
(
|
||||
{
|
||||
task,
|
||||
projectBoard,
|
||||
titleColor,
|
||||
column,
|
||||
openTicket,
|
||||
startWrapperIndexTest,
|
||||
setWrapperHover
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const dispatch = useDispatch();
|
||||
const [taskHover, setTaskHover] = useState({});
|
||||
|
||||
const priority = {
|
||||
2: "Высокий",
|
||||
1: "Средний",
|
||||
0: "Низкий"
|
||||
};
|
||||
const priority = {
|
||||
2: "Высокий",
|
||||
1: "Средний",
|
||||
0: "Низкий"
|
||||
};
|
||||
|
||||
const priorityClass = {
|
||||
2: "high",
|
||||
1: "middle",
|
||||
0: "low"
|
||||
};
|
||||
const priorityClass = {
|
||||
2: "high",
|
||||
1: "middle",
|
||||
0: "low"
|
||||
};
|
||||
|
||||
function dragDropTaskHandler(e, task, column) {
|
||||
e.preventDefault();
|
||||
if (task.id === startWrapperIndexTest.current.task.id) {
|
||||
return;
|
||||
function dragDropTaskHandler(e, task, column) {
|
||||
e.preventDefault();
|
||||
if (task.id === startWrapperIndexTest.current.task.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const finishTask = column.tasks.indexOf(task);
|
||||
|
||||
dispatch(
|
||||
movePositionProjectTask({
|
||||
startTask: startWrapperIndexTest.current.task,
|
||||
finishTask: task,
|
||||
finishIndex: finishTask
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const finishTask = column.tasks.indexOf(task);
|
||||
function dragOverTaskHandler(e, task) {
|
||||
e.preventDefault();
|
||||
if (startWrapperIndexTest.current.task.id === task.id) {
|
||||
return;
|
||||
}
|
||||
setTaskHover((prevState) => ({ [prevState]: false, [task.id]: true }));
|
||||
}
|
||||
|
||||
dispatch(
|
||||
movePositionProjectTask({
|
||||
startTask: startWrapperIndexTest.current.task,
|
||||
finishTask: task,
|
||||
finishIndex: finishTask
|
||||
})
|
||||
function dragStartHandler(e, task, columnId) {
|
||||
startWrapperIndexTest.current = { task: task, index: columnId };
|
||||
}
|
||||
|
||||
function dragLeaveTaskHandler() {
|
||||
setTaskHover((prevState) => ({ [prevState]: false }));
|
||||
}
|
||||
|
||||
function dragEndTaskHandler() {
|
||||
setTaskHover((prevState) => ({ [prevState]: false }));
|
||||
setWrapperHover((prevState) => ({
|
||||
[prevState]: false
|
||||
}));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const tasksHover = {};
|
||||
const columnHover = {};
|
||||
|
||||
if (Object.keys(projectBoard).length) {
|
||||
projectBoard.columns.forEach((column) => {
|
||||
columnHover[column.id] = false;
|
||||
column.tasks.forEach((task) => (tasksHover[task.id] = false));
|
||||
});
|
||||
}
|
||||
setWrapperHover(columnHover);
|
||||
setTaskHover(tasksHover);
|
||||
}, [projectBoard]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
key={task.id}
|
||||
className={`tasks__board__item ${
|
||||
taskHover[task.id] ? "task__hover" : ""
|
||||
}`}
|
||||
draggable={true}
|
||||
onDragStart={(e) => dragStartHandler(e, task, column.id)}
|
||||
onDragOver={(e) => dragOverTaskHandler(e, task)}
|
||||
onDragLeave={(e) => dragLeaveTaskHandler(e)}
|
||||
onDragEnd={() => dragEndTaskHandler()}
|
||||
onDrop={(e) => dragDropTaskHandler(e, task, column)}
|
||||
onClick={() => openTicket(task)}
|
||||
>
|
||||
<div className="tasks__board__item__title">
|
||||
<p className="task__board__item__title">{task.title}</p>
|
||||
</div>
|
||||
<p
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: task.description
|
||||
}}
|
||||
className="tasks__board__item__description"
|
||||
></p>
|
||||
{Boolean(task.mark.length) && (
|
||||
<div className="tasks__board__item__tags">
|
||||
{task.mark.map((tag) => {
|
||||
return (
|
||||
<div
|
||||
className="tag-item"
|
||||
key={tag.id}
|
||||
style={{ background: tag.color }}
|
||||
>
|
||||
<p>{tag.slug}</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<div className="tasks__board__item__container">
|
||||
{typeof task.execution_priority === "number" && (
|
||||
<div className="tasks__board__item__priority">
|
||||
<p>⚡</p>
|
||||
<span className={priorityClass[task.execution_priority]}>
|
||||
{priority[task.execution_priority]}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{task.dead_line && (
|
||||
<div className="tasks__board__item__dead-line">
|
||||
<p>⌛</p>
|
||||
<span style={{ color: titleColor }}>
|
||||
{getCorrectDate(task.dead_line)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="tasks__board__item__info">
|
||||
<div className="tasks__board__item__executor">
|
||||
<img
|
||||
src={
|
||||
task.executor?.avatar
|
||||
? urlForLocal(task.executor?.avatar)
|
||||
: avatarMok
|
||||
}
|
||||
alt="avatar"
|
||||
/>
|
||||
<span>
|
||||
{removeLast(task.executor?.fio) || "Исполнитель не назначен"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="tasks__board__item__info__tags">
|
||||
<div className="tasks__board__item__info__more">
|
||||
<img src={commentsBoard} alt="commentsImg" />
|
||||
<span>{task.comment_count}</span>
|
||||
</div>
|
||||
<div className="tasks__board__item__info__more">
|
||||
<img src={filesBoard} alt="filesImg" />
|
||||
<span>{task.file_count}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<TrackerSelectColumn
|
||||
columns={projectBoard.columns.filter((item) => item.id !== column.id)}
|
||||
currentColumn={column}
|
||||
task={task}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function dragOverTaskHandler(e, task) {
|
||||
e.preventDefault();
|
||||
if (startWrapperIndexTest.current.task.id === task.id) {
|
||||
return;
|
||||
}
|
||||
setTaskHover((prevState) => ({ [prevState]: false, [task.id]: true }));
|
||||
}
|
||||
|
||||
function dragStartHandler(e, task, columnId) {
|
||||
startWrapperIndexTest.current = { task: task, index: columnId };
|
||||
}
|
||||
|
||||
function dragLeaveTaskHandler() {
|
||||
setTaskHover((prevState) => ({ [prevState]: false }));
|
||||
}
|
||||
|
||||
function dragEndTaskHandler() {
|
||||
setTaskHover((prevState) => ({ [prevState]: false }));
|
||||
setWrapperHover((prevState) => ({
|
||||
[prevState]: false
|
||||
}));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const tasksHover = {};
|
||||
const columnHover = {};
|
||||
|
||||
if (Object.keys(projectBoard).length) {
|
||||
projectBoard.columns.forEach((column) => {
|
||||
columnHover[column.id] = false;
|
||||
column.tasks.forEach((task) => (tasksHover[task.id] = false));
|
||||
});
|
||||
}
|
||||
setWrapperHover(columnHover);
|
||||
setTaskHover(tasksHover);
|
||||
}, [projectBoard]);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={task.id}
|
||||
className={`tasks__board__item ${
|
||||
taskHover[task.id] ? "task__hover" : ""
|
||||
}`}
|
||||
draggable={true}
|
||||
onDragStart={(e) => dragStartHandler(e, task, column.id)}
|
||||
onDragOver={(e) => dragOverTaskHandler(e, task)}
|
||||
onDragLeave={(e) => dragLeaveTaskHandler(e)}
|
||||
onDragEnd={() => dragEndTaskHandler()}
|
||||
onDrop={(e) => dragDropTaskHandler(e, task, column)}
|
||||
onClick={(e) => openTicket(e, task)}
|
||||
>
|
||||
<div className="tasks__board__item__title">
|
||||
<p className="task__board__item__title">{task.title}</p>
|
||||
</div>
|
||||
<p
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: task.description
|
||||
}}
|
||||
className="tasks__board__item__description"
|
||||
></p>
|
||||
{Boolean(task.mark.length) && (
|
||||
<div className="tasks__board__item__tags">
|
||||
{task.mark.map((tag) => {
|
||||
return (
|
||||
<div
|
||||
className="tag-item"
|
||||
key={tag.id}
|
||||
style={{ background: tag.color }}
|
||||
>
|
||||
<p>{tag.slug}</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<div className="tasks__board__item__container">
|
||||
{typeof task.execution_priority === "number" && (
|
||||
<div className="tasks__board__item__priority">
|
||||
<p>⚡</p>
|
||||
<span className={priorityClass[task.execution_priority]}>
|
||||
{priority[task.execution_priority]}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{task.dead_line && (
|
||||
<div className="tasks__board__item__dead-line">
|
||||
<p>⌛</p>
|
||||
<span style={{ color: titleColor }}>
|
||||
{getCorrectDate(task.dead_line)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="tasks__board__item__info">
|
||||
<div className="tasks__board__item__executor">
|
||||
<img
|
||||
src={
|
||||
task.executor?.avatar
|
||||
? urlForLocal(task.executor?.avatar)
|
||||
: avatarMok
|
||||
}
|
||||
alt="avatar"
|
||||
/>
|
||||
<span>
|
||||
{removeLast(task.executor?.fio) || "Исполнитель не назначен"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="tasks__board__item__info__tags">
|
||||
<div className="tasks__board__item__info__more">
|
||||
<img src={commentsBoard} alt="commentsImg" />
|
||||
<span>{task.comment_count}</span>
|
||||
</div>
|
||||
<div className="tasks__board__item__info__more">
|
||||
<img src={filesBoard} alt="filesImg" />
|
||||
<span>{task.file_count}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<TrackerSelectColumn
|
||||
columns={projectBoard.columns.filter((item) => item.id !== column.id)}
|
||||
currentColumn={column}
|
||||
task={task}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
TrackerCardTask.displayName = "TrackerCardTask";
|
||||
|
||||
export default TrackerCardTask;
|
||||
|
@ -12,6 +12,7 @@ import ellipseGreen from "assets/images/landingTracker/ellipseGreen.svg";
|
||||
import cat from "assets/images/landingTracker/landingCat.webp";
|
||||
import flag from "assets/images/landingTracker/projectsFlag.webp";
|
||||
import questionMark from "assets/images/landingTracker/questionMark.svg";
|
||||
import target from "assets/images/landingTracker/target.webp";
|
||||
import trackerCup from "assets/images/landingTracker/trackerCup.webp";
|
||||
import trackerPreview from "assets/images/landingTracker/trackerPreview.webp";
|
||||
import trackerSign from "assets/images/landingTracker/trackerSign.webp";
|
||||
@ -173,9 +174,9 @@ export const LandingTracker = () => {
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{/* <div className="steps__portfolio">
|
||||
<img src={portfolio} alt="portfolio" />
|
||||
</div> */}
|
||||
<div className="goals__target">
|
||||
<img src={target} alt="target" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
@ -446,6 +446,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__target {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import moment from "moment";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Link, useParams } from "react-router-dom";
|
||||
import { Link, useLocation, useParams } from "react-router-dom";
|
||||
|
||||
import {
|
||||
activeLoader,
|
||||
@ -51,6 +51,8 @@ import avatarMok from "assets/images/avatarMok.webp";
|
||||
export const ProjectTracker = () => {
|
||||
const dispatch = useDispatch();
|
||||
const projectId = useParams();
|
||||
const taskParams = useParams();
|
||||
const taskRefs = useRef([]);
|
||||
|
||||
const [openColumnSelect, setOpenColumnSelect] = useState({});
|
||||
const [selectedTab, setSelectedTab] = useState(0);
|
||||
@ -78,6 +80,29 @@ export const ProjectTracker = () => {
|
||||
initListeners();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// const observer = new MutationObserver(() => {
|
||||
// if (taskParams.taskId && taskRefs.current[taskParams.taskId]) {
|
||||
// taskRefs.current[taskParams.taskId].click();
|
||||
// console.log(taskRefs.current[taskParams.taskId]);
|
||||
// }
|
||||
// });
|
||||
|
||||
// observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
// return () => observer.disconnect();
|
||||
if (projectBoard.columns && taskParams.taskId) {
|
||||
for (const column of projectBoard.columns) {
|
||||
const task = column.tasks.find((task) => task.id == taskParams.taskId);
|
||||
if (task) {
|
||||
openTicket(task);
|
||||
return;
|
||||
}
|
||||
}
|
||||
console.log(projectBoard);
|
||||
}
|
||||
}, [projectBoard]);
|
||||
|
||||
useEffect(() => {
|
||||
let columnsTasksEmpty = true;
|
||||
if (Object.keys(projectBoard).length) {
|
||||
@ -145,21 +170,32 @@ export const ProjectTracker = () => {
|
||||
setPriorityTask(length);
|
||||
}
|
||||
|
||||
function openTicket(e, task) {
|
||||
const updateUrlWithTaskId = (taskId) => {
|
||||
const currentUrl = window.location.pathname;
|
||||
const taskUrlSegment = `/task/`;
|
||||
|
||||
if (currentUrl.includes(taskUrlSegment)) {
|
||||
// Если URL содержит '/task/', заменяем старый ID на новый
|
||||
const baseUrl = currentUrl.substring(
|
||||
0,
|
||||
currentUrl.indexOf(taskUrlSegment) + taskUrlSegment.length
|
||||
);
|
||||
const newUrl = `${baseUrl}${taskId}`;
|
||||
window.history.pushState({}, "", newUrl);
|
||||
} else {
|
||||
// Если URL не содержит '/task/', добавляем '/task/${taskId}'
|
||||
const newUrl = `${currentUrl}${taskUrlSegment}${taskId}`;
|
||||
window.history.pushState({}, "", newUrl);
|
||||
}
|
||||
};
|
||||
|
||||
function openTicket(task) {
|
||||
setSelectedTicket(task);
|
||||
setModalActiveTicket(true);
|
||||
const currentUrl = window.location.pathname;
|
||||
const newUrl = `${currentUrl}/task/${task.id}`;
|
||||
window.history.pushState({}, "", newUrl);
|
||||
updateUrlWithTaskId(task.id);
|
||||
document.body.style.overflow = "hidden";
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const currentUrl = window.location.pathname;
|
||||
const newUrl = currentUrl.replace(/\/task\/\d+$/, "");
|
||||
window.history.replaceState({}, "", newUrl);
|
||||
}, []);
|
||||
|
||||
function deleteColumn(column) {
|
||||
const priorityColumns = [];
|
||||
apiRequest("/project-column/update-column", {
|
||||
@ -421,19 +457,16 @@ export const ProjectTracker = () => {
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{Boolean(modalActiveTicket) && (
|
||||
<ModalTicket
|
||||
active={modalActiveTicket}
|
||||
setActive={setModalActiveTicket}
|
||||
task={selectedTicket}
|
||||
projectId={projectBoard.id}
|
||||
projectName={projectBoard.name}
|
||||
projectUsers={projectBoard.projectUsers}
|
||||
projectOwnerId={projectBoard.owner_id}
|
||||
projectMarks={projectBoard.mark}
|
||||
/>
|
||||
)}
|
||||
<ModalTicket
|
||||
active={modalActiveTicket}
|
||||
setActive={setModalActiveTicket}
|
||||
task={selectedTicket}
|
||||
projectId={projectBoard.id}
|
||||
projectName={projectBoard.name}
|
||||
projectUsers={projectBoard.projectUsers}
|
||||
projectOwnerId={projectBoard.owner_id}
|
||||
projectMarks={projectBoard.mark}
|
||||
/>
|
||||
|
||||
<div className="tasks__container">
|
||||
{Boolean(projectBoard?.columns) &&
|
||||
@ -535,6 +568,9 @@ export const ProjectTracker = () => {
|
||||
startWrapperIndexTest={startWrapperIndexTest}
|
||||
task={task}
|
||||
titleColor={titleColor}
|
||||
ref={(el) => {
|
||||
taskRefs.current[task.id] = el;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@ -24,6 +24,7 @@ export const DeveloperPage = () => {
|
||||
return (
|
||||
<Routes>
|
||||
<Route exact path="/tracker/task/:id" element={<TicketFullScreen />} />
|
||||
|
||||
<Route
|
||||
exact
|
||||
path="/tracker/project/:id/task/:taskId"
|
||||
|
Loading…
Reference in New Issue
Block a user