Fixed tracker card
This commit is contained in:
193
src/components/TrackerCardTask/TrackerCardTask.jsx
Normal file
193
src/components/TrackerCardTask/TrackerCardTask.jsx
Normal file
@ -0,0 +1,193 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
import { movePositionProjectTask } from "@redux/projectsTrackerSlice";
|
||||
|
||||
import { getCorrectDate } from "@utils/calendarHelper";
|
||||
import { removeLast, urlForLocal } from "@utils/helper";
|
||||
|
||||
import TrackerSelectColumn from "@components/TrackerSelectColumn/TrackerSelectColumn";
|
||||
|
||||
import commentsBoard from "assets/icons/commentsBoard.svg";
|
||||
import filesBoard from "assets/icons/filesBoard.svg";
|
||||
import avatarMok from "assets/images/avatarMok.png";
|
||||
|
||||
import "./trackerCardTask.scss";
|
||||
|
||||
const TrackerCardTask = ({
|
||||
task,
|
||||
projectBoard,
|
||||
titleColor,
|
||||
column,
|
||||
openTicket,
|
||||
startWrapperIndexTest,
|
||||
setWrapperHover
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [taskHover, setTaskHover] = useState({});
|
||||
|
||||
const priority = {
|
||||
2: "Высокий",
|
||||
1: "Средний",
|
||||
0: "Низкий"
|
||||
};
|
||||
|
||||
const priorityClass = {
|
||||
2: "high",
|
||||
1: "middle",
|
||||
0: "low"
|
||||
};
|
||||
|
||||
function dragDropTaskHandler(e, task, column) {
|
||||
e.preventDefault();
|
||||
if (task.id === startWrapperIndexTest.current.task.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const finishTask = column.tasks.indexOf(task);
|
||||
|
||||
dispatch(
|
||||
movePositionProjectTask({
|
||||
startTask: startWrapperIndexTest.current.task,
|
||||
finishTask: task,
|
||||
finishIndex: finishTask
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function dragOverTaskHandler(e, task) {
|
||||
e.preventDefault();
|
||||
if (startWrapperIndexTest.current.task.id === task.id) {
|
||||
return;
|
||||
}
|
||||
setTaskHover((prevState) => ({ [prevState]: false, [task.id]: true }));
|
||||
}
|
||||
|
||||
function dragStartHandler(e, task, columnId) {
|
||||
startWrapperIndexTest.current = { task: task, index: columnId };
|
||||
}
|
||||
|
||||
function dragLeaveTaskHandler() {
|
||||
setTaskHover((prevState) => ({ [prevState]: false }));
|
||||
}
|
||||
|
||||
function dragEndTaskHandler() {
|
||||
setTaskHover((prevState) => ({ [prevState]: false }));
|
||||
setWrapperHover((prevState) => ({
|
||||
[prevState]: false
|
||||
}));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const tasksHover = {};
|
||||
const columnHover = {};
|
||||
|
||||
if (Object.keys(projectBoard).length) {
|
||||
projectBoard.columns.forEach((column) => {
|
||||
columnHover[column.id] = false;
|
||||
column.tasks.forEach((task) => (tasksHover[task.id] = false));
|
||||
});
|
||||
}
|
||||
setWrapperHover(columnHover);
|
||||
setTaskHover(tasksHover);
|
||||
}, [projectBoard]);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={task.id}
|
||||
className={`tasks__board__item ${
|
||||
taskHover[task.id] ? "task__hover" : ""
|
||||
}`}
|
||||
draggable={true}
|
||||
onDragStart={(e) => dragStartHandler(e, task, column.id)}
|
||||
onDragOver={(e) => dragOverTaskHandler(e, task)}
|
||||
onDragLeave={(e) => dragLeaveTaskHandler(e)}
|
||||
onDragEnd={() => dragEndTaskHandler()}
|
||||
onDrop={(e) => dragDropTaskHandler(e, task, column)}
|
||||
onClick={(e) => openTicket(e, task)}
|
||||
>
|
||||
<div
|
||||
className="tasks__board__item__title"
|
||||
onClick={() => {
|
||||
if (window.innerWidth < 985) {
|
||||
window.location.replace(`/tracker/task/${task.id}`);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<p className="task__board__item__title">{task.title}</p>
|
||||
</div>
|
||||
<p
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: task.description
|
||||
}}
|
||||
className="tasks__board__item__description"
|
||||
></p>
|
||||
{Boolean(task.mark.length) && (
|
||||
<div className="tasks__board__item__tags">
|
||||
{task.mark.map((tag) => {
|
||||
return (
|
||||
<div
|
||||
className="tag-item"
|
||||
key={tag.id}
|
||||
style={{ background: tag.color }}
|
||||
>
|
||||
<p>{tag.slug}</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<div className="tasks__board__item__container">
|
||||
{typeof task.execution_priority === "number" && (
|
||||
<div className="tasks__board__item__priority">
|
||||
<p>⚡</p>
|
||||
<span className={priorityClass[task.execution_priority]}>
|
||||
{priority[task.execution_priority]}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{task.dead_line && (
|
||||
<div className="tasks__board__item__dead-line">
|
||||
<p>⌛</p>
|
||||
<span style={{ color: titleColor }}>
|
||||
{getCorrectDate(task.dead_line)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="tasks__board__item__info">
|
||||
<div className="tasks__board__item__executor">
|
||||
<img
|
||||
src={
|
||||
task.executor?.avatar
|
||||
? urlForLocal(task.executor?.avatar)
|
||||
: avatarMok
|
||||
}
|
||||
alt="avatar"
|
||||
/>
|
||||
<span>
|
||||
{removeLast(task.executor?.fio) || "Исполнитель не назначен"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="tasks__board__item__info__tags">
|
||||
<div className="tasks__board__item__info__more">
|
||||
<img src={commentsBoard} alt="commentsImg" />
|
||||
<span>{task.comment_count}</span>
|
||||
</div>
|
||||
<div className="tasks__board__item__info__more">
|
||||
<img src={filesBoard} alt="filesImg" />
|
||||
<span>{task.file_count}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<TrackerSelectColumn
|
||||
columns={projectBoard.columns.filter((item) => item.id !== column.id)}
|
||||
currentColumn={column}
|
||||
task={task}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TrackerCardTask;
|
365
src/components/TrackerCardTask/trackerCardTask.scss
Normal file
365
src/components/TrackerCardTask/trackerCardTask.scss
Normal file
@ -0,0 +1,365 @@
|
||||
.tasks {
|
||||
&__board {
|
||||
background: #f5f7f9;
|
||||
box-shadow: 0px 2px 5px rgba(60, 66, 87, 0.04),
|
||||
0px 0px 0px 1px rgba(60, 66, 87, 0.08), 0px 1px 1px rgba(0, 0, 0, 0.06);
|
||||
border-radius: 8px;
|
||||
padding: 12px 10px 12px 8px;
|
||||
width: 360px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 10px;
|
||||
height: fit-content;
|
||||
position: relative;
|
||||
transition: all 0.3s ease;
|
||||
transform: scaleY(-1);
|
||||
min-height: 815px;
|
||||
|
||||
@media (max-width: 900px) {
|
||||
min-width: auto;
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
transform: scaleX(1);
|
||||
}
|
||||
|
||||
.tasks-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 8px;
|
||||
max-height: 750px;
|
||||
overflow: auto;
|
||||
padding: 5px;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 3px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #cbd9f9;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #c5c0c6;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
&__hover {
|
||||
box-shadow: 0px 2px 10px #9cc480, 0px 0px 0px 1px rgba(60, 66, 87, 0.08),
|
||||
0px 1px 1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.task__hover {
|
||||
box-shadow: 0 0 5px gray;
|
||||
}
|
||||
|
||||
&__item {
|
||||
width: 328px;
|
||||
padding: 6px 10px 8px 10px;
|
||||
position: relative;
|
||||
box-shadow: 0px 3px 2px -2px rgba(0, 0, 0, 0.06),
|
||||
0px 5px 3px -2px rgba(0, 0, 0, 0.02);
|
||||
border-radius: 6px;
|
||||
background: #ffffff;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
transition: 0.4s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.025);
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
width: 100%;
|
||||
max-height: none;
|
||||
|
||||
&:hover {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__hide {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&__title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
|
||||
p {
|
||||
color: #1a1919;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
line-height: 20px;
|
||||
margin-bottom: 0;
|
||||
max-height: 100px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 3;
|
||||
}
|
||||
|
||||
span {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
border-radius: 6px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
padding-bottom: 10px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 1px solid #dddddd;
|
||||
}
|
||||
}
|
||||
|
||||
&__description {
|
||||
margin: 4px 0;
|
||||
color: #5c6165;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 120%;
|
||||
max-height: 100px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
&__container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__info {
|
||||
display: flex;
|
||||
column-gap: 10px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
pointer-events: none;
|
||||
margin-top: 5px;
|
||||
|
||||
&__tags {
|
||||
display: flex;
|
||||
column-gap: 5px;
|
||||
}
|
||||
|
||||
&__more {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
span {
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
color: #6e7c87;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&__avatars {
|
||||
position: relative;
|
||||
img {
|
||||
position: relative;
|
||||
}
|
||||
img:first-child {
|
||||
right: -15px;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__priority {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 5px;
|
||||
margin-top: 3px;
|
||||
|
||||
p {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.high {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.middle {
|
||||
color: #cece00;
|
||||
}
|
||||
|
||||
.low {
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
|
||||
&__dead-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 5px;
|
||||
|
||||
p {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: #1458dd;
|
||||
}
|
||||
|
||||
span {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
img {
|
||||
margin-top: -2px;
|
||||
width: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
&__executor {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
column-gap: 5px;
|
||||
|
||||
span {
|
||||
max-width: 210px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
&__tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
column-gap: 6px;
|
||||
row-gap: 3px;
|
||||
margin: 3px 0;
|
||||
|
||||
.tag-item {
|
||||
padding: 3px 10px;
|
||||
border-radius: 10px;
|
||||
color: white;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.open-items {
|
||||
cursor: pointer;
|
||||
border-radius: 44px;
|
||||
width: 33px;
|
||||
height: 33px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
bottom: -15px;
|
||||
font-size: 20px;
|
||||
left: 165px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.more-items {
|
||||
background: #8bcc60;
|
||||
}
|
||||
|
||||
.less-items {
|
||||
background: #f92828;
|
||||
}
|
||||
|
||||
&__more {
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
.column__select {
|
||||
position: absolute;
|
||||
padding: 15px;
|
||||
background: #e1fccf;
|
||||
border-radius: 12px;
|
||||
right: -20px;
|
||||
top: 5px;
|
||||
z-index: 7;
|
||||
row-gap: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@media (max-width: 910px) {
|
||||
right: 10px;
|
||||
top: 40px;
|
||||
}
|
||||
|
||||
&__item {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
img {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__no-items {
|
||||
font-weight: 500;
|
||||
font-size: 25px;
|
||||
transform: scaleY(-1);
|
||||
|
||||
@media (max-width: 900px) {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__no-tasks {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transform: scaleY(-1);
|
||||
|
||||
&-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
img {
|
||||
width: 27px;
|
||||
height: 27px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-weight: 700;
|
||||
font-size: 22px;
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
&-more {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user