Victor Batischev 59d0f5eae6 remove last
2024-02-28 19:59:56 +03:00

872 lines
29 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 "react-datepicker/dist/react-datepicker.css";
import { useDispatch, useSelector } from "react-redux";
import { getProfileInfo } from "@redux/outstaffingSlice";
import {
addPersonToProject,
editColumnName,
editProjectName,
getColumnId,
getColumnName,
getColumnPriority,
getProjectBoard,
getValueModalType,
setColumnName,
setColumnPriority,
setProject,
setProjectBoardFetch
} from "@redux/projectsTrackerSlice";
import { getCorrectDate } from "@utils/calendarHelper";
import { getCorrectRequestDate, removeLast, urlForLocal } from "@utils/helper";
import { apiRequest } from "@api/request";
import { useNotification } from "@hooks/useNotification";
import BaseButton from "@components/Common/BaseButton/BaseButton";
import { Loader } from "@components/Common/Loader/Loader";
import ModalLayout from "@components/Common/ModalLayout/ModalLayout";
import arrowRight from "assets/icons/arrows/arrowRightCreateTask.svg";
import arrowDown from "assets/icons/arrows/selectArrow.png";
import close from "assets/icons/close.png";
import calendarImg from "assets/icons/createTaskCalendar.svg";
import crossWhite from "assets/icons/crossWhite.svg";
import avatarMok from "assets/images/avatarMok.png";
import "./trackerModal.scss";
registerLocale("ru", ru);
export const TrackerModal = ({
active,
setActive,
selectedTab,
defautlInput,
titleProject,
projectId,
priorityTask,
projectUsers,
projectMarks
}) => {
const dispatch = useDispatch();
const projectBoard = useSelector(getProjectBoard);
const columnName = useSelector(getColumnName);
const columnId = useSelector(getColumnId);
const columnPriority = useSelector(getColumnPriority);
const profileInfo = useSelector(getProfileInfo);
const modalType = useSelector(getValueModalType);
const [projectName, setProjectName] = useState(defautlInput);
const [valueColumn, setValueColumn] = useState("");
const [nameProject, setNameProject] = useState("");
const [valueTicket, setValueTicket] = useState("");
const [descriptionTicket, setDescriptionTicket] = useState("");
const [workers, setWorkers] = useState([]);
const [selectWorkersOpen, setSelectWorkersOpen] = useState(false);
const [selectedWorker, setSelectedWorker] = useState(null);
const [emailWorker, setEmailWorker] = useState("");
const [selectColumnPriority, setSelectColumnPriority] = useState(
"Выберите приоритет колонки"
);
const [selectedExecutorTask, setSelectedExecutorTask] = useState(
"Выберите исполнителя"
);
const [selectExecutorTaskOpen, setSelectExecutorTaskOpen] = useState(false);
const [correctProjectUsers, setCorrectProjectUsers] = useState([]);
const [correctProjectTags, setCorrectProjectTags] = useState([]);
const [taskTags, setTaskTags] = useState([]);
const [selectTagsOpen, setSelectTagsOpen] = useState(false);
const [selectedPriority, setSelectedPriority] = useState(null);
const [selectPriority, setSelectPriority] = useState(false);
const [selectColumnPriorityOpen, setSelectColumnPriorityOpen] =
useState(false);
const { showNotification } = useNotification();
const [deadLineDate, setDeadLineDate] = useState("");
const [datePickerOpen, setDatePickerOpen] = useState(false);
const [startDate, setStartDate] = useState(new Date());
const [loader, setLoader] = useState(false);
const priority = [
{
name: "Высокий",
key: 2
},
{
name: "Средний",
key: 1
},
{
name: "Низкий",
key: 0
}
];
function createTab() {
if (!valueColumn) {
showNotification({ show: true, text: "Введите название", type: "error" });
return;
}
apiRequest("/project-column/create-column", {
method: "POST",
data: {
project_id: projectBoard.id,
priority: projectBoard.columns.length
? projectBoard.columns.at(-1).priority + 1
: 1,
title: valueColumn
}
}).then(() => {
dispatch(setProjectBoardFetch(projectBoard.id));
showNotification({
show: true,
text: "Колонка создана",
type: "success"
});
});
setValueColumn("");
setActive(false);
}
function createTicket() {
if (!valueTicket || !descriptionTicket) {
showNotification({
show: true,
text: "Введите название и описание",
type: "error"
});
return;
}
setLoader(true);
apiRequest("/task/create-task", {
method: "POST",
data: {
project_id: projectBoard.id,
title: valueTicket,
description: descriptionTicket,
status: 1,
user_id: localStorage.getItem("id"),
column_id: selectedTab,
execution_priority: selectedPriority ? selectedPriority.key : "",
priority: priorityTask,
dead_line: deadLineDate ? getCorrectRequestDate(deadLineDate) : ""
}
}).then((res) => {
if (res.status === 500) {
showNotification({
show: true,
text: "Задача с таким именем уже существует",
type: "error"
});
setLoader(false);
} else {
for (let i = 0; i < taskTags.length; i++) {
apiRequest("/mark/attach", {
method: "POST",
data: {
mark_id: taskTags[i].id,
entity_type: 2,
entity_id: res.id
}
}).then(() => {
setTaskTags([]);
});
}
if (selectedExecutorTask.user_id) {
apiRequest("/task/update-task", {
method: "PUT",
data: {
task_id: res.id,
executor_id: selectedExecutorTask.user_id
}
}).then(() => {
dispatch(setProjectBoardFetch(projectBoard.id));
setActive(false);
setValueTicket("");
setDescriptionTicket("");
setSelectedExecutorTask("Выберите исполнителя");
setSelectedPriority(null);
setLoader(false);
});
} else {
setActive(false);
setLoader(false);
setValueTicket("");
setDescriptionTicket("");
dispatch(setProjectBoardFetch(projectBoard.id));
}
setDeadLineDate("");
showNotification({
show: true,
text: "Задача создана",
type: "success"
});
}
});
}
function editProject() {
apiRequest("/project/update", {
method: "PUT",
data: {
project_id: projectId,
name: projectName
}
}).then(() => {
setActive(false);
dispatch(editProjectName({ id: projectId, name: projectName }));
showNotification({
show: true,
text: "Название проекта успешно изменено",
type: "success"
});
});
}
function changeColumnParams() {
projectBoard.columns.forEach((column) => {
if (column.id === columnId && column.priority !== columnPriority) {
const priorityColumns = [
{
column_id: column.id,
priority: Number(columnPriority)
}
];
for (let i = column.priority; i < columnPriority; i++) {
const currentColumn = {
column_id: projectBoard.columns[i].id,
priority: i
};
priorityColumns.push(currentColumn);
}
for (let i = column.priority; i > columnPriority; i--) {
const currentColumn = {
column_id: projectBoard.columns[i - 2].id,
priority: i
};
priorityColumns.push(currentColumn);
}
apiRequest("/project-column/set-priority", {
method: "POST",
data: {
project_id: projectBoard.id,
data: JSON.stringify(priorityColumns)
}
}).then(() => {
dispatch(setProjectBoardFetch(projectBoard.id));
});
}
});
changeColumnTitle();
}
function changeColumnTitle() {
apiRequest("/project-column/update-column", {
method: "PUT",
data: {
column_id: columnId,
title: columnName
}
}).then(() => {
setActive(false);
dispatch(editColumnName({ id: columnId, title: columnName }));
showNotification({
show: true,
text: "Колонка создана",
type: "success"
});
});
}
function createProject() {
if (nameProject !== "") {
apiRequest("/project/create", {
method: "POST",
data: {
user_id: localStorage.getItem("id"),
name: nameProject,
status: 19
}
}).then((res) => {
if (!Array.isArray(res.name)) {
const result = { ...res, columns: [] };
dispatch(setProject(result));
setActive(false);
setNameProject("");
} else {
showNotification({
show: true,
text: "Проект с таким именем уже существует",
type: "error"
});
}
});
}
}
function addUserToProject() {
apiRequest("/project/add-user", {
method: "POST",
data: {
user_id: selectedWorker.user_id,
project_id: projectBoard.id
}
}).then((el) => {
dispatch(addPersonToProject(el));
setActive(false);
setSelectedWorker("");
setSelectWorkersOpen(false);
});
}
function inviteUserByEmail() {
apiRequest("/project/add-user-by-email", {
method: "POST",
data: {
email: emailWorker,
project_id: projectBoard.id
}
}).then((el) => {
setActive(false);
setEmailWorker("");
showNotification({
show: true,
text: "Приглашение отправлено",
type: "success"
});
});
}
useEffect(() => {
modalType === "add-worker"
? apiRequest("/project/my-employee").then((el) => {
let persons = el.managerEmployees;
let ids = projectBoard.projectUsers.map((user) => user.user_id);
setWorkers(
persons.reduce((acc, cur) => {
if (!ids.includes(cur.user_id)) acc.push(cur);
return acc;
}, [])
);
})
: "";
if (
localStorage.getItem("role_status") !== "18" &&
projectUsers &&
Boolean(
!projectUsers.find((item) => item.user_id === profileInfo.id_user)
)
) {
setCorrectProjectUsers([
...projectUsers,
{
user: {
avatar: profileInfo.photo,
fio: profileInfo.fio
},
user_id: profileInfo.id_user
}
]);
} else {
setCorrectProjectUsers(projectUsers);
}
initListeners();
}, [active]);
useEffect(() => {
let tagIds = taskTags.map((tag) => tag.id);
if (projectMarks) {
setCorrectProjectTags(
projectMarks.reduce((acc, cur) => {
if (!tagIds.includes(cur.id)) acc.push(cur);
return acc;
}, [])
);
}
}, [taskTags, projectMarks]);
const initListeners = () => {
document.addEventListener("click", closeByClickingOut);
};
const closeByClickingOut = (event) => {
const path = event.path || (event.composedPath && event.composedPath());
if (
event &&
!path.find(
(div) =>
div.classList &&
(div.classList.contains("tags__selected__name") ||
div.classList.contains("tags__dropDown"))
)
) {
setSelectTagsOpen(false);
}
if (
event &&
!path.find(
(div) =>
div.classList &&
(div.classList.contains("select__executor") ||
div.classList.contains("select__executor__dropDown"))
)
) {
setSelectExecutorTaskOpen(false);
}
};
return (
<ModalLayout active={active} setActive={setActive} type={modalType}>
{modalType === "add-worker" && (
<>
<div className="select__person">
<div className="title-project select-person">
<h4>Добавьте участника</h4>
<div className="invite__blocks">
<div className="add-person-block">
<p className="select-person__info">
Выберите пользователя в списке
</p>
<div
className={
selectWorkersOpen
? "select__worker open"
: "select__worker"
}
onClick={() => setSelectWorkersOpen(!selectWorkersOpen)}
>
<p>
{selectedWorker
? removeLast(selectedWorker.employee.fio)
: "Выберите пользователя"}
</p>
<img className="arrow" src={arrowDown} alt="arrow" />
{Boolean(selectWorkersOpen) && (
<div className="select__worker__dropDown">
{Boolean(workers.length) ? (
workers.map((worker) => {
if (worker === selectedWorker) {
return;
}
return (
<div
className="worker"
key={worker.id}
onClick={() => {
setSelectedWorker(worker);
}}
>
<span>{removeLast(worker.employee.fio)}</span>
<img
src={urlForLocal(worker.employee.avatar)}
alt="avatar"
/>
</div>
);
})
) : (
<div>Нет пользователей</div>
)}
</div>
)}
</div>
<BaseButton
styles={"button-add add-person-btn"}
onClick={addUserToProject}
>
Добавить
</BaseButton>
</div>
<div className="invite-person-block">
<span>или добавьте по e-mail</span>
<div className="input-container invite-person-block__input">
<input
className="name-project"
placeholder="e-mail"
type="email"
value={emailWorker}
onChange={(e) => setEmailWorker(e.target.value)}
/>
</div>
<BaseButton
styles={"button-add add-person-btn"}
onClick={inviteUserByEmail}
>
Пригласить
</BaseButton>
</div>
</div>
</div>
</div>
</>
)}
{modalType === "create-ticket-project" && (
<>
<div className="title-project">
<div className="create-task-head">
<div className="create-task-body__right__owner">
<p>Создание задачи</p>
</div>
</div>
<div className="create-task-body">
<div className="create-task-body__left">
<div className="input-container">
<input
maxLength="100"
className="name-project"
value={valueTicket}
onChange={(e) => setValueTicket(e.target.value)}
placeholder="Название задачи"
/>
</div>
<CKEditor
editor={ClassicEditor}
data={descriptionTicket}
config={{
toolbar: [
"heading",
"|",
"bold",
"italic",
"link",
"bulletedList",
"numberedList"
],
removePlugins: ["BlockQuote"],
placeholder: "Описание задачи"
}}
onChange={(event, editor) => {
const data = editor.getData();
setDescriptionTicket(data);
}}
/>
</div>
<div className="create-task-body__right">
<div className="create-task-body__right__tags">
<div className="tags__selected">
<div className="tags__selected__items">
{taskTags.map((tag) => {
return (
<div
className="selected-tag"
key={tag.id}
style={{ background: tag.color }}
>
<p>{tag.slug}</p>
<img
src={crossWhite}
className="delete"
alt="delete"
onClick={() =>
setTaskTags((prevState) =>
prevState.filter(
(prevTag) => prevTag.id !== tag.id
)
)
}
/>
</div>
);
})}
</div>
<div
className="tags__selected__name"
onClick={() => setSelectTagsOpen(!selectTagsOpen)}
>
Выберите тег
<img
className={
selectTagsOpen ? "arrow arrow--open" : "arrow"
}
src={arrowDown}
alt="arrow"
/>
</div>
</div>
{selectTagsOpen && (
<div className="tags__dropDown">
<img
src={close}
className="close"
onClick={() => setSelectTagsOpen(false)}
/>
{correctProjectTags.map((tag) => {
return (
<div
className="tag__item"
key={tag.id}
onClick={() =>
setTaskTags((prevState) => [...prevState, tag])
}
>
<p>{tag.slug}</p>
<span style={{ background: tag.color }} />
</div>
);
})}
{Boolean(!correctProjectTags.length) && (
<p className="no-tags">Нет тегов</p>
)}
</div>
)}
</div>
<div className="select__priority">
<div
className="select__priority__name"
onClick={() => setSelectPriority(!selectPriority)}
>
{selectedPriority
? `Приоритет: ${selectedPriority.name}`
: "Выберите приоритет"}
<img
className={selectPriority ? "arrow arrow--open" : "arrow"}
src={arrowDown}
alt="arrow"
/>
</div>
{selectPriority && (
<div className="select__priority__dropDown">
{priority.map((item) => {
return (
<div
className="dropdown__item"
key={item.key}
onClick={() => {
setSelectPriority(false);
setSelectedPriority(item);
}}
>
{item.name}
</div>
);
})}
</div>
)}
</div>
<div
onClick={() =>
setSelectExecutorTaskOpen(!selectExecutorTaskOpen)
}
className={
selectExecutorTaskOpen
? "select__executor select__executor--open"
: "select__executor"
}
>
<div className="selected__executor">
{selectedExecutorTask.user_id ? (
<>
<img
className="avatar"
src={urlForLocal(selectedExecutorTask.user.avatar)}
alt="avatar"
/>
<span>{selectedExecutorTask.user.fio}</span>
</>
) : (
<span>{selectedExecutorTask}</span>
)}
</div>
<img className="arrow" src={arrowDown} alt="arrow" />
{selectExecutorTaskOpen && (
<div className="select__executor__dropDown">
{correctProjectUsers.length ? (
correctProjectUsers.map((person) => {
return (
<div
onClick={() => setSelectedExecutorTask(person)}
className="executor"
key={person.user_id}
>
<img
className="avatar"
src={
person.user?.avatar
? urlForLocal(person.user.avatar)
: avatarMok
}
alt="avatar"
/>
<span>{removeLast(person.user.fio)}</span>
</div>
);
})
) : (
<span>Нет пользователей</span>
)}
</div>
)}
</div>
<div className="create-task-body__right__dead-line">
<p></p>
<p onClick={() => setDatePickerOpen(!datePickerOpen)}>
{deadLineDate
? getCorrectDate(deadLineDate)
: "Срок исполнения"}
</p>
<DatePicker
className="datePicker"
open={datePickerOpen}
locale="ru"
selected={startDate}
onChange={(date) => {
setDatePickerOpen(false);
setStartDate(date);
setDeadLineDate(date);
}}
/>
</div>
</div>
</div>
{loader ? (
<Loader style={"green"} />
) : (
<BaseButton styles={"button-add"} onClick={createTicket}>
Создать задачу
</BaseButton>
)}
</div>
</>
)}
{modalType === "edit-project" && (
<div>
<div className="title-project">
<h4>Введите новое название</h4>
<div className="input-container">
<input
className="name-project"
value={projectName}
onChange={(e) => setProjectName(e.target.value)}
/>
</div>
</div>
<BaseButton styles={"button-add"} onClick={editProject}>
Сохранить
</BaseButton>
</div>
)}
{modalType === "create-project" && (
<div>
<div className="title-project">
<h4>{titleProject}</h4>
<div className="input-container">
<input
maxLength="30"
className="name-project"
value={nameProject}
onChange={(e) => setNameProject(e.target.value)}
/>
</div>
<BaseButton styles={"button-add"} onClick={createProject}>
Создать
</BaseButton>
</div>
</div>
)}
{modalType === "addSubtask" && (
<div>
<div className="title-project subtask">
<h4>
Вы добавляете подзадачу{" "}
<p>в колонку(id) задачи "{defautlInput}"</p>
</h4>
<p className="title-project__decs">Введите текст</p>
<div>
<textarea className="title-project__textarea"></textarea>
</div>
</div>
<BaseButton styles={"button-add"} onClick={(e) => e.preventDefault()}>
Добавить
</BaseButton>
</div>
)}
{modalType === "create-column" && (
<div>
<div className="title-project">
<h4>Введите название колонки</h4>
<div className="input-container">
<input
maxLength="100"
className="name-project"
value={valueColumn}
onChange={(e) => setValueColumn(e.target.value)}
/>
</div>
</div>
<BaseButton styles={"button-add"} onClick={createTab}>
Добавить
</BaseButton>
</div>
)}
{modalType === "edit-column" && (
<div>
<div className="title-project">
<div>
<h4>Название колонки</h4>
<div className="input-container">
<input
className="name-project"
value={columnName}
onChange={(e) => dispatch(setColumnName(e.target.value))}
/>
</div>
</div>
<div>
<h4>Приоритет колонки</h4>
<div
className={
selectColumnPriorityOpen
? "select-priority select-priority--open"
: "select-priority"
}
onClick={() =>
setSelectColumnPriorityOpen(!selectColumnPriorityOpen)
}
>
<span>{selectColumnPriority}</span>
<img src={arrowDown} alt="arrow" />
{selectColumnPriorityOpen && (
<div className="select-priority__dropDown">
{projectBoard.columns.map((column, index) => {
return (
<span
key={column.id}
onClick={() => {
setSelectColumnPriority(index + 1);
dispatch(setColumnPriority(index + 1));
}}
>
{index + 1}
</span>
);
})}
</div>
)}
</div>
</div>
</div>
<BaseButton styles={"button-add"} onClick={changeColumnParams}>
Сохранить
</BaseButton>
</div>
)}
<span className="exit" onClick={() => setActive(false)}></span>
</ModalLayout>
);
};
export default TrackerModal;