From c55a697f6b1944314b44bafeb04a108eca50f813 Mon Sep 17 00:00:00 2001 From: M1kola Date: Tue, 30 May 2023 03:32:16 +0300 Subject: [PATCH] timer with comments --- src/components/UI/ModalTicket/ModalTicket.jsx | 163 ++++++++++++++++-- .../UI/ModalTicket/ModalTicket.scss | 92 ++++++++-- .../UI/TicketFullScreen/TicketFullScreen.jsx | 92 ++++++++-- src/helper.js | 11 ++ src/images/accept.png | Bin 0 -> 389 bytes 5 files changed, 316 insertions(+), 42 deletions(-) create mode 100644 src/images/accept.png diff --git a/src/components/UI/ModalTicket/ModalTicket.jsx b/src/components/UI/ModalTicket/ModalTicket.jsx index e2e3fe72..bcc76ebf 100644 --- a/src/components/UI/ModalTicket/ModalTicket.jsx +++ b/src/components/UI/ModalTicket/ModalTicket.jsx @@ -24,7 +24,8 @@ import fullScreen from "../../../images/inFullScreen.svg"; import close from "../../../images/closeProjectPersons.svg"; import "./ModalTicket.scss"; -import {urlForLocal} from "../../../helper"; +import {urlForLocal, getCorrectRequestDate} from "../../../helper"; +import accept from "../../../images/accept.png"; export const ModalTiсket = ({ active, @@ -41,11 +42,20 @@ export const ModalTiсket = ({ 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) const [members, setMembers] = useState(task.taskUsers) const [users, setUsers] = useState([]) + const [timerStart, setTimerStart] = useState(false) + const [timerInfo, setTimerInfo] = useState({}) + const [currentTimerCount, setCurrentTimerCount] = useState({ + hours: 0, + minute: 0, + seconds: 0 + }) + const [timerId, setTimerId] = useState(null) function deleteTask() { apiRequest("/task/update-task", { @@ -111,6 +121,47 @@ export const ModalTiсket = ({ text: commentsEditText[commentId] } }).then((res) => { + // createSubComment() + }) + } + + // 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", + data: { + entity_type: 2, + entity_id: task.id, + created_at: getCorrectRequestDate(new Date()) + } + }).then((res) => { + setTimerStart(true) + setTimerInfo(res) + startTimer() + }) + } + + function stopTaskTimer() { + apiRequest("/timer/update", { + method: "PUT", + data: { + timer_id: timerInfo.id, + stopped_at: getCorrectRequestDate(new Date()) + } + }).then((res) => { + setTimerStart(false) + clearInterval(timerId) }) } @@ -170,10 +221,62 @@ export const ModalTiсket = ({ res.forEach((item) => { setCommentsEditOpen((prevValue) => ({...prevValue, [item.id]: false})) setCommentsEditText((prevValue) => ({...prevValue, [item.id]: item.text})) + setSubCommentsCreateOpen((prevValue) => ({...prevValue, [item.id]: false})) + }) + }) + apiRequest(`/timer/get-by-entity?entity_type=2&entity_id=${task.id}`).then((res) => { + let timerSeconds = 0 + 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 (!time.stopped_at) { + setTimerStart(true) + startTimer() + setTimerInfo(time) + } }) }) }, []) + function startTimer () { + setTimerId(setInterval(() => { + run() + }, 1000)) + } + + let updateTimerSec = currentTimerCount.seconds, updateTimerMinute = currentTimerCount.minute, updateTimerHours = currentTimerCount.hours + + function run () { + updateTimerSec++ + if (updateTimerSec > 60) { + updateTimerMinute++ + updateTimerSec = 0 + } + if (updateTimerMinute === 60) { + updateTimerMinute = 0 + updateTimerHours++ + } + + return setCurrentTimerCount({ + hours: updateTimerHours, + minute: updateTimerMinute, + seconds: updateTimerSec + }) + } + + function correctTimerTime (time) { + if (time < 10) return `0${time}` + if (time > 10) return time + } + + useEffect(() => { let ids = members.map((user) => user.user_id) setUsers(projectUsers.reduce((acc, cur) => { @@ -246,20 +349,40 @@ export const ModalTiсket = ({ {comments.map((comment) => { return
- {getCorrectDate(comment.created_at)} -
- edit { - if (commentsEditOpen[comment.id]) { - editComment(comment.id) - } - setCommentsEditOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]})) - }} /> +
+ avatar +

{comment.user.fio}

+
+
+ {getCorrectDate(comment.created_at)} +
+ edit { + if (commentsEditOpen[comment.id]) { + editComment(comment.id) + } + setCommentsEditOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]})) + }} /> +
+ delete deleteComment(comment.id)} />
- delete deleteComment(comment.id)} />
- {commentsEditOpen[comment.id] ? { + {commentsEditOpen[comment.id] ? { setCommentsEditText((prevValue) => ({...prevValue, [comment.id]: e.target.value})) - }} /> :

{commentsEditText[comment.id]}

} + }} /> :

