diff --git a/src/components/TrackerTaskComment/TrackerTaskComment.jsx b/src/components/TrackerTaskComment/TrackerTaskComment.jsx
new file mode 100644
index 00000000..7dc50b23
--- /dev/null
+++ b/src/components/TrackerTaskComment/TrackerTaskComment.jsx
@@ -0,0 +1,125 @@
+import React, { useState } from "react";
+import TrackerTaskSubComment from "../TrackerTaskComment/TrackerTaskComment";
+import { apiRequest } from "../../api/request";
+import {urlForLocal} from "../../helper";
+import {getCorrectDate} from "../Calendar/calendarHelper";
+import edit from "../../images/edit.svg";
+import del from "../../images/delete.svg";
+import accept from "../../images/accept.png";
+
+export const TrackerTaskComment = ({
+ taskId,
+ comment,
+ commentDelete,
+ addSubComment,
+ subCommentDelete
+}) => {
+ const [commentsEditOpen, setCommentsEditOpen] = useState(false)
+ const [commentsEditText, setCommentsEditText] = useState(comment.text)
+ const [subCommentsCreateOpen, setSubCommentsCreateOpen] = useState(false)
+ const [subCommentsCreateText, setSubCommentsCreateText] = useState('')
+
+ function editComment() {
+ if (commentsEditText === comment.text) return
+ apiRequest("/comment/update", {
+ method: "PUT",
+ data: {
+ comment_id: comment.id,
+ text: commentsEditText
+ }
+ }).then(() => {
+ })
+ }
+
+ function deleteComment() {
+ apiRequest("/comment/update", {
+ method: "PUT",
+ data: {
+ comment_id: comment.id,
+ status: 0
+ }
+ }).then(() => {
+ if (comment.parent_id) {
+ subCommentDelete(comment)
+ } else {
+ commentDelete(comment)
+ }
+ })
+ }
+
+ function createSubComment() {
+ setSubCommentsCreateOpen(false)
+ if(!subCommentsCreateText) return
+ apiRequest("/comment/create", {
+ method: "POST",
+ data: {
+ text: subCommentsCreateText,
+ entity_type: 2,
+ entity_id: taskId,
+ parent_id: comment.id
+ }
+ }).then((res) => {
+ let newSubComment = res
+ newSubComment.created_at = new Date()
+ setSubCommentsCreateText('')
+ addSubComment(comment.id, newSubComment)
+ })
+ }
+
+ return (
+
+
+
+
})
+
{comment.user.fio}
+
+
+
{getCorrectDate(comment.created_at)}
+
+

{
+ if (commentsEditOpen) {
+ editComment()
+ }
+ setCommentsEditOpen(!commentsEditOpen)
+ }} />
+
+

