This commit is contained in:
2023-05-23 23:02:39 +03:00
parent a443bad839
commit c55376ecb3
8 changed files with 427 additions and 48 deletions

View File

@ -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";
@ -35,6 +37,8 @@ export const ModalTiсket = ({
const [editOpen, setEditOpen] = useState(false);
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", {
@ -62,7 +66,7 @@ export const ModalTiсket = ({
});
}
function editComment() {
function createComment() {
apiRequest("/comment/create", {
method: "POST",
data: {
@ -71,12 +75,46 @@ export const ModalTiсket = ({
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))
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 (
@ -109,7 +147,7 @@ export const ModalTiсket = ({
{editOpen ? <input value={inputsValue.description} onChange={(e) => {
setInputsValue((prevValue) => ({...prevValue, description: e.target.value}))
}}/> :<p>{inputsValue.description}</p>}
<img src={taskImg} className="image-task"></img>
{/*<img src={taskImg} className="image-task"></img>*/}
</div>
<div className="content__communication">
<p className="tasks">
@ -136,7 +174,30 @@ export const ModalTiсket = ({
<input placeholder="Оставить комментарий" value={inputsValue.comment} onChange={(e) => {
setInputsValue((prevValue) => ({...prevValue, comment: e.target.value}))
}} />
<img src={send} onClick={editComment}></img>
<img src={send} onClick={createComment}></img>
</div>
<div className='comments__list'>
{comments.map((comment) => {
return <div className='comments__list__item' key={comment.id}>
<div className='comments__list__item__info'>
<span>{getCorrectDate(comment.created_at)}</span>
<div className={commentsEditOpen[comment.id] ? 'edit edit__open' : 'edit'} >
<img src={edit} alt='edit' onClick={() => {
if (commentsEditOpen[comment.id]) {
editComment(comment.id)
}
setCommentsEditOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]}))
}} />
</div>
<img src={del} alt='delete' onClick={() => deleteComment(comment.id)} />
</div>
{commentsEditOpen[comment.id] ? <input value={commentsEditText[comment.id]} onChange={(e) => {
setCommentsEditText((prevValue) => ({...prevValue, [comment.id]: e.target.value}))
}} /> : <p>{commentsEditText[comment.id]}</p>}
</div>
})
}
</div>
</div>
</div>

View File

@ -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 {

View File

@ -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,30 +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 [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, comment: ''})
apiRequest(`/comment/get-by-entity?entity_type=2&entity_id=${taskInfo.id}`).then((res) => setComments(res))
apiRequest(`/project/get-project?project_id=${taskInfo.project_id}`).then(
(project) => {
setProjectInfo(project);
setLoader(false)
}
);
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)
});
}, []);
@ -81,7 +96,7 @@ export const TicketFullScreen = ({}) => {
});
}
function editComment() {
function createComment() {
apiRequest("/comment/create", {
method: "POST",
data: {
@ -90,10 +105,50 @@ export const TicketFullScreen = ({}) => {
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));
};
@ -145,7 +200,7 @@ export const TicketFullScreen = ({}) => {
<div className="tracker__tabs__content content-tabs">
<div className="tasks__head">
<div className="tasks__head__wrapper">
<h4>Проект : {projectInfo.name}</h4>
<h4>Проект : {projectBoard.name}</h4>
<TrackerModal
active={modalAddWorker}
@ -153,19 +208,45 @@ export const TicketFullScreen = ({}) => {
></TrackerModal>
<div className="tasks__head__persons">
<img src={avatarTest} alt="avatar" />
<img src={avatarTest} alt="avatar" />
<span className="countPersons">+9</span>
{/*<img src={avatarTest} alt="avatar" />*/}
{/*<img src={avatarTest} alt="avatar" />*/}
<span className="countPersons">{projectBoard.projectUsers?.length}</span>
<span
className="addPerson"
onClick={() => {
dispatch(modalToggle("addWorker"));
setModalAddWorker(true);
setPersonListOpen(true)
}}
>
+
</span>
<p>добавить участника в проект</p>
<p>добавить участника</p>
{personListOpen &&
<div className='persons__list'>
<img className='persons__list__close' src={close} alt='close' onClick={() => setPersonListOpen(false)} />
<div className='persons__list__count'><span>{projectBoard.projectUsers?.length}</span>участник</div>
<div className='persons__list__info'>В проекте - <span>{projectBoard.name}</span></div>
<div className='persons__list__items'>
{projectBoard.projectUsers?.map((person) => {
return <div className='persons__list__item' key={person.user_id}>
<img className='avatar' src={urlForLocal(person.user.avatar)} alt='avatar' />
<span>{person.user.fio}</span>
<img className='delete' src={close} alt='delete' onClick={() => deletePerson(person.user_id)}/>
</div>
})
}
</div>
<div className='persons__list__add'
onClick={() => {
dispatch(modalToggle("addWorker"));
setModalAddWorker(true);
setPersonListOpen(false)
}}
>
<span className='addPerson'>+</span>
<p>Добавить участников</p>
</div>
</div>
}
</div>
<div className="tasks__head__select">
<span>Учавствую</span>
@ -195,7 +276,7 @@ export const TicketFullScreen = ({}) => {
{editOpen ? <input value={inputsValue.description} onChange={(e) => {
setInputsValue((prevValue) => ({...prevValue, description: e.target.value}))
}}/> :<p>{inputsValue.description}</p>}
<img src={task} className="image-task"></img>
{/*<img src={task} className="image-task"></img>*/}
</div>
<div className="content__communication">
<p className="tasks">
@ -222,7 +303,30 @@ export const TicketFullScreen = ({}) => {
<input placeholder="Оставить комментарий" value={inputsValue.comment} onChange={(e) => {
setInputsValue((prevValue) => ({...prevValue, comment: e.target.value}))
}} />
<img src={send} onClick={editComment}></img>
<img src={send} onClick={createComment}></img>
</div>
<div className='comments__list'>
{comments.map((comment) => {
return <div className='comments__list__item' key={comment.id}>
<div className='comments__list__item__info'>
<span>{getCorrectDate(comment.created_at)}</span>
<div className={commentsEditOpen[comment.id] ? 'edit edit__open' : 'edit'} >
<img src={edit} alt='edit' onClick={() => {
if (commentsEditOpen[comment.id]) {
editComment(comment.id)
}
setCommentsEditOpen((prevValue) => ({...prevValue, [comment.id]: !prevValue[comment.id]}))
}} />
</div>
<img src={del} alt='delete' onClick={() => deleteComment(comment.id)} />
</div>
{commentsEditOpen[comment.id] ? <input value={commentsEditText[comment.id]} onChange={(e) => {
setCommentsEditText((prevValue) => ({...prevValue, [comment.id]: e.target.value}))
}} /> : <p>{commentsEditText[comment.id]}</p>}
</div>
})
}
</div>
</div>
</div>

View File

@ -12,7 +12,8 @@ import {
editProjectName,
editColumnName,
getColumnName,
getColumnId
getColumnId,
addPersonToProject
} from "../../../redux/projectsTrackerSlice";
import arrowDown from "../../../images/selectArrow.png"
@ -136,12 +137,13 @@ 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)
})
}
@ -149,10 +151,14 @@ export const TrackerModal = ({
useEffect(() => {
modalType === "addWorker" ? apiRequest('/project/my-employee').then((el) => {
let persons = el.managerEmployees
projectBoard.projectUsers.forEach(person => persons.splice(persons.indexOf(person), 1))
setWorkers(persons)
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
}, []))
}) : ''
}, [modalType])
}, [active])
return (
<div
@ -178,21 +184,24 @@ export const TrackerModal = ({
<p>{selectedWorker ? selectedWorker.employee.fio : 'Выберите пользователя'}</p>
<img className='arrow' src={arrowDown} alt='arrow' />
{Boolean(selectWorkersOpen) &&
<div className='select__worker__dropDown'>
{workers.map((worker) => {
if ((workers.length === 1 || 0) && worker === selectedWorker) {
return <p>Пользователей нет</p>
<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)
}
}>
<p>{worker.employee.fio}</p>
<img src={urlForLocal(worker.employee.avatar)} alt='avatar'/>
</div>
}) :
<div>Нет пользователей</div>
}
if (worker === selectedWorker) {
return
}
return <div className='worker' key={worker.id} onClick={() => setSelectedWorker(worker)}>
<p>{worker.employee.fio}</p>
<img src={urlForLocal(worker.employee.avatar)} alt='avatar'/>
</div>
})
}
</div>
</div>
}
</div>
</div>