modal accept with notifications

This commit is contained in:
2023-07-14 03:03:33 +03:00
parent 242f298bee
commit 001920a840
17 changed files with 310 additions and 25 deletions

View File

@ -0,0 +1,24 @@
import React from "react";
import close from "assets/icons/closeProjectPersons.svg";
import './acceptModal.scss'
export const AcceptModal = ({closeModal, agreeHandler}) => {
return (
<div className='backDrop'>
<div className='acceptModal'>
<h3 className='acceptModal__title'>
Вы точно хотите переместить задачу в архив?
</h3>
<div className='acceptModal__buttons'>
<button className='agree' onClick={agreeHandler}>Да</button>
<button className='cancel' onClick={closeModal}>Нет</button>
</div>
<img className='acceptModal__close' src={close} alt='close' onClick={closeModal} />
</div>
</div>
)
}
export default AcceptModal

View File

@ -0,0 +1,61 @@
.backDrop {
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.11);
position: fixed;
top: 0;
left: 0;
display: flex;
z-index: 11;
align-items: center;
justify-content: center;
.acceptModal {
border-radius: 20px;
background: linear-gradient(180deg, #FFF 0%, #EBEBEB 100%);
padding: 50px 34px 25px;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
row-gap: 25px;
&__title {
max-width: 260px;
font-size: 18px;
font-weight: 500;
text-align: center;
margin-bottom: 0;
}
&__buttons {
display: flex;
column-gap: 20px;
button {
min-width: 90px;
height: 37px;
border-radius: 44px;
border: none;
font-size: 14px;
font-weight: 500;
color: white;
}
.agree {
background: #52B709;
}
.cancel {
background: #B0BABF;
}
}
&__close {
position: absolute;
top: 15px;
right: 22px;
cursor: pointer;
}
}
}

View File

