diff --git a/src/assets/images/accept.png b/src/assets/images/accept.png new file mode 100644 index 00000000..43966e45 Binary files /dev/null and b/src/assets/images/accept.png differ diff --git a/src/assets/images/mainTaskCommentImg.png b/src/assets/images/mainTaskCommentImg.png new file mode 100644 index 00000000..8b377db5 Binary files /dev/null and b/src/assets/images/mainTaskCommentImg.png differ diff --git a/src/components/Modal/Tracker/ModalTicket/ModalTicket.scss b/src/components/Modal/Tracker/ModalTicket/ModalTicket.scss index 72628097..ce06851a 100644 --- a/src/components/Modal/Tracker/ModalTicket/ModalTicket.scss +++ b/src/components/Modal/Tracker/ModalTicket/ModalTicket.scss @@ -63,22 +63,111 @@ .comments__list { display: flex; flex-direction: column; - row-gap: 10px; + max-height: 420px; + overflow: auto; + + &::-webkit-scrollbar { + width: 4px; + border-radius: 10px; + } + + &::-webkit-scrollbar-thumb { + background: #cbd9f9; + border-radius: 10px; + } + + &::-webkit-scrollbar-track { + background: #c5c0c6; + border-radius: 10px; + } + &__item { padding: 10px 20px; display: flex; flex-direction: column; max-width: 438px; - background: #f1f1f1; border-radius: 44px; font-size: 14px; width: 100%; - row-gap: 10px; + position: relative; + + &__subComment { + &:before { + content: ''; + background: #E4E4E6; + height: 1px; + width: 7px; + position: absolute; + top: 36%; + left: 2.5%; + } + } + + &__main { + &:after { + content: ''; + position: absolute; + background-image: url("../../../images/mainTaskCommentImg.png"); + width: 10px; + height: 8px; + top: 50px; + left: 25px; + } + + &:before { + content: ''; + position: absolute; + background: #E4E4E6; + width: 1px; + height: calc(100% - 120px); + left: 29px; + top: 65px; + } + } + + &__fio { + display: flex; + align-items: center; + + p { + font-size: 12px; + color: #000000; + line-height: 32px; + max-width: 150px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + margin-left: 10px; + } + + img { + width: 24px; + height: 24px; + } + } + + &__date { + display: flex; + align-items: center; + column-gap: 5px; + + img { + cursor: pointer; + width: 15px; + } + + span { + font-size: 12px; + } + } + + &__text { + margin-left: 34px; + } &__info { display: flex; - justify-content: center; - column-gap: 15px; + justify-content: space-between; .edit { width: 25px; @@ -91,10 +180,36 @@ .edit__open { background: green; } + } - img { - cursor: pointer; - width: 15px; + &__answer { + margin-left: 34px; + text-decoration-line: underline; + font-weight: 400; + font-size: 10px; + line-height: 32px; + cursor: pointer; + + &__new { + margin-left: 34px; + font-size: 14px; + border-radius: 5px; + border: 1px solid gainsboro; + padding: 3px 5px; + display: flex; + align-items: center; + margin-top: 5px; + + img { + width: 20px; + height: 20px; + cursor: pointer; + } + + input { + width: 90%; + border: none; + } } } } @@ -289,14 +404,28 @@ color: white; background: #1458dd; border-radius: 44px; - opacity: 0.5; - pointer-events: none; img { margin-left: 10px; } } + .disable { + opacity: 0.5; + pointer-events: none; + } + + .stop { + font-size: 12px; + margin-top: 25px; + width: 151px; + height: 40px; + border: none; + color: white; + background: red; + border-radius: 44px; + } + .time { display: flex; align-items: center; diff --git a/src/components/Modal/Tracker/TicketFullScreen/TicketFullScreen.jsx b/src/components/Modal/Tracker/TicketFullScreen/TicketFullScreen.jsx index 8f1a3f8b..6c845bab 100644 --- a/src/components/Modal/Tracker/TicketFullScreen/TicketFullScreen.jsx +++ b/src/components/Modal/Tracker/TicketFullScreen/TicketFullScreen.jsx @@ -1,48 +1,45 @@ import React, { useEffect, useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { Link, useNavigate, useParams } from "react-router-dom"; +import { ProfileHeader } from "../../../ProfileHeader/ProfileHeader"; +import { ProfileBreadcrumbs } from "../../../ProfileBreadcrumbs/ProfileBreadcrumbs"; +import { Footer } from "@components/Common/Footer/Footer"; +import { Link, useParams, useNavigate } from "react-router-dom"; +import TrackerModal from "../../../Modal/TrackerModal/TrackerModal"; +import TrackerTaskComment from "../../../TrackerTaskComment/TrackerTaskComment"; +import { Navigation } from "../../../Navigation/Navigation"; +import {Loader} from "@components/Common/Loader/Loader"; + +import {useDispatch, useSelector} from "react-redux"; import { deletePersonOnProject, - getBoarderLoader, - getProjectBoard, modalToggle, setProjectBoardFetch, setToggleTab, -} from "@redux/projectsTrackerSlice"; + getProjectBoard, + getBoarderLoader, +} from "../../../../redux/projectsTrackerSlice"; +import { apiRequest } from "../../../../api/request"; -import { urlForLocal } from "@utils/helper"; - -import { apiRequest } from "@api/request"; - -import { getCorrectDate } from "@components/Calendar/calendarHelper"; -import BaseButton from "@components/Common/BaseButton/BaseButton"; -import { Footer } from "@components/Common/Footer/Footer"; -import { Loader } from "@components/Common/Loader/Loader"; -import TrackerModal from "@components/Modal/TrackerModal/TrackerModal"; -import { Navigation } from "@components/Navigation/Navigation"; -import { ProfileBreadcrumbs } from "@components/ProfileBreadcrumbs/ProfileBreadcrumbs"; -import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader"; - -import archive2 from "assets/icons/archive.svg"; -import archive from "assets/icons/archiveTracker.svg"; -import arrow from "assets/icons/arrows/arrowCalendar.png"; -import arrow2 from "assets/icons/arrows/arrowStart.png"; -import selectArrow from "assets/icons/arrows/select.svg"; -import close from "assets/icons/closeProjectPersons.svg"; -import del from "assets/icons/delete.svg"; -import edit from "assets/icons/edit.svg"; -import file from "assets/icons/fileModal.svg"; -import link from "assets/icons/link.svg"; -import plus from "assets/icons/plus.svg"; -import send from "assets/icons/send.svg"; -import project from "assets/icons/trackerProject.svg"; -import tasks from "assets/icons/trackerTasks.svg"; -import watch from "assets/icons/watch.svg"; +import project from "../../../../assets/icons/trackerProject.svg"; +import watch from "../../../../assets/icons/watch.svg"; +import file from "../../../../assets/icons/fileModal.svg"; +import send from "../../../../assets/icons/send.svg"; +import arrow2 from "../../../../assets/icons/arrows/arrowStart.png"; +import plus from "../../../../assets/icons/plus.svg"; +import tasks from "../../../../assets/icons/trackerTasks.svg"; +import archive from "../../../../assets/icons/archive.svg"; +import arrow from "../../../../assets/icons/arrows/arrowCalendar.png"; +import link from "../../../../assets/icons/link.svg"; +import archive2 from "../../../../assets/icons/archive.svg"; +import del from "../../../../assets/icons/delete.svg"; +import edit from "../../../../assets/icons/edit.svg"; +import close from "../../../../assets/icons/close.png"; import "./ticketFullScreen.scss"; -export const TicketFullScreen = () => { +import {getCorrectRequestDate, urlForLocal} from "../../../../utils/helper"; + +export const TicketFullScreen = ({}) => { const [modalAddWorker, setModalAddWorker] = useState(false); const ticketId = useParams(); const dispatch = useDispatch(); @@ -54,35 +51,35 @@ export const TicketFullScreen = () => { const [inputsValue, setInputsValue] = useState({}); const [loader, setLoader] = useState(true); const [comments, setComments] = useState([]); - const [commentsEditOpen, setCommentsEditOpen] = useState({}); - const [commentsEditText, setCommentsEditText] = useState({}); - const [personListOpen, setPersonListOpen] = useState(false); + const [personListOpen, setPersonListOpen] = useState(false) + const [timerStart, setTimerStart] = useState(false) + const [timerInfo, setTimerInfo] = useState({}) useEffect(() => { apiRequest(`/task/get-task?task_id=${ticketId.id}`).then((taskInfo) => { setTaskInfo(taskInfo); - setInputsValue({ - title: taskInfo.title, - description: taskInfo.description, - comment: "", - }); - apiRequest( - `/comment/get-by-entity?entity_type=2&entity_id=${taskInfo.id}` - ).then((res) => { - setComments(res); - res.forEach((item) => { - setCommentsEditOpen((prevValue) => ({ - ...prevValue, - [item.id]: false, - })); - setCommentsEditText((prevValue) => ({ - ...prevValue, - [item.id]: item.text, - })); - }); - }); + setInputsValue({title: taskInfo.title, description: taskInfo.description, comment: ''}) + apiRequest(`/comment/get-by-entity?entity_type=2&entity_id=${taskInfo.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) + }) + taskInfo.timers.forEach((time) => { + if (!time.stopped_at) { + setTimerStart(true) + setTimerInfo(time) + } + }) dispatch(setProjectBoardFetch(taskInfo.project_id)); - setLoader(boardLoader); + setLoader(boardLoader) }); }, []); @@ -104,9 +101,10 @@ export const TicketFullScreen = () => { data: { task_id: taskInfo.id, title: inputsValue.title, - description: inputsValue.description, + description: inputsValue.description }, - }).then(() => {}); + }).then(() => { + }); } function createComment() { @@ -115,43 +113,39 @@ export const TicketFullScreen = () => { data: { text: inputsValue.comment, entity_type: 2, - entity_id: taskInfo.id, - }, + entity_id: taskInfo.id + } }).then((res) => { - let newComment = res; - newComment.created_at = new Date(); - setInputsValue((prevValue) => ({ ...prevValue, comment: "" })); - setComments((prevValue) => [...prevValue, newComment]); - setCommentsEditOpen((prevValue) => ({ ...prevValue, [res.id]: false })); - setCommentsEditText((prevValue) => ({ - ...prevValue, - [res.id]: res.text, - })); - }); + let newComment = res + newComment.created_at = new Date() + newComment.subComments = [] + setInputsValue((prevValue) => ({...prevValue, comment: ''})) + setComments((prevValue) => ([...prevValue, newComment])) + }) } - function deleteComment(commentId) { - apiRequest("/comment/update", { - method: "PUT", + function startTaskTimer() { + apiRequest("/timer/create", { + method: "POST", data: { - comment_id: commentId, - status: 0, - }, - }).then(() => { - setComments((prevValue) => - prevValue.filter((item) => item.id !== commentId) - ); - }); + entity_type: 2, + entity_id: taskInfo.id, + created_at: getCorrectRequestDate(new Date()) + } + }).then((res) => { + setTimerStart(true) + setTimerInfo(res) + }) } - function editComment(commentId) { - apiRequest("/comment/update", { + function stopTaskTimer() { + apiRequest("/timer/update", { method: "PUT", data: { - comment_id: commentId, - text: commentsEditText[commentId], - }, - }).then(() => {}); + timer_id: timerInfo.id, + stopped_at: getCorrectRequestDate(new Date()) + } + }).then(() => setTimerStart(false)) } function deletePerson(userId) { @@ -159,364 +153,304 @@ export const TicketFullScreen = () => { method: "DELETE", data: { project_id: projectBoard.id, - user_id: userId, + user_id: userId }, }).then(() => { - dispatch(deletePersonOnProject(userId)); + dispatch(deletePersonOnProject(userId)) }); } + function commentDelete(comment) { + setComments((prevValue) => prevValue.filter((item) => item.id !== comment.id)) + if (comment.subComments.length) { + comment.subComments.forEach((subComment) => { + apiRequest("/comment/update", { + method: "PUT", + data: { + comment_id: subComment.id, + status: 0 + } + }).then(() => { + }) + }) + } + } + + function addSubComment(commentId, subComment) { + const addSubComment = comments + addSubComment.forEach((comment) => { + if (comment.id === commentId) { + comment.subComments.push(subComment) + } + }) + setComments(addSubComment) + } + + function subCommentDelete(subComment) { + const deleteSubComment = comments + deleteSubComment.forEach((comment, index) => { + if (comment.id === subComment.parent_id) { + deleteSubComment[index].subComments = comment.subComments.filter((item) => item.id !== subComment.id) + } + }) + setComments([...deleteSubComment]) + } + const toggleTabs = (index) => { dispatch(setToggleTab(index)); }; return ( -
- - -
-
- -

Управление проектами с трекером

+
+ + +
+
+ +

Управление проектами с трекером

+
-
-
-
- toggleTabs(1)} - > - img -

Проекты

- - toggleTabs(2)} - > - img -

