Create new component TrackerTagList
This commit is contained in:
@ -0,0 +1,129 @@
|
||||
.tasks {
|
||||
&__head {
|
||||
&__executor {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e3e2e2;
|
||||
padding: 2px 6px;
|
||||
position: relative;
|
||||
max-width: 190px;
|
||||
width: 100%;
|
||||
|
||||
@media (max-width: 915px) {
|
||||
margin-right: 0;
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
@media (max-width: 650px) {
|
||||
border-color: gray;
|
||||
}
|
||||
|
||||
&-selected {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
max-width: 220px;
|
||||
width: 100%;
|
||||
margin-right: 10px;
|
||||
justify-content: center;
|
||||
|
||||
p {
|
||||
color: #252c32;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
max-width: 155px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.delete {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img {
|
||||
display: flex;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 915px) {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
justify-content: start;
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
p {
|
||||
color: #252c32;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
img {
|
||||
transition: all 0.15s ease;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.open {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
&-dropdown {
|
||||
position: absolute;
|
||||
top: 33px;
|
||||
left: 0;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
z-index: 5;
|
||||
padding: 10px 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 7px;
|
||||
width: 100%;
|
||||
|
||||
.executor-dropdown__person {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
p {
|
||||
max-width: 155px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
@media (max-width: 915px) {
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
p {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
273
src/components/TrackerTagList/TrackerTagList.jsx
Normal file
273
src/components/TrackerTagList/TrackerTagList.jsx
Normal file
@ -0,0 +1,273 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { HexColorPicker } from "react-colorful";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
import {
|
||||
addNewTagToProject,
|
||||
deleteTagProject,
|
||||
setProjectBoardFetch
|
||||
} from "@redux/projectsTrackerSlice";
|
||||
|
||||
import { apiRequest } from "@api/request";
|
||||
|
||||
import { useNotification } from "@hooks/useNotification";
|
||||
|
||||
import arrowDown from "assets/icons/arrows/selectArrow.png";
|
||||
import close from "assets/icons/close.png";
|
||||
import edit from "assets/icons/edit.svg";
|
||||
|
||||
const TrackerTagList = ({ projectBoard }) => {
|
||||
const dispatch = useDispatch();
|
||||
const projectId = useParams();
|
||||
|
||||
const { showNotification } = useNotification();
|
||||
const [tagInfo, setTagInfo] = useState({ description: "", name: "" });
|
||||
const [color, setColor] = useState("#aabbcc");
|
||||
const [tags, setTags] = useState({
|
||||
open: false,
|
||||
add: false,
|
||||
edit: false
|
||||
});
|
||||
|
||||
function deleteTag(tagId) {
|
||||
apiRequest("/mark/detach", {
|
||||
method: "DELETE",
|
||||
data: {
|
||||
mark_id: tagId,
|
||||
entity_type: 1,
|
||||
entity_id: projectId.id
|
||||
}
|
||||
}).then(() => {
|
||||
dispatch(deleteTagProject(tagId));
|
||||
showNotification({
|
||||
show: true,
|
||||
text: "Тег удален",
|
||||
type: "success"
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
}));
|
||||
showNotification({
|
||||
show: true,
|
||||
text: "Тег успешно создан",
|
||||
type: "success"
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function editTag() {
|
||||
apiRequest("/mark/update", {
|
||||
method: "PUT",
|
||||
data: {
|
||||
mark_id: tagInfo.editMarkId,
|
||||
title: tagInfo.description,
|
||||
slug: tagInfo.name,
|
||||
color: color
|
||||
}
|
||||
}).then(() => {
|
||||
dispatch(setProjectBoardFetch(projectId.id));
|
||||
setTags((prevState) => ({
|
||||
...prevState,
|
||||
edit: false
|
||||
}));
|
||||
setTagInfo({ description: "", name: "" });
|
||||
setColor("#aabbcc");
|
||||
showNotification({
|
||||
show: true,
|
||||
text: "Тег успешно изменён",
|
||||
type: "success"
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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("tasks__head__tags") ||
|
||||
div.classList.contains("tags__list"))
|
||||
)
|
||||
) {
|
||||
setTags({ open: false, add: false, edit: false });
|
||||
setTagInfo({ description: "", name: "" });
|
||||
setColor("#aabbcc");
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
initListeners();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="tasks__head__tags">
|
||||
<div
|
||||
className="tags__add"
|
||||
onClick={() => {
|
||||
setTags((prevState) => ({
|
||||
...prevState,
|
||||
open: !tags.open
|
||||
}));
|
||||
}}
|
||||
>
|
||||
<p>Список тегов</p>
|
||||
<img className={tags.open ? "open" : ""} src={arrowDown} alt="arrow" />
|
||||
</div>
|
||||
{tags.open && (
|
||||
<div className="tags__list">
|
||||
{!tags.add && !tags.edit && (
|
||||
<div
|
||||
className="add-new-tag"
|
||||
onClick={() =>
|
||||
setTags((prevState) => ({
|
||||
...prevState,
|
||||
add: true
|
||||
}))
|
||||
}
|
||||
>
|
||||
<p>Добавить новый тег</p>
|
||||
<span>+</span>
|
||||
</div>
|
||||
)}
|
||||
{!tags.add && !tags.edit && (
|
||||
<div className="tags__list__created">
|
||||
{projectBoard.mark.map((tag) => {
|
||||
return (
|
||||
<div className="tag-item" key={tag.id}>
|
||||
<div className="tag-item__info">
|
||||
<span
|
||||
className="tag-item__color"
|
||||
style={{ background: tag.color }}
|
||||
/>
|
||||
<div>
|
||||
<span className="tag-item__info__name">{tag.slug}</span>
|
||||
<p className="tag-item__description">{tag.title}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="tag-item__images">
|
||||
<img
|
||||
src={edit}
|
||||
alt="edit"
|
||||
onClick={() => {
|
||||
setTags((prevState) => ({
|
||||
...prevState,
|
||||
edit: true
|
||||
}));
|
||||
setTagInfo({
|
||||
description: tag.title,
|
||||
name: tag.slug,
|
||||
editMarkId: tag.id
|
||||
});
|
||||
setColor(tag.color);
|
||||
}}
|
||||
/>
|
||||
<img
|
||||
onClick={() => deleteTag(tag.id)}
|
||||
className="delete"
|
||||
src={close}
|
||||
alt="delete"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{(tags.add || tags.edit) && (
|
||||
<div className="form-tag">
|
||||
<input
|
||||
className="form-tag__input"
|
||||
placeholder="Описание метки"
|
||||
maxLength="25"
|
||||
value={tagInfo.description}
|
||||
onChange={(e) =>
|
||||
setTagInfo((prevState) => ({
|
||||
...prevState,
|
||||
description: e.target.value
|
||||
}))
|
||||
}
|
||||
/>
|
||||
<input
|
||||
className="form-tag__input"
|
||||
placeholder="Тег"
|
||||
value={tagInfo.name}
|
||||
maxLength="10"
|
||||
onChange={(e) =>
|
||||
setTagInfo((prevState) => ({
|
||||
...prevState,
|
||||
name: e.target.value
|
||||
}))
|
||||
}
|
||||
/>
|
||||
<HexColorPicker color={color} onChange={setColor} />
|
||||
<button
|
||||
onClick={() => {
|
||||
tags.add ? addNewTag() : editTag();
|
||||
}}
|
||||
className={
|
||||
tagInfo.name && tagInfo.description
|
||||
? "form-tag__btn"
|
||||
: "form-tag__btn disable"
|
||||
}
|
||||
>
|
||||
{tags.add ? "Добавить" : "Изменить"}
|
||||
</button>
|
||||
{(tags.add || tags.edit) && (
|
||||
<button
|
||||
className={"form-tag__btn"}
|
||||
onClick={() => {
|
||||
setTags((prevState) => ({
|
||||
...prevState,
|
||||
add: false,
|
||||
edit: false
|
||||
}));
|
||||
setTagInfo({
|
||||
description: "",
|
||||
name: ""
|
||||
});
|
||||
setColor("#aabbcc");
|
||||
}}
|
||||
>
|
||||
Отмена
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TrackerTagList;
|
0
src/components/TrackerTagList/trackerTagList.scss
Normal file
0
src/components/TrackerTagList/trackerTagList.scss
Normal file
Reference in New Issue
Block a user