import ClassicEditor from "@ckeditor/ckeditor5-build-classic"; import { CKEditor } from "@ckeditor/ckeditor5-react"; import ru from "date-fns/locale/ru"; import React, { useEffect, useState } from "react"; import DatePicker, { registerLocale } from "react-datepicker"; import { useDispatch, useSelector } from "react-redux"; import { Link, useNavigate, useParams } from "react-router-dom"; import { getProfileInfo } from "@redux/outstaffingSlice"; import { deletePersonOnProject, getBoarderLoader, modalToggle, setToggleTab, } from "@redux/projectsTrackerSlice"; import { backendImg, caseOfNum, getCorrectRequestDate, getToken, urlForLocal, } from "@utils/helper"; import { apiRequest } from "@api/request"; import { useNotification } from "@hooks/useNotification"; import { getCorrectDate } from "@components/Calendar/calendarHelper"; import { Footer } from "@components/Common/Footer/Footer"; import { Loader } from "@components/Common/Loader/Loader"; import AcceptModal from "@components/Modal/AcceptModal/AcceptModal"; import TrackerModal from "@components/Modal/Tracker/TrackerModal/TrackerModal"; import { Navigation } from "@components/Navigation/Navigation"; import { ProfileBreadcrumbs } from "@components/ProfileBreadcrumbs/ProfileBreadcrumbs"; import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader"; import TrackerTaskComment from "@components/TrackerTaskComment/TrackerTaskComment"; import arrow from "assets/icons/arrows/arrowCalendar.png"; import arrowStart from "assets/icons/arrows/arrowStart.png"; import calendarIcon from "assets/icons/calendar.svg"; import close from "assets/icons/close.png"; import fileDelete 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 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 archive from "assets/images/archiveIcon.png"; import avatarMok from "assets/images/avatarMok.png"; import "./ticketFullScreen.scss"; import arrowDown from "assets/icons/arrows/selectArrow.png"; registerLocale("ru", ru); export const TicketFullScreen = () => { const [modalAddWorker, setModalAddWorker] = useState(false); const ticketId = useParams(); const dispatch = useDispatch(); const navigate = useNavigate(); const boardLoader = useSelector(getBoarderLoader); const [projectInfo, setProjectInfo] = useState({}); const [taskInfo, setTaskInfo] = useState({}); const [editOpen, setEditOpen] = useState(false); const [inputsValue, setInputsValue] = useState({}); const [loader, setLoader] = useState(true); const [comments, setComments] = useState([]); const [personListOpen, setPersonListOpen] = useState(false); const [timerStart, setTimerStart] = useState(false); const [timerInfo, setTimerInfo] = useState({}); const [currentTimerCount, setCurrentTimerCount] = useState({ hours: 0, minute: 0, seconds: 0, }); const profileInfo = useSelector(getProfileInfo); const [timerId, setTimerId] = useState(null); const [dropListOpen, setDropListOpen] = useState(false); const [correctProjectUsers, setCorrectProjectUsers] = useState([]); const [dropListMembersOpen, setDropListMembersOpen] = useState(false); const [users, setUsers] = useState([]); const [deadLine, setDeadLine] = useState(""); const [datePickerOpen, setDatePickerOpen] = useState(false); const [startDate, setStartDate] = useState(null); const [uploadedFile, setUploadedFile] = useState(null); const [taskFiles, setTaskFiles] = useState([]); const [acceptModalOpen, setAcceptModalOpen] = useState(false); const [taskTags, setTaskTags] = useState([]); const [selectTagsOpen, setSelectTagsOpen] = useState(false); const [correctProjectTags, setCorrectProjectTags] = useState([]); const { showNotification } = useNotification(); useEffect(() => { apiRequest(`/task/get-task?task_id=${ticketId.id}&expand=mark`).then( (taskInfo) => { setTaskInfo(taskInfo); setDeadLine(taskInfo.dead_line); setStartDate( taskInfo.dead_line ? new Date(taskInfo.dead_line) : new Date() ); setInputsValue({ title: taskInfo.title, description: taskInfo.description, comment: "", }); setTaskTags(taskInfo.mark) 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); }); apiRequest( `/file/get-by-entity?entity_type=2&entity_id=${taskInfo.id}` ).then((res) => { if (Array.isArray(res)) { setTaskFiles(res); } }); apiRequest( `/timer/get-by-entity?entity_type=2&entity_id=${taskInfo.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, }); updateTimerHours = Math.floor(timerSeconds / 60 / 60); updateTimerMinute = Math.floor((timerSeconds / 60) % 60); updateTimerSec = timerSeconds % 60; if (!time.stopped_at) { setTimerStart(true); startTimer(); setTimerInfo(time); } }); }); apiRequest( `/project/get-project?project_id=${taskInfo.project_id}&expand=columns,mark` ).then((res) => { setProjectInfo(res); setCorrectProjectUsers(res.projectUsers); }); setLoader(boardLoader); } ); }, []); useEffect(() => { let tagIds = taskTags.map((tag) => tag.id); if (projectInfo.mark) { setCorrectProjectTags( projectInfo.mark.reduce((acc, cur) => { if (!tagIds.includes(cur.id)) acc.push(cur); return acc; }, []) ); } }, [taskTags, projectInfo]); function deleteTask() { apiRequest("/task/update-task", { method: "PUT", data: { task_id: ticketId.id, status: 0, }, }).then(() => { navigate(`/tracker/project/${taskInfo.project_id}`); }); } function archiveTask() { setAcceptModalOpen(true); } function editTask() { if (!inputsValue.title || !inputsValue.description) { return showNotification({ show: true, text: "Заполните поля", type: "error", }); } apiRequest("/task/update-task", { method: "PUT", data: { task_id: taskInfo.id, title: inputsValue.title, description: inputsValue.description, }, }).then(() => { showNotification({ show: true, text: "Изменения сохранены", type: "success", }); setEditOpen(!editOpen); }); } function createComment() { apiRequest("/comment/create", { method: "POST", data: { text: inputsValue.comment, entity_type: 2, entity_id: taskInfo.id, }, }).then((res) => { let newComment = res; newComment.created_at = new Date(); newComment.subComments = []; setInputsValue((prevValue) => ({ ...prevValue, comment: "" })); setComments((prevValue) => [...prevValue, newComment]); }); } 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); startTimer(); }); } function stopTaskTimer() { apiRequest("/timer/update", { method: "PUT", data: { timer_id: timerInfo.id, stopped_at: getCorrectRequestDate(new Date()), }, }).then(() => { setTimerStart(false); clearInterval(timerId); }); } function deletePerson(userId) { apiRequest("/project/del-user", { method: "DELETE", data: { project_id: projectInfo.id, user_id: userId, }, }).then(() => { 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)); }; function copyTicketLink() { navigator.clipboard.writeText( `https://itguild.info/tracker/task/${taskInfo.id}` ); } function startTimer() { setTimerId( setInterval(() => { run(); }, 1000) ); } useEffect(() => { if (taskInfo.taskUsers && projectInfo.projectUsers) { let ids = taskInfo.taskUsers.map((user) => user.user_id); setUsers( projectInfo.projectUsers.reduce((acc, cur) => { if (!ids.includes(cur.user_id)) acc.push(cur); return acc; }, []) ); } }, [taskInfo.taskUsers, projectInfo]); 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; } function deleteTaskExecutor() { apiRequest("/task/update-task", { method: "PUT", data: { task_id: taskInfo.id, executor_id: 0, }, }).then(() => { setTaskInfo((prevState) => ({ ...prevState, executor_id: null, executor: null, })); }); } function taskExecutor(person) { apiRequest("/task/update-task", { method: "PUT", data: { task_id: taskInfo.id, executor_id: person.user_id, }, }).then((res) => { setDropListOpen(false); setTaskInfo((prevState) => ({ ...prevState, executor_id: res.executor_id, executor: res.executor, })); }); } function deleteMember(person) { apiRequest("/task/del-user", { method: "DELETE", data: { task_id: taskInfo.id, user_id: person.user_id, }, }).then(() => { setTaskInfo((prevState) => ({ ...prevState, taskUsers: taskInfo.taskUsers.filter( (item) => item.user_id !== person.user_id ), })); }); } function addMember(person) { apiRequest("/task/add-user-to-task", { method: "POST", data: { task_id: taskInfo.id, user_id: person.user_id, }, }).then((res) => { setDropListMembersOpen(false); setTaskInfo((prevValue) => ({ ...prevValue, taskUsers: [...prevValue.taskUsers, res], })); }); } function selectDeadLine(date) { apiRequest("/task/update-task", { method: "PUT", data: { task_id: taskInfo.id, dead_line: getCorrectRequestDate(date), }, }).then(() => {}); } async function handleUpload(event) { const formData = new FormData(); formData.append("uploadFile", event.target.files[0]); const res = await fetch("https://itguild.info/api/file/upload", { method: "POST", body: formData, headers: { ...getToken() }, }); const data = await res.json(); setUploadedFile(data); } function attachFile() { apiRequest("/file/attach", { method: "POST", data: { file_id: uploadedFile[0].id, entity_type: 2, entity_id: taskInfo.id, status: 1, }, }).then((res) => { setTaskFiles((prevValue) => [...prevValue, res]); setUploadedFile(null); }); } function deleteLoadedFile() { setUploadedFile(null); } function deleteFile(file) { apiRequest("/file/detach", { method: "DELETE", data: { file_id: file.id, entity_type: 2, entity_id: taskInfo.id, status: 0, }, }).then(() => { setTaskFiles((prevValue) => prevValue.filter((item) => item.id !== file.id) ); }); } function closeAcceptModal() { setAcceptModalOpen(false); } function deleteTagFromTask(tagId) { apiRequest("/mark/detach", { method: "DELETE", data: { mark_id: tagId, entity_type: 2, entity_id: taskInfo.id, }, }).then(() => { setTaskTags((prevValue) => prevValue.filter((tag) => tag.id !== tagId)); }); } function addTagToTask(tagId) { apiRequest("/mark/attach", { method: "POST", data: { mark_id: tagId, entity_type: 2, entity_id: taskInfo.id, }, }).then((data) => { setSelectTagsOpen(false); setTaskTags((prevValue) => [...prevValue, data.mark]); }); } return (

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