deleteComment()} />
+
+
+ {commentsEditOpen ?
+
{
+ setCommentsEditText(e.target.value)
+ }} /> :
+
{commentsEditText}
}
+ {!comment.parent_id &&
+ <>
+ {
+ subCommentsCreateOpen ?
+
+
{
+ setSubCommentsCreateText(e.target.value)
+ }}/>
+

{
+ createSubComment()
+ }}
+ />
+
+ :
+
{
+ setSubCommentsCreateOpen(true)
+ }} className='comments__list__item__answer'>Ответить
+ }
+ >
+ }
+ {Boolean(comment.subComments?.length) && comment.subComments.map((subComment) => {
+ return
+ })
+ }
+
+ )
+}
+
+export default TrackerTaskComment
diff --git a/src/components/UI/ModalTicket/ModalTicket.jsx b/src/components/UI/ModalTicket/ModalTicket.jsx
index bcc76ebf..82b162fc 100644
--- a/src/components/UI/ModalTicket/ModalTicket.jsx
+++ b/src/components/UI/ModalTicket/ModalTicket.jsx
@@ -1,6 +1,7 @@
import React, {useEffect, useState} from "react";
import { Link } from "react-router-dom";
import TrackerModal from "../TrackerModal/TrackerModal";
+import TrackerTaskComment from "../../../components/TrackerTaskComment/TrackerTaskComment";
import { apiRequest } from "../../../api/request";
import { useDispatch } from "react-redux";
import {
@@ -8,8 +9,6 @@ import {
setProjectBoardFetch,
} from "../../../redux/projectsTrackerSlice";
-import {getCorrectDate} from '../../../components/Calendar/calendarHelper'
-
import category from "../../../images/category.png";
import watch from "../../../images/watch.png";
import file from "../../../images/fileModal.svg";
@@ -25,7 +24,6 @@ import close from "../../../images/closeProjectPersons.svg";
import "./ModalTicket.scss";
import {urlForLocal, getCorrectRequestDate} from "../../../helper";
-import accept from "../../../images/accept.png";
export const ModalTiсket = ({
active,
@@ -40,9 +38,6 @@ export const ModalTiсket = ({
const [editOpen, setEditOpen] = useState(false);
const [inputsValue, setInputsValue] = useState({title: task.title, description: task.description, comment: ''});
const [comments, setComments] = useState([]);
- const [commentsEditOpen, setCommentsEditOpen] = useState({})
- const [commentsEditText, setCommentsEditText] = useState({})
- const [subCommentsCreateOpen, setSubCommentsCreateOpen] = useState({})
const [dropListOpen, setDropListOpen] = useState(false)
const [dropListMembersOpen, setDropListMembersOpen] = useState(false)
const [executor, setExecutor] = useState(task.executor)
@@ -94,49 +89,48 @@ export const ModalTiсket = ({
}).then((res) => {
let newComment = res
newComment.created_at = new Date()
+ newComment.subComments = []
setInputsValue((prevValue) => ({...prevValue, comment: ''}))
setComments((prevValue) => ([...prevValue, newComment]))
- setCommentsEditOpen((prevValue) => ({...prevValue, [res.id]: false}))
- setCommentsEditText((prevValue) => ({...prevValue, [res.id]: res.text}))
})
}
- function deleteComment(commentId) {
- apiRequest("/comment/update", {
- method: "PUT",
- data: {
- comment_id: commentId,
- status: 0
+
+ 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)
}
- }).then((res) => {
- setComments((prevValue) => prevValue.filter((item) => item.id !== commentId))
})
+ setComments(addSubComment)
}
- function editComment(commentId) {
-
- apiRequest("/comment/update", {
- method: "PUT",
- data: {
- comment_id: commentId,
- text: commentsEditText[commentId]
+ 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)
}
- }).then((res) => {
- // createSubComment()
})
+ setComments([...deleteSubComment])
}
- // function createSubComment() {
- // apiRequest("/comment/create", {
- // method: "POST",
- // data: {
- // text: '12312312',
- // entity_type: 2,
- // entity_id: task.id,
- // parent_id: 36
- // }
- // }).then((res) => console.log(res))
- // }
-
function startTaskTimer() {
apiRequest("/timer/create", {
method: "POST",
@@ -159,7 +153,7 @@ export const ModalTiсket = ({
timer_id: timerInfo.id,
stopped_at: getCorrectRequestDate(new Date())
}
- }).then((res) => {
+ }).then(() => {
setTimerStart(false)
clearInterval(timerId)
})
@@ -185,7 +179,7 @@ export const ModalTiсket = ({
task_id: task.id,
executor_id: 0
},
- }).then((res) => {
+ }).then(() => {
setExecutor(null)
});
}
@@ -210,19 +204,24 @@ export const ModalTiсket = ({
task_id: task.id,
user_id: person.user_id
},
- }).then((res) => {
+ }).then(() => {
setMembers(members.filter((item) => item.user_id !== person.user_id))
});
}
useEffect(() => {
apiRequest(`/comment/get-by-entity?entity_type=2&entity_id=${task.id}`).then((res) => {
- setComments(res)
- res.forEach((item) => {
- setCommentsEditOpen((prevValue) => ({...prevValue, [item.id]: false}))
- setCommentsEditText((prevValue) => ({...prevValue, [item.id]: item.text}))
- setSubCommentsCreateOpen((prevValue) => ({...prevValue, [item.id]: false}))
- })
+ 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
@@ -347,45 +346,15 @@ export const ModalTiсket = ({
{comments.map((comment) => {
- return
-
-
-
})
-
{comment.user.fio}
-
-
-
{getCorrectDate(comment.created_at)}
-
-

{
- if (commentsEditOpen[comment.id]) {
- editComment(comment.id)
- }
- setCommentsEditOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]}))
- }} />
-
-

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

{
- setSubCommentsCreateOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]}))
- }}
- />
-
- :
-
{
- setSubCommentsCreateOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]}))
- }} className='comments__list__item__answer'>Ответить
- }
-
- })
-
+ return
+ })
}
diff --git a/src/components/UI/ModalTicket/ModalTicket.scss b/src/components/UI/ModalTicket/ModalTicket.scss
index a4436d78..cb71b885 100644
--- a/src/components/UI/ModalTicket/ModalTicket.scss
+++ b/src/components/UI/ModalTicket/ModalTicket.scss
@@ -81,6 +81,22 @@
flex-direction: column;
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;
@@ -89,6 +105,41 @@
border-radius: 44px;
font-size: 14px;
width: 100%;
+ 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;
@@ -163,6 +214,7 @@
padding: 3px 5px;
display: flex;
align-items: center;
+ margin-top: 5px;
img {
width: 20px;
diff --git a/src/components/UI/TicketFullScreen/TicketFullScreen.jsx b/src/components/UI/TicketFullScreen/TicketFullScreen.jsx
index d2adb881..0f0ad150 100644
--- a/src/components/UI/TicketFullScreen/TicketFullScreen.jsx
+++ b/src/components/UI/TicketFullScreen/TicketFullScreen.jsx
@@ -5,6 +5,7 @@ import { ProfileBreadcrumbs } from "../../ProfileBreadcrumbs/ProfileBreadcrumbs"
import { Footer } from "../../Footer/Footer";
import { Link, useParams, useNavigate } from "react-router-dom";
import TrackerModal from "../TrackerModal/TrackerModal";
+import TrackerTaskComment from "../../../components/TrackerTaskComment/TrackerTaskComment";
import { Navigation } from "../../Navigation/Navigation";
import {Loader} from "../../Loader/Loader";
@@ -33,12 +34,10 @@ import link from "../../../images/link.svg";
import archive2 from "../../../images/archive.svg";
import del from "../../../images/delete.svg";
import edit from "../../../images/edit.svg";
-import accept from "../../../images/accept.png"
import "./ticketFullScreen.scss";
import close from "../../../images/closeProjectPersons.svg";
import {getCorrectRequestDate, urlForLocal} from "../../../helper";
-import {getCorrectDate} from "../../Calendar/calendarHelper";
export const TicketFullScreen = ({}) => {
const [modalAddWorker, setModalAddWorker] = useState(false);
@@ -52,9 +51,6 @@ export const TicketFullScreen = ({}) => {
const [inputsValue, setInputsValue] = useState({});
const [loader, setLoader] = useState(true);
const [comments, setComments] = useState([]);
- const [commentsEditOpen, setCommentsEditOpen] = useState({})
- const [subCommentsCreateOpen, setSubCommentsCreateOpen] = useState({})
- const [commentsEditText, setCommentsEditText] = useState({})
const [personListOpen, setPersonListOpen] = useState(false)
const [timerStart, setTimerStart] = useState(false)
const [timerInfo, setTimerInfo] = useState({})
@@ -64,12 +60,17 @@ export const TicketFullScreen = ({}) => {
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}))
- setSubCommentsCreateOpen((prevValue) => ({...prevValue, [item.id]: false}))
- setCommentsEditText((prevValue) => ({...prevValue, [item.id]: item.text}))
- })
+ 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) {
@@ -102,7 +103,7 @@ export const TicketFullScreen = ({}) => {
title: inputsValue.title,
description: inputsValue.description
},
- }).then((res) => {
+ }).then(() => {
});
}
@@ -117,33 +118,9 @@ export const TicketFullScreen = ({}) => {
}).then((res) => {
let newComment = res
newComment.created_at = new Date()
+ newComment.subComments = []
setInputsValue((prevValue) => ({...prevValue, comment: ''}))
setComments((prevValue) => ([...prevValue, newComment]))
- setCommentsEditOpen((prevValue) => ({...prevValue, [res.id]: false}))
- setCommentsEditText((prevValue) => ({...prevValue, [res.id]: res.text}))
- })
- }
-
- function deleteComment(commentId) {
- apiRequest("/comment/update", {
- method: "PUT",
- data: {
- comment_id: commentId,
- status: 0
- }
- }).then((res) => {
- setComments((prevValue) => prevValue.filter((item) => item.id !== commentId))
- })
- }
-
- function editComment(commentId) {
- apiRequest("/comment/update", {
- method: "PUT",
- data: {
- comment_id: commentId,
- text: commentsEditText[commentId]
- }
- }).then((res) => {
})
}
@@ -168,7 +145,7 @@ export const TicketFullScreen = ({}) => {
timer_id: timerInfo.id,
stopped_at: getCorrectRequestDate(new Date())
}
- }).then((res) => setTimerStart(false))
+ }).then(() => setTimerStart(false))
}
function deletePerson(userId) {
@@ -183,6 +160,42 @@ export const TicketFullScreen = ({}) => {
});
}
+ 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));
};
@@ -341,43 +354,14 @@ export const TicketFullScreen = ({}) => {
{comments.map((comment) => {
- return
-
-
-
})
-
{comment.user.fio}
-
-
-
{getCorrectDate(comment.created_at)}
-
-

{
- if (commentsEditOpen[comment.id]) {
- editComment(comment.id)
- }
- setCommentsEditOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]}))
- }} />
-
-

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

{
- setSubCommentsCreateOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]}))
- }}
- />
-
- :
-
{
- setSubCommentsCreateOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]}))
- }} className='comments__list__item__answer'>Ответить
- }
-
+ return
})
}