Все мои задачи

- - toggleTabs(3)} - > - img -

Архив

- -
- {loader ? ( - - ) : ( - <> -
-
-
-

Проект : {projectBoard.name}

+
+
+ toggleTabs(1)} + > + img +

Проекты

+ + toggleTabs(2)} + > + img +

Все мои задачи

+ + toggleTabs(3)} + > + img +

Архив

+ +
+ {loader ? : + <> +
+
+
+

Проект : {projectBoard.name}

- + -
- {/*avatar*/} - {/*avatar*/} - - {projectBoard.projectUsers?.length} - - { - setPersonListOpen(true); - }} - > - + - -

добавить участника

- {personListOpen && ( -
- close setPersonListOpen(false)} - /> -
- {projectBoard.projectUsers?.length} - участник -
-
- В проекте - “{projectBoard.name}” -
-
- {projectBoard.projectUsers?.map((person) => { - return ( -
- avatar - {person.user.fio} - delete deletePerson(person.user_id)} - /> -
- ); - })} -
-
{ - dispatch(modalToggle("addWorker")); - setModalAddWorker(true); - setPersonListOpen(false); - }} +
+ {/*avatar*/} + {/*avatar*/} + {projectBoard.projectUsers?.length} + { + setPersonListOpen(true) + }} > - + -