toggleTabs(1)} > img

Проекты

toggleTabs(2)} > img

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

toggleTabs(3)} > img

Архив

{loader ? ( ) : ( <>
Проект : {projectInfo.name}
{projectInfo.projectUsers?.length && projectInfo.projectUsers.slice(0, 3).map((person) => { return ( avatar ); })}
{projectInfo.projectUsers?.length > 3 && ( +1 )} { setPersonListOpen(true); }} > +

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

{personListOpen && (
close setPersonListOpen(false)} />
{projectInfo.projectUsers?.length} участник
В проекте -

“{projectInfo.name}”

{projectInfo.projectUsers?.map((person) => { return (
avatar {person.user.fio} delete deletePerson(person.user_id)} />
); })}
{ dispatch(modalToggle("addWorker")); setModalAddWorker(true); setPersonListOpen(false); }} > +

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

)}

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

arrow
{editOpen ? ( { setInputsValue((prevValue) => ({ ...prevValue, title: e.target.value, })); }} /> ) : (
{inputsValue.title}
)}
{editOpen ? ( { const data = editor.getData(); setInputsValue((prevValue) => ({ ...prevValue, description: data, })); }} /> ) : (

)}

{Boolean(taskFiles.length) && (
{taskFiles.map((file) => { return (
img
deleteFile(file)} > delete
); })}
)} {uploadedFile && (
{uploadedFile.map((file) => { return (
img
deleteLoadedFile(file)} > delete
); })}
)}
{/*

*/} {/* {*/} {/* dispatch(modalToggle("addSubtask"));*/} {/* setModalAddWorker(true);*/} {/* }}*/} {/* styles={"button-green-add"}*/} {/* >*/} {/* */} {/* Добавить под задачу*/} {/* */} {/*

*/}
{taskFiles.length ? taskFiles.length : 0} {caseOfNum(taskFiles.length, "files")}
{ setInputsValue((prevValue) => ({ ...prevValue, comment: e.target.value, })); }} /> send
{comments.map((comment) => { return ( ); })}

