This commit is contained in:
Mikola 2023-10-24 22:49:12 +03:00
parent 5f92d86bd9
commit c4a4fa1333
5 changed files with 292 additions and 1 deletions

10
package-lock.json generated
View File

@ -26,6 +26,7 @@
"react": "^18.2.0",
"react-app-polyfill": "^2.0.0",
"react-bootstrap": "^1.6.0",
"react-colorful": "^5.6.1",
"react-datepicker": "^4.10.0",
"react-dev-utils": "^12.0.1",
"react-dom": "^18.2.0",
@ -20725,6 +20726,15 @@
"react-dom": ">=16.8.0"
}
},
"node_modules/react-colorful": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz",
"integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==",
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/react-datepicker": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-4.10.0.tgz",

View File

@ -22,6 +22,7 @@
"react": "^18.2.0",
"react-app-polyfill": "^2.0.0",
"react-bootstrap": "^1.6.0",
"react-colorful": "^5.6.1",
"react-datepicker": "^4.10.0",
"react-dev-utils": "^12.0.1",
"react-dom": "^18.2.0",

View File

@ -1,10 +1,14 @@
import React, { useEffect, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Link, useParams } from "react-router-dom";
import {
HexColorPicker
} from "react-colorful";
import {
activeLoader,
deletePersonOnProject,
addNewTagToProject,
filterCreatedByMe,
filteredExecutorTasks,
filteredParticipateTasks,
@ -51,6 +55,7 @@ import accept from "assets/images/accept.png";
import archive from "assets/images/archiveIcon.png";
import avatarMok from "assets/images/avatarMok.png";
import { getCorrectDate } from "../../components/Calendar/calendarHelper";
export const ProjectTracker = () => {
@ -66,6 +71,12 @@ export const ProjectTracker = () => {
const [modalActiveTicket, setModalActiveTicket] = useState(false);
const [selectedTicket, setSelectedTicket] = useState({});
const [personListOpen, setPersonListOpen] = useState(false);
const [tags, setTags] = useState({
open: false,
add: false
})
const [color, setColor] = useState("#aabbcc");
const [tagInfo, setTagInfo] = useState({description: '', name: ''})
const [checkBoxParticipateTasks, setCheckBoxParticipateTasks] =
useState(false);
const [filteredNoTasks, setFilteredNoTasks] = useState(false);
@ -283,6 +294,33 @@ export const ProjectTracker = () => {
dispatch(setProjectBoardFetch(projectId.id));
}
function addNewTag () {
apiRequest("/mark/create", {
method: "POST",
data: {
title: tagInfo.description,
slug: tagInfo.name,
color: color,
status: 1
},
}).then((data) => {
apiRequest("/mark/attach", {
method: "POST",
data: {
mark_id: data.id,
entity_type: 1,
entity_id: projectId.id
}
}).then((data) => {
dispatch(addNewTagToProject(data.mark))
setTags((prevState) => ({
...prevState,
add: false
}))
})
})
}
return (
<div className="tracker">
<ProfileHeader />
@ -531,6 +569,87 @@ export const ProjectTracker = () => {
)}
</div>
)}
<div className="tasks__head__tags">
<div className='tags__add' onClick={() => {
setTags((prevState) => ({
...prevState,
open: !tags.open
}))
}}>
<p>Список тегов</p>
<span>+</span>
</div>
{tags.open &&
<div className='tags__list'>
<img src={close} className='close' alt='close' onClick={() => {
setTags((prevState) => ({
...prevState,
open: false
}))
}} />
{!tags.add &&
<div className='tags__list__created'>
{projectBoard.mark.map((tag) => {
return <div className='tagItem' key={tag.id}>
<p className='tagItem__description'>
{tag.title}
</p>
<div className='tagItem__info'>
<span className='tagItem__info__name'>{tag.slug}</span>
<span className='tagItem__info__color' style={{background: tag.color}}/>
</div>
</div>
})
}
<div className='addNewTag' onClick={() => setTags((prevState) => ({...prevState, add: true}))}>
<p>
Добавить новый тег
</p>
<span>
+
</span>
</div>
</div>
}
{tags.add &&
<div className='formTag'>
<img src={arrow} className='arrow' alt='arrow' onClick={() => {
setTags((prevState) => ({
...prevState,
add: false
}))
}}/>
<input
className='formTag__input'
placeholder='Описание метки'
maxLength="25"
value={tagInfo.description}
onChange={(e) => setTagInfo(prevState => ({
...prevState,
description: e.target.value
}))}
/>
<input
className='formTag__input'
placeholder='Тег'
value={tagInfo.name}
maxLength="10"
onChange={(e) => setTagInfo(prevState => ({
...prevState,
name: e.target.value
}))}
/>
<HexColorPicker color={color} onChange={setColor} />
<button
onClick={addNewTag}
className={tagInfo.name && tagInfo.description ? 'formTag__btn' : 'formTag__btn disable'}>
Добавить
</button>
</div>
}
</div>
}
</div>
<Link to="/profile/tracker" className="tasks__head__back">
<p>Вернуться на проекты</p>
<img src={arrow} alt="arrow" />

View File

@ -236,7 +236,7 @@
&__wrapper {
display: flex;
max-width: 1280px;
max-width: 1400px;
width: 100%;
margin: 0 auto;
justify-content: space-between;
@ -746,6 +746,163 @@
display: none;
}
}
&__tags {
position: relative;
.tags {
&__add {
display: flex;
align-items: center;
margin: 0 10px;
column-gap: 5px;
cursor: pointer;
padding: 4px;
border-radius: 8px;
border: 1px solid #e3e2e2;
max-height: 30px;
p {
white-space: nowrap;
font-weight: 400;
font-size: 14px;
line-height: 17px;
}
span {
width: 14px;
height: 14px;
font-weight: 400;
line-height: 16px;
border-radius: 50px;
align-items: center;
justify-content: center;
display: flex;
background: #cbd9f9;
color: white;
font-size: 14px;
transition: all 0.15s ease;
}
}
&__list {
position: absolute;
background: #f8f9fa;
z-index: 20;
border-radius: 8px;
padding: 20px 10px 10px;
top: 30px;
width: 220px;
display: flex;
flex-direction: column;
.close {
cursor: pointer;
width: 20px;
height: 20px;
position: absolute;
right: 10px;
top: 2px;
}
&__created {
display: flex;
flex-direction: column;
row-gap: 8px;
margin-top: 8px;
.tagItem {
display: flex;
flex-direction: column;
padding: 5px;
border: 1px solid #e3e2e2;
border-radius: 8px;
&__description {
font-size: 14px;
}
&__info {
display: flex;
align-items: center;
column-gap: 10px;
&__name {
font-size: 16px;
font-weight: 600;
}
&__color {
border: 1px solid #e3e2e2;
width: 20px;
height: 20px;
border-radius: 50px;
}
}
}
}
.addNewTag {
display: flex;
align-items: center;
column-gap: 8px;
cursor: pointer;
justify-content: center;
p {
font-size: 13px;
}
span {
width: 16px;
height: 16px;
border-radius: 50px;
align-items: center;
justify-content: center;
display: flex;
background: #52b709;
color: white;
font-size: 16px;
transition: all 0.15s ease;
}
}
.formTag {
display: flex;
flex-direction: column;
padding-top: 8px;
row-gap: 8px;
.arrow {
position: absolute;
cursor: pointer;
top: 5px;
width: 15px;
height: 15px;
transform: rotate(180deg);
}
&__input {
outline: none;
border-radius: 8px;
border: 1px solid #e3e2e2;
font-size: 15px;
padding: 5px;
}
&__btn {
outline: none;
border: none;
background: #6f6f6f;
color: whitesmoke;
margin: 0 auto;
border-radius: 10px;
font-size: 15px;
}
.disable {
opacity: 0.5;
pointer-events: none;
}
}
}
}
}
}
&__container {

View File

@ -45,6 +45,9 @@ export const projectsTrackerSlice = createSlice({
addPersonToProject: (state, action) => {
state.projectBoard.projectUsers.push(action.payload);
},
addNewTagToProject: (state, action) => {
state.projectBoard.mark.push(action.payload)
},
activeLoader: (state) => {
state.boardLoader = true;
},
@ -179,6 +182,7 @@ export const {
setColumnPriority,
deletePersonOnProject,
addPersonToProject,
addNewTagToProject,
filterCreatedByMe,
filteredParticipateTasks,
filteredExecutorTasks,