1013 lines
35 KiB
React
Raw Normal View History

2023-06-29 02:27:08 +03:00
import ClassicEditor from "@ckeditor/ckeditor5-build-classic";
import { CKEditor } from "@ckeditor/ckeditor5-react";
2023-07-07 17:38:31 +03:00
import ru from "date-fns/locale/ru";
2023-05-04 18:38:56 +03:00
import React, { useEffect, useState } from "react";
2023-07-07 17:38:31 +03:00
import DatePicker, { registerLocale } from "react-datepicker";
2023-06-22 14:53:35 +03:00
import { useDispatch, useSelector } from "react-redux";
import { Link, useNavigate, useParams } from "react-router-dom";
2023-05-30 10:10:34 +03:00
2023-05-23 23:02:39 +03:00
import {
deletePersonOnProject,
2023-06-22 14:53:35 +03:00
getBoarderLoader,
2023-07-07 17:38:31 +03:00
modalToggle,
2023-06-29 03:41:59 +03:00
setToggleTab,
2023-06-22 14:53:35 +03:00
} from "@redux/projectsTrackerSlice";
2023-05-31 08:36:15 +03:00
2023-07-13 15:49:34 +03:00
import {
backendImg,
caseOfNum,
getCorrectRequestDate,
getToken,
urlForLocal,
} from "@utils/helper";
2023-04-20 20:10:08 +03:00
2023-06-22 14:53:35 +03:00
import { apiRequest } from "@api/request";
2023-07-07 17:38:31 +03:00
import { getCorrectDate } from "@components/Calendar/calendarHelper";
2023-06-22 14:53:35 +03:00
import { Footer } from "@components/Common/Footer/Footer";
import { Loader } from "@components/Common/Loader/Loader";
2023-07-14 03:03:49 +03:00
import AcceptModal from "@components/Modal/AcceptModal/AcceptModal";
2023-06-22 19:18:41 +03:00
import TrackerModal from "@components/Modal/Tracker/TrackerModal/TrackerModal";
2023-06-22 14:53:35 +03:00
import { Navigation } from "@components/Navigation/Navigation";
import { ProfileBreadcrumbs } from "@components/ProfileBreadcrumbs/ProfileBreadcrumbs";
import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader";
import TrackerTaskComment from "@components/TrackerTaskComment/TrackerTaskComment";
2023-04-20 20:10:08 +03:00
2023-06-22 14:53:35 +03:00
import arrow from "assets/icons/arrows/arrowCalendar.png";
2023-06-29 02:26:49 +03:00
import arrowStart from "assets/icons/arrows/arrowStart.png";
2023-07-07 17:38:31 +03:00
import calendarIcon from "assets/icons/calendar.svg";
2023-06-22 14:53:35 +03:00
import close from "assets/icons/close.png";
2023-07-13 15:49:07 +03:00
import fileDelete from "assets/icons/closeProjectPersons.svg";
2023-06-22 14:53:35 +03:00
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";
2023-07-07 00:46:58 +03:00
import archive from "assets/images/archiveIcon.png";
2023-06-29 02:27:08 +03:00
import avatarMok from "assets/images/avatarMok.png";
2023-06-12 23:30:18 +03:00
2023-06-22 14:53:35 +03:00
import "./ticketFullScreen.scss";
2023-07-07 17:38:31 +03:00
registerLocale("ru", ru);
2023-06-22 14:53:35 +03:00
export const TicketFullScreen = () => {
2023-04-20 20:10:08 +03:00
const [modalAddWorker, setModalAddWorker] = useState(false);
2023-05-04 18:38:56 +03:00
const ticketId = useParams();
2023-05-02 18:51:19 +03:00
const dispatch = useDispatch();
2023-05-03 20:01:23 +03:00
const navigate = useNavigate();
2023-05-23 23:02:39 +03:00
const boardLoader = useSelector(getBoarderLoader);
2023-06-29 03:41:59 +03:00
const [projectInfo, setProjectInfo] = useState({});
2023-05-04 18:38:56 +03:00
const [taskInfo, setTaskInfo] = useState({});
2023-05-16 00:24:52 +03:00
const [editOpen, setEditOpen] = useState(false);
2023-05-17 23:18:46 +03:00
const [inputsValue, setInputsValue] = useState({});
const [loader, setLoader] = useState(true);
const [comments, setComments] = useState([]);
2023-06-22 14:53:35 +03:00
const [personListOpen, setPersonListOpen] = useState(false);
const [timerStart, setTimerStart] = useState(false);
const [timerInfo, setTimerInfo] = useState({});
2023-06-29 02:26:49 +03:00
const [currentTimerCount, setCurrentTimerCount] = useState({
hours: 0,
minute: 0,
seconds: 0,
});
const [timerId, setTimerId] = useState(null);
2023-06-29 03:41:18 +03:00
const [dropListOpen, setDropListOpen] = useState(false);
const [correctProjectUsers, setCorrectProjectUsers] = useState([]);
const [dropListMembersOpen, setDropListMembersOpen] = useState(false);
const [users, setUsers] = useState([]);
2023-07-07 17:38:31 +03:00
const [deadLine, setDeadLine] = useState("");
2023-07-07 17:38:19 +03:00
const [datePickerOpen, setDatePickerOpen] = useState(false);
const [startDate, setStartDate] = useState(null);
2023-07-13 15:49:07 +03:00
const [uploadedFile, setUploadedFile] = useState(null);
2023-07-13 15:49:34 +03:00
const [taskFiles, setTaskFiles] = useState([]);
2023-07-14 03:03:49 +03:00
const [acceptModalOpen, setAcceptModalOpen] = useState(false);
2023-04-20 20:10:08 +03:00
2023-05-03 20:01:23 +03:00
useEffect(() => {
apiRequest(`/task/get-task?task_id=${ticketId.id}`).then((taskInfo) => {
2023-05-04 18:38:56 +03:00
setTaskInfo(taskInfo);
2023-07-07 17:38:31 +03:00
setDeadLine(taskInfo.dead_line);
setStartDate(
taskInfo.dead_line ? new Date(taskInfo.dead_line) : new Date()
);
2023-06-22 14:53:35 +03:00
setInputsValue({
title: taskInfo.title,
description: taskInfo.description,
comment: "",
});
apiRequest(
`/comment/get-by-entity?entity_type=2&entity_id=${taskInfo.id}`
).then((res) => {
2023-06-12 23:30:18 +03:00
const comments = res.reduce((acc, cur) => {
if (!cur.parent_id) {
2023-06-22 14:53:35 +03:00
acc.push({ ...cur, subComments: [] });
2023-06-12 23:30:18 +03:00
} else {
acc.forEach((item) => {
2023-06-22 14:53:35 +03:00
if (item.id === cur.parent_id) item.subComments.push(cur);
});
2023-06-12 23:30:18 +03:00
}
2023-06-22 14:53:35 +03:00
return acc;
}, []);
setComments(comments);
});
2023-07-13 15:49:34 +03:00
apiRequest(
`/file/get-by-entity?entity_type=2&entity_id=${taskInfo.id}`
).then((res) => {
2023-07-13 15:49:07 +03:00
if (Array.isArray(res)) {
2023-07-13 15:49:34 +03:00
setTaskFiles(res);
2023-07-13 15:49:07 +03:00
}
2023-07-13 15:49:34 +03:00
});
2023-06-29 02:27:08 +03:00
apiRequest(
`/timer/get-by-entity?entity_type=2&entity_id=${taskInfo.id}`
).then((res) => {
let timerSeconds = 0;
res.length &&
2023-06-29 02:26:49 +03:00
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);
}
});
2023-06-29 02:27:08 +03:00
});
2023-06-29 03:41:59 +03:00
apiRequest(
`/project/get-project?project_id=${taskInfo.project_id}&expand=columns`
).then((res) => {
setProjectInfo(res);
setCorrectProjectUsers(res.projectUsers);
});
2023-06-22 14:53:35 +03:00
setLoader(boardLoader);
2023-05-04 18:38:56 +03:00
});
}, []);
2023-05-03 20:01:23 +03:00
function deleteTask() {
apiRequest("/task/update-task", {
method: "PUT",
data: {
task_id: ticketId.id,
status: 0,
},
2023-05-31 11:24:46 +03:00
}).then(() => {
2023-05-04 18:38:56 +03:00
navigate(`/tracker/project/${taskInfo.project_id}`);
2023-05-03 20:01:23 +03:00
});
}
2023-04-20 20:10:08 +03:00
2023-07-14 03:03:49 +03:00
function archiveTask() {
setAcceptModalOpen(true);
2023-07-14 03:03:33 +03:00
}
2023-05-16 00:24:52 +03:00
function editTask() {
apiRequest("/task/update-task", {
method: "PUT",
data: {
task_id: taskInfo.id,
title: inputsValue.title,
2023-06-22 14:53:35 +03:00
description: inputsValue.description,
2023-05-16 00:24:52 +03:00
},
2023-06-22 14:53:35 +03:00
}).then(() => {});
2023-05-16 00:24:52 +03:00
}
2023-05-23 23:02:39 +03:00
function createComment() {
2023-05-17 23:18:46 +03:00
apiRequest("/comment/create", {
method: "POST",
data: {
text: inputsValue.comment,
entity_type: 2,
2023-06-22 14:53:35 +03:00
entity_id: taskInfo.id,
},
2023-05-17 23:18:46 +03:00
}).then((res) => {
2023-06-22 14:53:35 +03:00
let newComment = res;
newComment.created_at = new Date();
newComment.subComments = [];
setInputsValue((prevValue) => ({ ...prevValue, comment: "" }));
setComments((prevValue) => [...prevValue, newComment]);
});
2023-05-17 23:18:46 +03:00
}
2023-06-12 23:30:18 +03:00
function startTaskTimer() {
apiRequest("/timer/create", {
method: "POST",
2023-05-23 23:02:39 +03:00
data: {
2023-06-12 23:30:18 +03:00
entity_type: 2,
entity_id: taskInfo.id,
2023-06-22 14:53:35 +03:00
created_at: getCorrectRequestDate(new Date()),
},
2023-06-12 23:30:18 +03:00
}).then((res) => {
2023-06-22 14:53:35 +03:00
setTimerStart(true);
setTimerInfo(res);
2023-06-29 02:26:49 +03:00
startTimer();
2023-06-22 14:53:35 +03:00
});
2023-05-23 23:02:39 +03:00
}
2023-06-12 23:30:18 +03:00
function stopTaskTimer() {
apiRequest("/timer/update", {
2023-05-23 23:02:39 +03:00
method: "PUT",
data: {
2023-06-12 23:30:18 +03:00
timer_id: timerInfo.id,
2023-06-22 14:53:35 +03:00
stopped_at: getCorrectRequestDate(new Date()),
},
2023-06-29 02:26:49 +03:00
}).then(() => {
setTimerStart(false);
clearInterval(timerId);
});
2023-05-23 23:02:39 +03:00
}
function deletePerson(userId) {
apiRequest("/project/del-user", {
method: "DELETE",
data: {
2023-06-29 03:41:18 +03:00
project_id: projectInfo.id,
2023-06-22 14:53:35 +03:00
user_id: userId,
2023-05-23 23:02:39 +03:00
},
2023-05-31 11:24:46 +03:00
}).then(() => {
2023-06-22 14:53:35 +03:00
dispatch(deletePersonOnProject(userId));
2023-05-23 23:02:39 +03:00
});
}
2023-06-12 23:30:18 +03:00
function commentDelete(comment) {
2023-06-22 14:53:35 +03:00
setComments((prevValue) =>
prevValue.filter((item) => item.id !== comment.id)
);
2023-06-12 23:30:18 +03:00
if (comment.subComments.length) {
comment.subComments.forEach((subComment) => {
apiRequest("/comment/update", {
method: "PUT",
data: {
comment_id: subComment.id,
2023-06-22 14:53:35 +03:00
status: 0,
},
}).then(() => {});
});
2023-06-12 23:30:18 +03:00
}
}
function addSubComment(commentId, subComment) {
2023-06-22 14:53:35 +03:00
const addSubComment = comments;
2023-06-12 23:30:18 +03:00
addSubComment.forEach((comment) => {
if (comment.id === commentId) {
2023-06-22 14:53:35 +03:00
comment.subComments.push(subComment);
2023-06-12 23:30:18 +03:00
}
2023-06-22 14:53:35 +03:00
});
setComments(addSubComment);
2023-06-12 23:30:18 +03:00
}
function subCommentDelete(subComment) {
2023-06-22 14:53:35 +03:00
const deleteSubComment = comments;
2023-06-12 23:30:18 +03:00
deleteSubComment.forEach((comment, index) => {
if (comment.id === subComment.parent_id) {
2023-06-22 14:53:35 +03:00
deleteSubComment[index].subComments = comment.subComments.filter(
(item) => item.id !== subComment.id
);
2023-06-12 23:30:18 +03:00
}
2023-06-22 14:53:35 +03:00
});
setComments([...deleteSubComment]);
2023-06-12 23:30:18 +03:00
}
2023-04-20 20:10:08 +03:00
const toggleTabs = (index) => {
2023-05-02 18:51:19 +03:00
dispatch(setToggleTab(index));
2023-04-20 20:10:08 +03:00
};
function copyTicketLink() {
navigator.clipboard.writeText(
`https://itguild.info/tracker/task/${taskInfo.id}`
);
}
2023-06-29 02:26:49 +03:00
function startTimer() {
setTimerId(
setInterval(() => {
run();
}, 1000)
);
}
2023-06-29 03:41:18 +03:00
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]);
2023-06-29 02:26:49 +03:00
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;
}
2023-06-29 03:41:18 +03:00
function deleteTaskExecutor() {
apiRequest("/task/update-task", {
method: "PUT",
data: {
task_id: taskInfo.id,
executor_id: 0,
},
}).then(() => {
setTaskInfo((prevState) => ({
...prevState,
executor_id: null,
2023-06-29 03:41:59 +03:00
executor: null,
}));
2023-06-29 03:41:18 +03:00
});
}
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,
2023-06-29 03:41:59 +03:00
executor: res.executor,
}));
2023-06-29 03:41:18 +03:00
});
}
function deleteMember(person) {
apiRequest("/task/del-user", {
method: "DELETE",
data: {
task_id: taskInfo.id,
user_id: person.user_id,
},
}).then(() => {
setTaskInfo((prevState) => ({
...prevState,
2023-06-29 03:41:59 +03:00
taskUsers: taskInfo.taskUsers.filter(
(item) => item.user_id !== person.user_id
),
}));
2023-06-29 03:41:18 +03:00
});
}
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,
2023-06-29 03:41:59 +03:00
taskUsers: [...prevValue.taskUsers, res],
2023-06-29 03:41:18 +03:00
}));
});
}
2023-07-07 17:38:19 +03:00
function selectDeadLine(date) {
apiRequest("/task/update-task", {
method: "PUT",
data: {
task_id: taskInfo.id,
2023-07-07 17:38:31 +03:00
dead_line: getCorrectRequestDate(date),
2023-07-07 17:38:19 +03:00
},
2023-07-07 17:38:31 +03:00
}).then(() => {});
2023-07-07 17:38:19 +03:00
}
2023-07-13 15:49:07 +03:00
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,
2023-07-13 15:49:34 +03:00
status: 1,
},
2023-07-13 15:49:07 +03:00
}).then((res) => {
2023-07-13 15:49:34 +03:00
setTaskFiles((prevValue) => [...prevValue, res]);
setUploadedFile(null);
});
2023-07-13 15:49:07 +03:00
}
function deleteLoadedFile() {
2023-07-13 15:49:34 +03:00
setUploadedFile(null);
2023-07-13 15:49:07 +03:00
}
function deleteFile(file) {
apiRequest("/file/detach", {
method: "DELETE",
data: {
file_id: file.id,
entity_type: 2,
entity_id: taskInfo.id,
2023-07-13 15:49:34 +03:00
status: 0,
},
2023-07-13 15:49:07 +03:00
}).then(() => {
2023-07-13 15:49:34 +03:00
setTaskFiles((prevValue) =>
prevValue.filter((item) => item.id !== file.id)
);
});
2023-07-13 15:49:07 +03:00
}
2023-07-14 03:03:49 +03:00
function closeAcceptModal() {
setAcceptModalOpen(false);
2023-07-14 03:03:33 +03:00
}
2023-04-20 20:10:08 +03:00
return (
2023-06-22 14:53:35 +03:00
<section className="ticket-full-screen">
<ProfileHeader />
<Navigation />
<div className="container">
<div className="tracker__content">
<ProfileBreadcrumbs
links={[
{ name: "Главная", link: "/profile" },
{ name: "Трекер", link: "/profile/tracker" },
]}
/>
<h2 className="tracker__title">Управление проектами с трекером</h2>
2023-04-20 20:10:08 +03:00
</div>
2023-06-22 14:53:35 +03:00
</div>
<div className="tracker__tabs">
<div className="tracker__tabs__head">
<Link
to="/profile/tracker"
2023-08-07 15:52:58 +03:00
className="tab active-tab projectsTab"
2023-06-22 14:53:35 +03:00
onClick={() => toggleTabs(1)}
>
<img src={project} alt="img" />
<p>Проекты </p>
</Link>
<Link
to="/profile/tracker"
2023-08-07 15:52:58 +03:00
className="tab tasksTab"
2023-06-22 14:53:35 +03:00
onClick={() => toggleTabs(2)}
>
<img src={tasks} alt="img" />
<p>Все мои задачи</p>
</Link>
<Link
to="/profile/tracker"
2023-08-07 15:52:58 +03:00
className="tab archiveTab"
2023-06-22 14:53:35 +03:00
onClick={() => toggleTabs(3)}
>
<img src={archive} alt="img" />
<p>Архив</p>
</Link>
</div>
{loader ? (
<Loader />
) : (
<>
<div className="tracker__tabs__content content-tabs">
<div className="tasks__head">
2023-07-07 00:46:40 +03:00
<div className="tasks__head__wrapper tasks__head__wrapper__fullScreen">
2023-06-29 03:41:18 +03:00
<h5>Проект : {projectInfo.name}</h5>
2023-04-20 20:10:08 +03:00
2023-06-22 14:53:35 +03:00
<TrackerModal
active={modalAddWorker}
setActive={setModalAddWorker}
></TrackerModal>
2023-04-20 20:10:08 +03:00
2023-06-22 14:53:35 +03:00
<div className="tasks__head__persons">
2023-06-29 03:41:18 +03:00
{projectInfo.projectUsers?.length > 3 && (
2023-06-29 02:27:08 +03:00
<span className="countPersons">+1...</span>
)}
2023-06-29 02:26:49 +03:00
<div className="projectPersons">
2023-06-29 03:41:18 +03:00
{projectInfo.projectUsers?.length &&
2023-06-29 03:41:59 +03:00
projectInfo.projectUsers.slice(0, 3).map((person) => {
return (
<img
key={person.user_id}
src={
person.user?.avatar
? urlForLocal(person.user.avatar)
: avatarMok
}
alt="avatar"
/>
);
})}
2023-06-29 02:26:49 +03:00
</div>
2023-06-22 14:53:35 +03:00
<span
className="addPerson"
onClick={() => {
setPersonListOpen(true);
}}
>
+
</span>
<p>добавить участника</p>
{personListOpen && (
<div className="persons__list">
<img
className="persons__list__close"
src={close}
alt="close"
onClick={() => setPersonListOpen(false)}
/>
<div className="persons__list__count">
2023-06-29 03:41:18 +03:00
<span>{projectInfo.projectUsers?.length}</span>
2023-06-22 14:53:35 +03:00
участник
</div>
<div className="persons__list__info">
2023-07-04 16:19:58 +03:00
<span>В проекте - </span>
<p>{projectInfo.name}</p>
2023-06-22 14:53:35 +03:00
</div>
<div className="persons__list__items">
2023-06-29 03:41:18 +03:00
{projectInfo.projectUsers?.map((person) => {
2023-06-22 14:53:35 +03:00
return (
<div
className="persons__list__item"
key={person.user_id}
2023-05-24 19:23:24 +03:00
>
2023-06-22 14:53:35 +03:00
<img
className="avatar"
2023-06-29 03:41:18 +03:00
src={
person.user?.avatar
? urlForLocal(person.user.avatar)
: avatarMok
}
2023-06-22 14:53:35 +03:00
alt="avatar"
/>
<span>{person.user.fio}</span>
<img
className="delete"
src={close}
alt="delete"
onClick={() => deletePerson(person.user_id)}
/>
2023-05-24 19:23:24 +03:00
</div>
2023-06-22 14:53:35 +03:00
);
})}
2023-05-24 19:23:24 +03:00
</div>
2023-06-22 14:53:35 +03:00
<div
className="persons__list__add"
onClick={() => {
dispatch(modalToggle("addWorker"));
setModalAddWorker(true);
setPersonListOpen(false);
}}
>
<span className="addPerson">+</span>
<p>Добавить участников</p>
</div>
</div>
)}
</div>
<Link to={`/profile/tracker`} className="link">
<div className="tasks__head__back">
<p>Вернуться на проекты</p>
<img src={arrow} alt="arrow" />
2023-06-12 23:30:18 +03:00
</div>
2023-06-22 14:53:35 +03:00
</Link>
</div>
</div>
</div>
<div className="modal-tiket__content ticket">
<div className="content ticket-whith">
<div className="content__task">
{editOpen ? (
<input
2023-07-07 00:46:40 +03:00
maxLength="100"
2023-06-22 14:53:35 +03:00
value={inputsValue.title}
onChange={(e) => {
setInputsValue((prevValue) => ({
...prevValue,
title: e.target.value,
}));
}}
/>
) : (
2023-08-07 15:52:58 +03:00
<h5 className="fullName nameFullScreen">{inputsValue.title}</h5>
2023-06-22 14:53:35 +03:00
)}
<div className="content__description">
{editOpen ? (
2023-06-29 02:26:49 +03:00
<CKEditor
editor={ClassicEditor}
data={inputsValue.description}
config={{
removePlugins: [
"CKFinderUploadAdapter",
"CKFinder",
"EasyImage",
"Image",
"ImageCaption",
"ImageStyle",
"ImageToolbar",
"ImageUpload",
"MediaEmbed",
"BlockQuote",
],
}}
onChange={(event, editor) => {
const data = editor.getData();
2023-06-22 14:53:35 +03:00
setInputsValue((prevValue) => ({
...prevValue,
2023-06-29 02:26:49 +03:00
description: data,
2023-06-22 14:53:35 +03:00
}));
}}
/>
) : (
2023-06-29 02:27:08 +03:00
<p
2023-08-07 15:52:58 +03:00
className="fullDescription fullScreenDescription"
2023-06-29 02:27:08 +03:00
dangerouslySetInnerHTML={{
__html: inputsValue.description,
}}
/>
2023-06-22 14:53:35 +03:00
)}
</div>
2023-07-13 15:49:34 +03:00
{Boolean(taskFiles.length) && (
2023-08-07 15:52:58 +03:00
<div className="task__files filesFullScreen">
2023-07-13 15:49:34 +03:00
{taskFiles.map((file) => {
return (
<div className="taskFile" key={file.id}>
<img
className="imgFile"
src={backendImg(file.file?.url)}
alt="img"
/>
<div
className="deleteFile"
onClick={() => deleteFile(file)}
>
<img src={fileDelete} alt="delete" />
2023-07-13 15:49:07 +03:00
</div>
</div>
2023-07-13 15:49:34 +03:00
);
})}
</div>
)}
2023-07-13 15:49:07 +03:00
{uploadedFile && (
2023-07-13 15:49:34 +03:00
<div className="fileLoaded">
{uploadedFile.map((file) => {
return (
<div className="loadedFile" key={file.id}>
<img
src={backendImg(file.url)}
alt="img"
key={file.id}
/>
<div
className="deleteFile"
onClick={() => deleteLoadedFile(file)}
>
<img src={fileDelete} alt="delete" />
</div>
</div>
);
})}
<button onClick={attachFile}>Загрузить</button>
</div>
2023-07-13 15:49:07 +03:00
)}
2023-06-22 14:53:35 +03:00
<div className="content__communication">
2023-06-29 03:41:18 +03:00
{/*<p className="tasks">*/}
{/* <BaseButton*/}
{/* onClick={() => {*/}
{/* dispatch(modalToggle("addSubtask"));*/}
{/* setModalAddWorker(true);*/}
{/* }}*/}
{/* styles={"button-green-add"}*/}
{/* >*/}
{/* <img src={plus}></img>*/}
{/* Добавить под задачу*/}
{/* </BaseButton>*/}
{/*</p>*/}
2023-07-13 15:49:07 +03:00
<div className="file">
<div className="input__wrapper">
<input
2023-07-13 15:49:34 +03:00
name="file"
id="input__file"
type="file"
accept="image/*,.png,.jpg,.svg,.jpeg"
className="input__file"
onChange={handleUpload}
2023-07-13 15:49:07 +03:00
/>
2023-07-13 15:49:34 +03:00
<label
htmlFor="input__file"
className="button-add-file"
>
2023-07-13 15:49:07 +03:00
<img src={file}></img>
Загрузить файл
</label>
</div>
<span>{taskFiles.length ? taskFiles.length : 0}</span>
{caseOfNum(taskFiles.length, "files")}
</div>
2023-06-22 14:53:35 +03:00
</div>
2023-08-07 15:52:58 +03:00
<div className="content__input commentFullScreen">
2023-06-22 14:53:35 +03:00
<input
placeholder="Оставить комментарий"
value={inputsValue.comment}
onChange={(e) => {
setInputsValue((prevValue) => ({
...prevValue,
comment: e.target.value,
}));
}}
/>
<img src={send} onClick={createComment} alt="send"></img>
</div>
<div className="comments__list">
{comments.map((comment) => {
return (
<TrackerTaskComment
key={comment.id}
taskId={taskInfo.id}
comment={comment}
commentDelete={commentDelete}
addSubComment={addSubComment}
subCommentDelete={subCommentDelete}
/>
);
})}
2023-05-24 19:23:24 +03:00
</div>
</div>
2023-06-22 14:53:35 +03:00
</div>
2023-08-07 15:52:58 +03:00
<div className="workers fullScreenWorkers">
2023-06-29 02:26:49 +03:00
<div className="workers_box task__info">
2023-06-22 14:53:35 +03:00
<p className="workers__creator">
2023-08-07 15:52:58 +03:00
Создатель :
<p>&nbsp;{taskInfo.user?.fio}</p>
2023-06-22 14:53:35 +03:00
</p>
2023-04-20 20:10:08 +03:00
2023-06-29 03:41:18 +03:00
{taskInfo.executor ? (
<div className="executor">
<p>Исполнитель: {taskInfo.executor.fio}</p>
<img
src={
taskInfo.executor?.avatar
? urlForLocal(taskInfo.executor.avatar)
: avatarMok
}
2023-06-29 03:41:59 +03:00
alt="avatar"
/>
2023-06-29 03:41:18 +03:00
<img
src={close}
className="delete"
onClick={() => deleteTaskExecutor()}
/>
</div>
) : (
<div className="add-worker moreItems ">
<button
className="button-add-worker"
onClick={() => setDropListOpen(true)}
>
+
</button>
<span>Добавить исполнителя</span>
{dropListOpen && (
<div className="dropdownList">
<img
src={close}
className="dropdownList__close"
onClick={() => setDropListOpen(false)}
/>
{correctProjectUsers.map((person) => {
return (
<div
className="dropdownList__person"
key={person.user_id}
onClick={() => taskExecutor(person)}
>
<span>{person.user.fio}</span>
<img
src={
person.user?.avatar
? urlForLocal(person.user.avatar)
: avatarMok
}
2023-06-29 03:41:59 +03:00
alt="avatar"
2023-06-29 03:41:18 +03:00
/>
</div>
);
})}
</div>
)}
</div>
)}
{Boolean(taskInfo.taskUsers.length) && (
<div className="members">
<p>Участники:</p>
<div className="members__list">
{taskInfo.taskUsers.map((member) => {
return (
<div className="worker" key={member.user_id}>
<p>{member.fio}</p>
<img
src={
member?.avatar
? urlForLocal(member.avatar)
: avatarMok
}
2023-06-29 03:41:59 +03:00
alt="avatar"
2023-06-29 03:41:18 +03:00
/>
<img
src={close}
className="delete"
onClick={() => deleteMember(member)}
/>
</div>
);
})}
</div>
</div>
)}
2023-06-22 14:53:35 +03:00
<div className="add-worker moreItems">
2023-06-29 03:41:18 +03:00
<button
className="button-add-worker"
onClick={() => setDropListMembersOpen(true)}
2023-06-22 14:53:35 +03:00
>
+
2023-06-29 03:41:18 +03:00
</button>
2023-06-22 14:53:35 +03:00
<span>Добавить участников</span>
2023-06-29 03:41:18 +03:00
{dropListMembersOpen && (
<div className="dropdownList">
<img
src={close}
className="dropdownList__close"
onClick={() => setDropListMembersOpen(false)}
/>
{users.length ? (
users.map((person) => {
return (
<div
className="dropdownList__person"
key={person.user_id}
onClick={() => addMember(person)}
>
<span>{person.user.fio}</span>
<img
src={
person.user?.avatar
? urlForLocal(person.user.avatar)
: avatarMok
}
2023-06-29 03:41:59 +03:00
alt="avatar"
2023-06-29 03:41:18 +03:00
/>
</div>
);
})
) : (
<p className="noUsers">Нет пользователей</p>
)}
</div>
)}
2023-06-22 14:53:35 +03:00
</div>
</div>
2023-04-20 20:10:08 +03:00
2023-06-22 14:53:35 +03:00
<div className="workers_box-middle">
2023-07-07 17:38:31 +03:00
<div className="deadLine">
<div
className="deadLine__container"
onClick={() => setDatePickerOpen(!datePickerOpen)}
>
<img src={calendarIcon} alt="calendar" />
<span>
{deadLine
? getCorrectDate(deadLine)
: "Срок исполнения:"}
</span>
2023-07-07 17:38:19 +03:00
</div>
<DatePicker
2023-07-07 17:38:31 +03:00
className="datePicker"
open={datePickerOpen}
locale="ru"
selected={startDate}
onChange={(date) => {
setDatePickerOpen(false);
setStartDate(date);
setDeadLine(date);
selectDeadLine(date);
}}
2023-07-07 17:38:19 +03:00
/>
</div>
2023-06-22 14:53:35 +03:00
<div className="time">
2023-06-29 02:26:49 +03:00
<img src={watch}></img>
2023-06-22 14:53:35 +03:00
<span>Длительность : </span>
2023-06-29 02:26:49 +03:00
<p>
{correctTimerTime(currentTimerCount.hours)}:
{correctTimerTime(currentTimerCount.minute)}:
{correctTimerTime(currentTimerCount.seconds)}
</p>
2023-06-22 14:53:35 +03:00
</div>
2023-04-20 20:10:08 +03:00
2023-06-22 14:53:35 +03:00
{timerStart ? (
2023-06-29 02:26:49 +03:00
<button
className={
2023-06-29 02:27:08 +03:00
taskInfo.executor_id ===
Number(localStorage.getItem("id"))
2023-06-29 02:26:49 +03:00
? "stop"
: "stop disable"
}
onClick={() => stopTaskTimer()}
>
2023-06-22 14:53:35 +03:00
Остановить
</button>
) : (
<button
className={
2023-06-29 02:27:08 +03:00
taskInfo.executor_id ===
Number(localStorage.getItem("id"))
2023-06-22 14:53:35 +03:00
? "start"
: "start disable"
2023-05-24 19:23:24 +03:00
}
2023-06-22 14:53:35 +03:00
onClick={() => startTaskTimer()}
>
2023-06-29 02:26:49 +03:00
Начать делать
<img src={arrowStart}></img>
2023-06-22 14:53:35 +03:00
</button>
)}
</div>
2023-06-12 23:30:18 +03:00
2023-06-22 14:53:35 +03:00
<div className="workers_box-bottom">
<div
className={editOpen ? "edit" : ""}
onClick={() => {
if (editOpen) {
setEditOpen(!editOpen);
editTask();
} else {
setEditOpen(!editOpen);
}
}}
>
<img src={edit} alt="edit"></img>
<p>{editOpen ? "сохранить" : "редактировать"}</p>
</div>
<div>
<img src={link} alt="link"></img>
<p onClick={copyTicketLink}>ссылка на задачу</p>
2023-06-22 14:53:35 +03:00
</div>
2023-07-14 03:03:33 +03:00
<div onClick={archiveTask}>
2023-07-07 00:46:40 +03:00
<img src={archive} alt="arch"></img>
2023-06-22 14:53:35 +03:00
<p>в архив</p>
</div>
<div onClick={deleteTask}>
<img src={del} alt="delete"></img>
<p>удалить</p>
2023-05-24 19:23:24 +03:00
</div>
</div>
2023-06-22 14:53:35 +03:00
</div>
</div>
</>
)}
</div>
2023-07-14 03:03:49 +03:00
{acceptModalOpen && (
<AcceptModal closeModal={closeAcceptModal} agreeHandler={deleteTask} />
)}
2023-06-22 14:53:35 +03:00
<Footer />
</section>
2023-04-20 20:10:08 +03:00
);
};
export default TicketFullScreen;