{commentsEditText[comment.id]}

} + {subCommentsCreateOpen[comment.id] ? +
+ + accept { + setSubCommentsCreateOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]})) + }} + /> +
+ : + { + setSubCommentsCreateOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]})) + }} className='comments__list__item__answer'>Ответить + }
}) @@ -335,12 +458,20 @@ export const ModalTiсket = ({
Длительность : -

{"0:00:00"}

+

+ {correctTimerTime(currentTimerCount.hours)}:{correctTimerTime(currentTimerCount.minute)}:{correctTimerTime(currentTimerCount.seconds)} +

- + {timerStart ? + + : + + }
diff --git a/src/components/UI/ModalTicket/ModalTicket.scss b/src/components/UI/ModalTicket/ModalTicket.scss index aa2ddbf2..a4436d78 100644 --- a/src/components/UI/ModalTicket/ModalTicket.scss +++ b/src/components/UI/ModalTicket/ModalTicket.scss @@ -79,22 +79,60 @@ .comments__list { display: flex; flex-direction: column; - row-gap: 10px; + max-height: 420px; + overflow: auto; &__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; + + &__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; @@ -107,10 +145,35 @@ .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; + + img { + width: 20px; + height: 20px; + cursor: pointer; + } + + input { + width: 90%; + border: none; + } } } } @@ -315,14 +378,23 @@ color: white; background: #1458dd; border-radius: 44px; - opacity: 0.5; - pointer-events: none; img { margin-left: 10px; } } + .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/UI/TicketFullScreen/TicketFullScreen.jsx b/src/components/UI/TicketFullScreen/TicketFullScreen.jsx index 6be108e7..d2adb881 100644 --- a/src/components/UI/TicketFullScreen/TicketFullScreen.jsx +++ b/src/components/UI/TicketFullScreen/TicketFullScreen.jsx @@ -22,7 +22,6 @@ import { apiRequest } from "../../../api/request"; import project from "../../../images/trackerProject.svg"; import watch from "../../../images/watch.png"; import file from "../../../images/fileModal.svg"; -import task from "../../../images/tasksMock.png"; import send from "../../../images/send.svg"; import arrow2 from "../../../images/arrowStart.png"; import plus from "../../../images/plus.svg"; @@ -34,10 +33,11 @@ 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 {urlForLocal} from "../../../helper"; +import {getCorrectRequestDate, urlForLocal} from "../../../helper"; import {getCorrectDate} from "../../Calendar/calendarHelper"; export const TicketFullScreen = ({}) => { @@ -53,8 +53,11 @@ export const TicketFullScreen = ({}) => { 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({}) useEffect(() => { apiRequest(`/task/get-task?task_id=${ticketId.id}`).then((taskInfo) => { @@ -64,9 +67,16 @@ export const TicketFullScreen = ({}) => { setComments(res) res.forEach((item) => { setCommentsEditOpen((prevValue) => ({...prevValue, [item.id]: false})) + setSubCommentsCreateOpen((prevValue) => ({...prevValue, [item.id]: false})) setCommentsEditText((prevValue) => ({...prevValue, [item.id]: item.text})) }) }) + taskInfo.timers.forEach((time) => { + if (!time.stopped_at) { + setTimerStart(true) + setTimerInfo(time) + } + }) dispatch(setProjectBoardFetch(taskInfo.project_id)); setLoader(boardLoader) }); @@ -137,6 +147,30 @@ export const TicketFullScreen = ({}) => { }) } + function startTaskTimer() { + apiRequest("/timer/create", { + method: "POST", + data: { + entity_type: 2, + entity_id: taskInfo.id, + created_at: getCorrectRequestDate(new Date()) + } + }).then((res) => { + setTimerStart(true) + setTimerInfo(res) + }) + } + + function stopTaskTimer() { + apiRequest("/timer/update", { + method: "PUT", + data: { + timer_id: timerInfo.id, + stopped_at: getCorrectRequestDate(new Date()) + } + }).then((res) => setTimerStart(false)) + } + function deletePerson(userId) { apiRequest("/project/del-user", { method: "DELETE", @@ -309,20 +343,40 @@ export const TicketFullScreen = ({}) => { {comments.map((comment) => { return
- {getCorrectDate(comment.created_at)} -
- edit { - if (commentsEditOpen[comment.id]) { - editComment(comment.id) - } - setCommentsEditOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]})) - }} /> +
+ avatar +