@ -9,6 +9,7 @@ import { Link } from "react-router-dom";
import { getProfileInfo } from "@redux/outstaffingSlice";
import { setProjectBoardFetch } from "@redux/projectsTrackerSlice";
import { useNotification } from "@hooks/useNotification";
import {
backendImg,
@ -22,6 +23,7 @@ import { apiRequest } from "@api/request";
import TrackerModal from "@components/Modal/Tracker/TrackerModal/TrackerModal";
import TrackerTaskComment from "@components/TrackerTaskComment/TrackerTaskComment";
import AcceptModal from "@components/Modal/AcceptModal/AcceptModal";
import archive from "assets/icons/archive.svg";
import arrow from "assets/icons/arrows/arrowStart.png";
@ -82,6 +84,8 @@ export const ModalTiсket = ({
const [correctProjectUsers, setCorrectProjectUsers] = useState(projectUsers);
const [executorId, setExecutorId] = useState(task.executor_id);
const profileInfo = useSelector(getProfileInfo);
const [acceptModalOpen, setAcceptModalOpen] = useState(false)
const { showNotification } = useNotification()
function deleteTask() {
apiRequest("/task/update-task", {
@ -93,9 +97,14 @@ export const ModalTiсket = ({
}).then(() => {
setActive(false);
dispatch(setProjectBoardFetch(projectId));
showNotification({show: true, text: 'Задача успешно была перемещена в архив', type: 'archive'})
});
}
function archiveTask () {
setAcceptModalOpen(true)
}
function editTask() {
apiRequest("/task/update-task", {
method: "PUT",
@ -416,6 +425,7 @@ export const ModalTiсket = ({
navigator.clipboard.writeText(
`https://itguild.info/tracker/task/${task.id}`
);
showNotification({show: true, text: 'Ссылка скопирована в буфер обмена', type: 'copy'})
}
function selectDeadLine(date) {
@ -430,6 +440,10 @@ export const ModalTiсket = ({
});
}
function closeAcceptModal () {
setAcceptModalOpen(false)
}
return (
<div
className={active ? "modal-tiket active" : "modal-tiket"}
@ -809,7 +823,7 @@ export const ModalTiсket = ({
<img src={link}></img>
<p onClick={copyTicketLink}>ссылка на задачу</p>
</div>
<div onClick={deleteTask}>
<div onClick={archiveTask}>
<img src={archive}></img>
<p>в архив</p>
</div>
@ -819,8 +833,13 @@ export const ModalTiсket = ({
</div>
</div>
</div>
{acceptModalOpen &&
<AcceptModal
closeModal={closeAcceptModal}
agreeHandler={deleteTask}
/>
}
</div>
<TrackerModal
active={addSubtask}
setActive={setAddSubtask}

View File

@ -689,6 +689,7 @@
.react-datepicker-popper {
top: 10px !important;
left: -110px !important;
z-index: 10;
}
.react-datepicker__current-month {

View File

@ -31,6 +31,7 @@ import { Navigation } from "@components/Navigation/Navigation";
import { ProfileBreadcrumbs } from "@components/ProfileBreadcrumbs/ProfileBreadcrumbs";
import { ProfileHeader } from "@components/ProfileHeader/ProfileHeader";
import TrackerTaskComment from "@components/TrackerTaskComment/TrackerTaskComment";
import AcceptModal from "@components/Modal/AcceptModal/AcceptModal";
import arrow from "assets/icons/arrows/arrowCalendar.png";
import arrowStart from "assets/icons/arrows/arrowStart.png";
@ -82,6 +83,7 @@ export const TicketFullScreen = () => {
const [startDate, setStartDate] = useState(null);
const [uploadedFile, setUploadedFile] = useState(null);
const [taskFiles, setTaskFiles] = useState([]);
const [acceptModalOpen, setAcceptModalOpen] = useState(false)
useEffect(() => {
apiRequest(`/task/get-task?task_id=${ticketId.id}`).then((taskInfo) => {
@ -161,6 +163,10 @@ export const TicketFullScreen = () => {
});
}
function archiveTask () {
setAcceptModalOpen(true)
}
function editTask() {
apiRequest("/task/update-task", {
method: "PUT",
@ -450,6 +456,10 @@ export const TicketFullScreen = () => {
});
}
function closeAcceptModal () {
setAcceptModalOpen(false)
}
return (
<section className="ticket-full-screen">
<ProfileHeader />
@ -976,7 +986,7 @@ export const TicketFullScreen = () => {
<img src={link} alt="link"></img>
<p onClick={copyTicketLink}>ссылка на задачу</p>
</div>
<div>
<div onClick={archiveTask}>
<img src={archive} alt="arch"></img>
<p>в архив</p>
</div>
@ -990,6 +1000,12 @@ export const TicketFullScreen = () => {
</>
)}
</div>
{acceptModalOpen &&
<AcceptModal
closeModal={closeAcceptModal}
agreeHandler={deleteTask}
/>
}
<Footer />
</section>
);

View File

@ -30,6 +30,7 @@ import arrowDown from "assets/icons/arrows/selectArrow.png";
import avatarMok from "assets/images/avatarMok.png";
import "./trackerModal.scss";
import {useNotification} from "@hooks/useNotification";
export const TrackerModal = ({
active,
@ -67,9 +68,11 @@ export const TrackerModal = ({
const [correctProjectUsers, setCorrectProjectUsers] = useState([]);
const [selectColumnPriorityOpen, setSelectColumnPriorityOpen] =
useState(false);
const { showNotification } = useNotification()
function createTab() {
if (!valueColumn) {
showNotification({show: true, text: 'Введите название', type: 'error'})
return;
}
@ -91,6 +94,7 @@ export const TrackerModal = ({
function createTiket() {
if (!valueTiket || !descriptionTicket) {
showNotification({show: true, text: 'Введите название и описание', type: 'error'})
return;
}
@ -106,25 +110,30 @@ export const TrackerModal = ({
priority: priorityTask,
},
}).then((res) => {
if (selectedExecutorTask.user_id) {
apiRequest("/task/update-task", {
method: "PUT",
data: {
task_id: res.id,
executor_id: selectedExecutorTask.user_id,
},
}).then(() => {
dispatch(setProjectBoardFetch(projectBoard.id));
if (res.status === 500) {
showNotification({show: true, text: 'Задача с таким именем уже существует', type: 'error'})
} else {
if (selectedExecutorTask.user_id) {
apiRequest("/task/update-task", {
method: "PUT",
data: {
task_id: res.id,
executor_id: selectedExecutorTask.user_id,
},
}).then(() => {
dispatch(setProjectBoardFetch(projectBoard.id));
setActive(false);
setValueTiket("");
setDescriptionTicket("Описание задачи");
setSelectedExecutorTask("Выберите исполнителя задачи");
});
} else {
setActive(false);
setValueTiket("");
setDescriptionTicket("Описание задачи");
setSelectedExecutorTask("Выберите исполнителя задачи");
});
} else {
setActive(false);
setValueTiket("");
setDescriptionTicket("Описание задачи");
dispatch(setProjectBoardFetch(projectBoard.id));
dispatch(setProjectBoardFetch(projectBoard.id));
}
showNotification({show: true, text: 'Задача создана', type: 'success'})
}
});
}
@ -204,10 +213,14 @@ export const TrackerModal = ({
status: 19,
},
}).then((res) => {
const result = { ...res, columns: [] };
dispatch(setProject(result));
setActive(false);
setNameProject("");
if (!Array.isArray(res.name)) {
const result = { ...res, columns: [] };
dispatch(setProject(result));
setActive(false);
setNameProject("");
} else {
showNotification({show: true, text: 'Проект с таким именем уже существует', type: 'error'})
}
});
}
}

View File

@ -0,0 +1,36 @@
import React from "react";
import {useDispatch, useSelector} from "react-redux";
import { closeNotification, getNotification } from "@redux/outstaffingSlice";
import close from "assets/icons/closeProjectPersons.svg";
import copy from "assets/icons/copyNotification.svg";
import error from "assets/icons/errorNotification.svg";
import archive from "assets/icons/archiveNotification.svg";
import success from "assets/icons/successNotification.svg"
const images = {
archive: archive,
error: error,
copy: copy,
success: success
}
import './notification.scss'
export const Notification = () => {
const dispatch = useDispatch();
const notificationInfo = useSelector(getNotification)
return (
<div className='notification'>
<div className='notification__info'>
<img src={images[notificationInfo.type]} alt='img' />
<h2>{notificationInfo.text}</h2>
</div>
<img onClick={() => dispatch(closeNotification())}
className='notification__close' src={close} alt='close' />
</div>
)
}
export default Notification

View File

@ -0,0 +1,35 @@
.notification {
border-radius: 40px;
background: linear-gradient(180deg, #FFF 0%, #EBEBEB 100%);
padding: 20px 82px 17px 27px;
position: fixed;
bottom: 25px;
right: 25px;
z-index: 20;
&__info {
display: flex;
column-gap: 10px;
align-items: center;
h2 {
max-width: 194px;
font-weight: 500;
font-size: 16px;
margin-bottom: 0;
}
img {
max-width: 24px;
}
}
&__close {
cursor: pointer;
position: absolute;
top: 15px;
right: 25px;
width: 15px;
height: 15px;
}
}

View File

@ -3,11 +3,13 @@ import { useDispatch } from "react-redux";
import { Link } from "react-router-dom";
import { deleteProject, modalToggle } from "@redux/projectsTrackerSlice";
import {useNotification} from "@hooks/useNotification";
import { apiRequest } from "@api/request";
import { ModalSelect } from "@components/Modal/ModalSelect/ModalSelect";
import TrackerModal from "@components/Modal/Tracker/TrackerModal/TrackerModal";
import AcceptModal from "@components/Modal/AcceptModal/AcceptModal"
import archiveSet from "assets/icons/archive.svg";
import del from "assets/icons/delete.svg";
@ -19,7 +21,9 @@ import "./projectTiket.scss";
export const ProjectTiket = ({ project, index }) => {
const [modalSelect, setModalSelect] = useState(false);
const [modalAdd, setModalAdd] = useState(false);
const [acceptModalOpen, setAcceptModalOpen] = useState(false);
const dispatch = useDispatch();
const { showNotification } = useNotification()
useEffect(() => {
initListeners();
@ -49,6 +53,7 @@ export const ProjectTiket = ({ project, index }) => {
},
}).then(() => {
dispatch(deleteProject(project));
showNotification({show: true, text: 'Проект успешно была перемещена в архив', type: 'archive'});
});
}
@ -58,6 +63,10 @@ export const ProjectTiket = ({ project, index }) => {
);
}
function closeAcceptModal () {
setAcceptModalOpen(false)
}
return (
<div className="project" key={index}>
<Link to={`/tracker/project/${project.id}`}>{project.name}</Link>
@ -98,7 +107,10 @@ export const ProjectTiket = ({ project, index }) => {
<img src={link}></img>
<p onClick={copyProjectLink}>ссылка на проект</p>
</div>
<div>
<div onClick={() => {
setModalSelect(false)
setAcceptModalOpen(true)
}}>
<img src={archiveSet}></img>
<p>в архив</p>
</div>
@ -108,6 +120,12 @@ export const ProjectTiket = ({ project, index }) => {
</div>
</div>
</ModalSelect>
{acceptModalOpen &&
<AcceptModal
closeModal={closeAcceptModal}
agreeHandler={removeProject}
/>
}
</div>
);
};