diff --git a/src/components/UI/ModalTicket/ModalTicket.jsx b/src/components/UI/ModalTicket/ModalTicket.jsx
index 290ff0bd..1aa706f1 100644
--- a/src/components/UI/ModalTicket/ModalTicket.jsx
+++ b/src/components/UI/ModalTicket/ModalTicket.jsx
@@ -8,6 +8,8 @@ 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";
@@ -33,7 +35,10 @@ export const ModalTiсket = ({
const dispatch = useDispatch();
const [addSubtask, setAddSubtask] = useState(false);
const [editOpen, setEditOpen] = useState(false);
- const [inputsValue, setInputsValue] = useState({title: task.title, description: task.description})
+ const [inputsValue, setInputsValue] = useState({title: task.title, description: task.description, comment: ''});
+ const [comments, setComments] = useState([]);
+ const [commentsEditOpen, setCommentsEditOpen] = useState({})
+ const [commentsEditText, setCommentsEditText] = useState({})
function deleteTask() {
apiRequest("/task/update-task", {
@@ -61,6 +66,57 @@ export const ModalTiсket = ({
});
}
+ function createComment() {
+ apiRequest("/comment/create", {
+ method: "POST",
+ data: {
+ text: inputsValue.comment,
+ entity_type: 2,
+ entity_id: task.id
+ }
+ }).then((res) => {
+ let newComment = res
+ newComment.created_at = new Date()
+ 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) => {
+ })
+ }
+
+ 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}))
+ })
+ })
+ }, [])
+
return (
{
setInputsValue((prevValue) => ({...prevValue, description: e.target.value}))
}}/> :
{inputsValue.description}
}
-
+ {/*
*/}
@@ -115,8 +171,33 @@ export const ModalTiсket = ({
+
+ {comments.map((comment) => {
+ return
+
+
{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]}
}
+
+ })
+
+ }
diff --git a/src/components/UI/ModalTicket/ModalTicket.scss b/src/components/UI/ModalTicket/ModalTicket.scss
index fdd19c48..353a98ab 100644
--- a/src/components/UI/ModalTicket/ModalTicket.scss
+++ b/src/components/UI/ModalTicket/ModalTicket.scss
@@ -75,6 +75,46 @@
color: #1a1919;
margin-bottom: 0;
}
+
+ .comments__list {
+ display: flex;
+ flex-direction: column;
+ row-gap: 10px;
+ &__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;
+
+ &__info {
+ display: flex;
+ justify-content: center;
+ column-gap: 15px;
+
+ .edit {
+ width: 25px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 5px;
+ }
+
+ .edit__open {
+ background: green;
+ }
+
+ img {
+ cursor: pointer;
+ width: 15px;
+ }
+ }
+ }
+ }
}
&__description {
diff --git a/src/components/UI/TicketFullScreen/TicketFullScreen.jsx b/src/components/UI/TicketFullScreen/TicketFullScreen.jsx
index 46f1c769..dce1ebd8 100644
--- a/src/components/UI/TicketFullScreen/TicketFullScreen.jsx
+++ b/src/components/UI/TicketFullScreen/TicketFullScreen.jsx
@@ -8,8 +8,15 @@ import TrackerModal from "../TrackerModal/TrackerModal";
import { Navigation } from "../../Navigation/Navigation";
import {Loader} from "../../Loader/Loader";
-import { useDispatch } from "react-redux";
-import {modalToggle, setToggleTab} from "../../../redux/projectsTrackerSlice";
+import {useDispatch, useSelector} from "react-redux";
+import {
+ deletePersonOnProject,
+ modalToggle,
+ setProjectBoardFetch,
+ setToggleTab,
+ getProjectBoard,
+ getBoarderLoader
+} from "../../../redux/projectsTrackerSlice";
import { apiRequest } from "../../../api/request";
import project from "../../../images/trackerProject.svg";
@@ -22,7 +29,6 @@ import plus from "../../../images/plus.svg";
import tasks from "../../../images/trackerTasks.svg";
import archive from "../../../images/archiveTracker.svg";
import selectArrow from "../../../images/select.svg";
-import avatarTest from "../../../images/AvatarTest .png";
import arrow from "../../../images/arrowCalendar.png";
import link from "../../../images/link.svg";
import archive2 from "../../../images/archive.svg";
@@ -30,28 +36,39 @@ import del from "../../../images/delete.svg";
import edit from "../../../images/edit.svg";
import "./ticketFullScreen.scss";
+import close from "../../../images/closeProjectPersons.svg";
+import {urlForLocal} from "../../../helper";
+import {getCorrectDate} from "../../Calendar/calendarHelper";
export const TicketFullScreen = ({}) => {
const [modalAddWorker, setModalAddWorker] = useState(false);
const ticketId = useParams();
const dispatch = useDispatch();
const navigate = useNavigate();
- const [projectInfo, setProjectInfo] = useState({});
+ const projectBoard = useSelector(getProjectBoard);
+ const boardLoader = useSelector(getBoarderLoader);
const [taskInfo, setTaskInfo] = useState({});
const [editOpen, setEditOpen] = useState(false);
- const [inputsValue, setInputsValue] = useState({})
- const [loader, setLoader] = useState(true)
+ const [inputsValue, setInputsValue] = useState({});
+ const [loader, setLoader] = useState(true);
+ const [comments, setComments] = useState([]);
+ const [commentsEditOpen, setCommentsEditOpen] = useState({})
+ const [commentsEditText, setCommentsEditText] = useState({})
+ const [personListOpen, setPersonListOpen] = useState(false)
useEffect(() => {
apiRequest(`/task/get-task?task_id=${ticketId.id}`).then((taskInfo) => {
setTaskInfo(taskInfo);
- setInputsValue({title: taskInfo.title, description: taskInfo.description})
- apiRequest(`/project/get-project?project_id=${taskInfo.project_id}`).then(
- (project) => {
- setProjectInfo(project);
- setLoader(false)
- }
- );
+ 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}))
+ setCommentsEditText((prevValue) => ({...prevValue, [item.id]: item.text}))
+ })
+ })
+ dispatch(setProjectBoardFetch(taskInfo.project_id));
+ setLoader(boardLoader)
});
}, []);
@@ -79,6 +96,59 @@ export const TicketFullScreen = ({}) => {
});
}
+ 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()
+ 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) => {
+ })
+ }
+
+ function deletePerson(userId) {
+ apiRequest("/project/del-user", {
+ method: "DELETE",
+ data: {
+ project_id: projectBoard.id,
+ user_id: userId
+ },
+ }).then((res) => {
+ dispatch(deletePersonOnProject(userId))
+ });
+ }
+
const toggleTabs = (index) => {
dispatch(setToggleTab(index));
};
@@ -130,7 +200,7 @@ export const TicketFullScreen = ({}) => {
-
Проект : {projectInfo.name}
+
Проект : {projectBoard.name}
{
>
-
-
-
+9
+ {/*
*/}
+ {/*
*/}
+
{projectBoard.projectUsers?.length}
{
- dispatch(modalToggle("addWorker"));
- setModalAddWorker(true);
+ setPersonListOpen(true)
}}
>
+
-
добавить участника в проект
+
добавить участника
+ {personListOpen &&
+
+
setPersonListOpen(false)} />
+
{projectBoard.projectUsers?.length}участник
+
В проекте - “{projectBoard.name}”
+
+ {projectBoard.projectUsers?.map((person) => {
+ return
+
+
{person.user.fio}
+
deletePerson(person.user_id)}/>
+
+ })
+ }
+
+
{
+ dispatch(modalToggle("addWorker"));
+ setModalAddWorker(true);
+ setPersonListOpen(false)
+ }}
+ >
+
+
+
Добавить участников
+
+
+ }
Учавствую
@@ -180,7 +276,7 @@ export const TicketFullScreen = ({}) => {
{editOpen ?
{
setInputsValue((prevValue) => ({...prevValue, description: e.target.value}))
}}/> :
{inputsValue.description}
}
-
+ {/*
*/}
@@ -204,8 +300,33 @@ export const TicketFullScreen = ({}) => {
+
+ {comments.map((comment) => {
+ return
+
+
{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]}
}
+
+ })
+
+ }
diff --git a/src/components/UI/TrackerModal/TrackerModal.jsx b/src/components/UI/TrackerModal/TrackerModal.jsx
index d8361f34..2d23bab6 100644
--- a/src/components/UI/TrackerModal/TrackerModal.jsx
+++ b/src/components/UI/TrackerModal/TrackerModal.jsx
@@ -12,7 +12,8 @@ import {
editProjectName,
editColumnName,
getColumnName,
- getColumnId
+ getColumnId,
+ addPersonToProject
} from "../../../redux/projectsTrackerSlice";
import arrowDown from "../../../images/selectArrow.png"
@@ -136,23 +137,36 @@ export const TrackerModal = ({
apiRequest("/project/add-user", {
method: "POST",
data: {
- user_id: selectedWorker.id,
+ user_id: selectedWorker.user_id,
project_id: projectBoard.id
}
}).then((el) => {
+ dispatch(addPersonToProject(el))
setActive(false);
- selectedWorker(null)
+ setSelectedWorker('')
+ setSelectWorkersOpen(false)
})
}
useEffect(() => {
- modalType === "addWorker" ? apiRequest('/project/my-employee').then((el) => setWorkers(el.managerEmployees)) : ''
- }, [modalType])
+ modalType === "addWorker" ? 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
+ }, []))
+ }) : ''
+ }, [active])
+
return (
setActive(false)}
+ onClick={() => {
+ setActive(false)
+ setSelectWorkersOpen(false)
+ }}
>
e.stopPropagation()}>
{modalType === "addWorker" && (
@@ -170,18 +184,24 @@ export const TrackerModal = ({
{selectedWorker ? selectedWorker.employee.fio : 'Выберите пользователя'}
{Boolean(selectWorkersOpen) &&
-
- {workers.map((worker) => {
- if (worker === selectedWorker) {
- return
+
+ {Boolean(workers.length) ?
+ workers.map((worker) => {
+ if (worker === selectedWorker) {
+ return
+ }
+ return
+ {
+ setSelectedWorker(worker)
+ }
+ }>
+
{worker.employee.fio}
+
+
+ }) :
+
Нет пользователей
}
- return
setSelectedWorker(worker)}>
-
{worker.employee.fio}
-
-
- })
- }
-
+
}
diff --git a/src/images/closeProjectPersons.svg b/src/images/closeProjectPersons.svg
new file mode 100644
index 00000000..baf390e2
--- /dev/null
+++ b/src/images/closeProjectPersons.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/pages/ProjectTracker/ProjectTracker.js b/src/pages/ProjectTracker/ProjectTracker.js
index 854e5ced..8c19d66e 100644
--- a/src/pages/ProjectTracker/ProjectTracker.js
+++ b/src/pages/ProjectTracker/ProjectTracker.js
@@ -5,6 +5,7 @@ import { ProfileBreadcrumbs } from "../../components/ProfileBreadcrumbs/ProfileB
import { Footer } from "../../components/Footer/Footer";
import { Navigation } from "../../components/Navigation/Navigation";
import { Loader } from "../../components/Loader/Loader";
+import { urlForLocal } from '../../helper'
import { useDispatch, useSelector } from "react-redux";
import { apiRequest } from "../../api/request";
@@ -18,6 +19,7 @@ import {
activeLoader,
setColumnName,
setColumnId,
+ deletePersonOnProject
} from "../../redux/projectsTrackerSlice";
import ModalTicket from "../../components/UI/ModalTicket/ModalTicket";
@@ -32,6 +34,7 @@ import filesBoard from "../../images/filesBoard.svg";
import arrow from "../../images/arrowCalendar.png";
import del from "../../images/delete.svg";
import edit from "../../images/edit.svg";
+import close from "../../images/closeProjectPersons.svg"
export const ProjectTracker = () => {
const dispatch = useDispatch();
@@ -44,6 +47,7 @@ export const ProjectTracker = () => {
const [modalAdd, setModalAdd] = useState(false);
const [modalActiveTicket, setModalActiveTicket] = useState(false);
const [selectedTicket, setSelectedTicket] = useState({});
+ const [personListOpen, setPersonListOpen] = useState(false)
const startWrapperIndexTest = useRef({});
const projectBoard = useSelector(getProjectBoard);
@@ -151,6 +155,18 @@ export const ProjectTracker = () => {
});
}
+ function deletePerson(userId) {
+ apiRequest("/project/del-user", {
+ method: "DELETE",
+ data: {
+ project_id: projectBoard.id,
+ user_id: userId
+ },
+ }).then((res) => {
+ dispatch(deletePersonOnProject(userId))
+ });
+ }
+
return (
@@ -226,13 +242,39 @@ export const ProjectTracker = () => {
{
- dispatch(modalToggle("addWorker"));
- setModalAdd(true);
+ setPersonListOpen(true)
}}
>
+
добавить участника
+ {personListOpen &&
+
+
setPersonListOpen(false)} />
+
{projectBoard.projectUsers?.length}участник
+
В проекте - “{projectBoard.name}”
+
+ {projectBoard.projectUsers?.map((person) => {
+ return
+
+
{person.user.fio}
+
deletePerson(person.user_id)}/>
+
+ })
+ }
+
+
{
+ dispatch(modalToggle("addWorker"));
+ setModalAdd(true);
+ setPersonListOpen(false)
+ }}
+ >
+
+
+
Добавить участников
+
+
+ }
Участвую
diff --git a/src/pages/Tracker/tracker.scss b/src/pages/Tracker/tracker.scss
index f7452790..6a0d7626 100644
--- a/src/pages/Tracker/tracker.scss
+++ b/src/pages/Tracker/tracker.scss
@@ -309,6 +309,118 @@
line-height: 17px;
max-width: 125px;
}
+
+ .persons__list {
+ position: absolute;
+ z-index: 2;
+ display: flex;
+ flex-direction: column;
+ background: linear-gradient(180deg, #FFFFFF 0%, #EBEBEB 100%);
+ border-radius: 40px;
+ padding: 33px 24px 44px 34px;
+ width: 425px;
+ cursor: default;
+
+ &__close {
+ cursor: pointer;
+ width: 8px;
+ height: 8px;
+ margin-left: auto;
+ }
+
+ &__count {
+ display: flex;
+ align-items: end;
+ color: #1458DD;
+ font-size: 22px;
+ margin-top: 10px;
+ span {
+ font-size: 44px;
+ font-weight: 700;
+ line-height: 40px;
+ width: auto;
+ height: auto;
+ margin-right: 5px;
+ }
+ }
+
+ &__info {
+ display: flex;
+ font-size: 18px;
+ line-height: 22px;
+ color: #263238;
+ font-weight: 500;
+ margin: 13px 0 32px;
+
+ span {
+ width: auto;
+ height: auto;
+ color: #1458DD;
+ font-weight: 600;
+ font-size: 18px;
+ line-height: 22px;
+ }
+ }
+
+ &__items {
+ display: flex;
+ flex-wrap: wrap;
+ row-gap: 60px;
+ column-gap: 35px;
+ margin-bottom: 38px;
+ }
+
+ &__item {
+ width: 145px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .avatar {
+ width: 22px;
+ height: 22px;
+ }
+
+ span {
+ display: block;
+ font-weight: 400;
+ font-size: 12px;
+ line-height: initial;
+ color: #807777;
+ width: auto;
+ height: auto;
+ max-width: 85px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+
+ .delete {
+ cursor: pointer;
+ width: 14px;
+ height: 14px;
+ }
+ }
+
+ &__add {
+ display: flex;
+ cursor: pointer;
+
+ span {
+ background: #8BCC60;
+ left: 0;
+ }
+
+ p {
+ margin-left: 17px;
+ color: #000000;
+ font-weight: 400;
+ font-size: 12px;
+ line-height: 32px;
+ position: initial;
+ }
+ }
+ }
}
&__select {
diff --git a/src/redux/projectsTrackerSlice.js b/src/redux/projectsTrackerSlice.js
index 3e7333aa..b4fe55fd 100644
--- a/src/redux/projectsTrackerSlice.js
+++ b/src/redux/projectsTrackerSlice.js
@@ -35,6 +35,12 @@ export const projectsTrackerSlice = createSlice({
}
});
},
+ deletePersonOnProject: (state,action) => {
+ state.projectBoard.projectUsers = state.projectBoard.projectUsers.filter((person) => person.user_id !== action.payload)
+ },
+ addPersonToProject: (state, action) => {
+ state.projectBoard.projectUsers.push(action.payload)
+ },
activeLoader: (state) => {
state.boardLoader = true;
},
@@ -100,7 +106,9 @@ export const {
activeLoader,
editProjectName,
editColumnName,
- setColumnId
+ setColumnId,
+ deletePersonOnProject,
+ addPersonToProject
} = projectsTrackerSlice.actions;
export const getProjects = (state) => state.tracker.projects;