{comment.user.fio}

+
+
+ {getCorrectDate(comment.created_at)} +
+ edit { + if (commentsEditOpen[comment.id]) { + editComment(comment.id) + } + setCommentsEditOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]})) + }} /> +
+ delete deleteComment(comment.id)} />
- delete deleteComment(comment.id)} />
- {commentsEditOpen[comment.id] ? { + {commentsEditOpen[comment.id] ? { setCommentsEditText((prevValue) => ({...prevValue, [comment.id]: e.target.value})) - }} /> :

{commentsEditText[comment.id]}

} + }} /> :

{commentsEditText[comment.id]}

} + {subCommentsCreateOpen[comment.id] ? +
+ + accept { + setSubCommentsCreateOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]})) + }} + /> +
+ : + { + setSubCommentsCreateOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]})) + }} className='comments__list__item__answer'>Ответить + }
}) @@ -378,9 +432,15 @@ export const TicketFullScreen = ({}) => {

{"0:00:00"}

- + {timerStart ? + + : + + }
diff --git a/src/helper.js b/src/helper.js index 5e5b9993..ae8b66a1 100644 --- a/src/helper.js +++ b/src/helper.js @@ -51,3 +51,14 @@ export function scrollToForm() { behavior: "smooth", }); } + +export function getCorrectRequestDate(date) { + const yyyy = String(date.getUTCFullYear()) + const mm = String(date.getUTCMonth() + 1).padStart(2, "0"); + const dd = String(date.getUTCDate()).padStart(2, "0"); + const hh = String(date.getUTCHours()) + const min = String(date.getUTCMinutes()) + const sec = String(date.getUTCSeconds()) + return `${yyyy}-${mm}-${dd} ${hh}:${min}:${sec}` +} + diff --git a/src/images/accept.png b/src/images/accept.png new file mode 100644 index 0000000000000000000000000000000000000000..43966e45465aea9de26a828bf8b58c87d22daf13 GIT binary patch literal 389 zcmV;00eb$4P)Sz&SA-Ii`!n*`nma@oV?d1u0ASYrSH0000$lJtlDO;WzLDn}+a{J?LJ z%9w(DIh9Ykq+^p)<(=}RkpEr$!B>1}a;iL4mQ%jBH+IXUjE8(AJSravkIF{^m5&7~ z--TlCpuodoE-@>aD&?+aJeaKF{cRf_IF