Добавить участников

-
-
- )} -
-
- Учавствую - arrow -
-
- Мои - arrow -
- -
-

Вернуться на проекты

- arrow -
- -
-
-
-
-
-
- Задача - {editOpen ? ( - { - setInputsValue((prevValue) => ({ - ...prevValue, - title: e.target.value, - })); - }} - /> - ) : ( -
{inputsValue.title}
- )} -
- {editOpen ? ( - { - setInputsValue((prevValue) => ({ - ...prevValue, - description: e.target.value, - })); - }} - /> - ) : ( -

{inputsValue.description}

- )} -
-
-

- { - dispatch(modalToggle("addSubtask")); - setAddSubtask(true); - }} - styles={"tasks__button"} - > - - Добавить под задачу - -

-

- - - Загрузить файл - - {0} - Файлов -

-
-
- { - setInputsValue((prevValue) => ({ - ...prevValue, - comment: e.target.value, - })); - }} - /> - -
-
- {comments.map((comment) => { - return ( -
-
- {getCorrectDate(comment.created_at)} -
- edit { - if (commentsEditOpen[comment.id]) { - editComment(comment.id); - } - setCommentsEditOpen((prevValue) => ({ - ...prevValue, - [comment.id]: !prevValue[comment.id], - })); - }} - /> + + + +

добавить участника

+ {personListOpen && +
+ close setPersonListOpen(false)} /> +
{projectBoard.projectUsers?.length}участник
+
В проекте - “{projectBoard.name}”
+
+ {projectBoard.projectUsers?.map((person) => { + return
+ avatar + {person.user.fio} + delete deletePerson(person.user_id)}/> +
+ }) + } +
+
{ + dispatch(modalToggle("addWorker")); + setModalAddWorker(true); + setPersonListOpen(false) + }} + > + + +

Добавить участников

+
- delete deleteComment(comment.id)} - /> -
- {commentsEditOpen[comment.id] ? ( - { - setCommentsEditText((prevValue) => ({ - ...prevValue, - [comment.id]: e.target.value, - })); - }} - /> - ) : ( -

{commentsEditText[comment.id]}

- )} + } +
+ +
+