Создатель :

 {taskInfo.user?.fio}

{taskInfo.executor ? (

Исполнитель: {taskInfo.executor.fio}

avatar deleteTaskExecutor()} />
) : (
Добавить исполнителя {dropListOpen && (
setDropListOpen(false)} /> {correctProjectUsers.map((person) => { return (
taskExecutor(person)} > {person.user.fio} avatar
); })}
)}
)} {Boolean(taskInfo.taskUsers.length) && (

Участники:

{taskInfo.taskUsers.map((member) => { return (

{member.fio}

avatar deleteMember(member)} />
); })}
)}
Добавить участников {dropListMembersOpen && (
setDropListMembersOpen(false)} /> {users.length ? ( users.map((person) => { return (
addMember(person)} > {person.user.fio} avatar
); }) ) : (

Нет пользователей

)}
)}
setDatePickerOpen(!datePickerOpen)} > calendar {deadLine ? getCorrectDate(deadLine) : "Срок исполнения:"}
{ setDatePickerOpen(false); setStartDate(date); setDeadLine(date); selectDeadLine(date); }} />
Длительность :

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

{timerStart ? ( ) : ( )}
{taskTags.map((tag) => { return (

{tag.slug}

delete deleteTagFromTask(tag.id)} />
); })}
setSelectTagsOpen(!selectTagsOpen)} > Выберите тег arrow
{selectTagsOpen && (
setSelectTagsOpen(false)} className="tags__dropDown__close" src={close} alt="close" /> {correctProjectTags.map((tag) => { return (
addTagToTask(tag.id)} >

{tag.slug}

); })} {!Boolean(correctProjectTags.length) && (

Нет тегов

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

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

link

ссылка на задачу

arch

в архив

delete

удалить

)}
{acceptModalOpen && ( )}
); }; export default TicketFullScreen;