Вернуться на проекты

+ arrow
- ); - })} + +
-
-
-
-

- Создатель : {taskInfo.user?.fio} -

-
- {Boolean(taskInfo.taskUsers?.length) && - taskInfo.taskUsers.map((worker, index) => { - return ( -
- -

{worker.name}

-
- ); - })} -
+
+
+
+ Задача + {editOpen ? { + setInputsValue((prevValue) => ({...prevValue, title: e.target.value})) + }} /> :
{inputsValue.title}
} +
+ {editOpen ? { + setInputsValue((prevValue) => ({...prevValue, description: e.target.value})) + }}/> :

{inputsValue.description}

} + {/**/} +
+
+

+ +

+

+ + {0} + Файлов +

+
+
+ { + setInputsValue((prevValue) => ({...prevValue, comment: e.target.value})) + }} /> + send +
+
+ {comments.map((comment) => { + return + }) -
- - Добавить исполнителя + } +
+
-
- - Добавить участников -
-
+
+
+

+ Создатель : {taskInfo.user?.fio} +

+
+ {Boolean(taskInfo.taskUsers?.length) && + taskInfo.taskUsers.map((worker, index) => { + return ( +
+ worket +

{worker.name}

+
+ ); + })} +
-
-
- - Длительность : -

{"0:00:00"}

-
+
+ + Добавить исполнителя +
+
+ + Добавить участников +
+
- -
+
+
+ watch + Длительность : +

{"0:00:00"}

+
-
-
{ - if (editOpen) { - setEditOpen(!editOpen); - editTask(); - } else { - setEditOpen(!editOpen); + {timerStart ? + + : + } - }} - > - -

{editOpen ? "сохранить" : "редактировать"}

-
-
- -

ссылка на проект

-
-
- -

в архив

-
-
- -

удалить

+
+ +
+
{ + if(editOpen) { + setEditOpen(!editOpen) + editTask() + } else { + setEditOpen(!editOpen) + } + }}> + edit +

{editOpen ? 'сохранить' : 'редактировать'}

+
+
+ link +

ссылка на проект

+
+
+ arch +

в архив

+
+
+ delete +

удалить

+
+
-
-
- - )} -
-
+ + } + +