diff --git a/src/components/ModalTags.tsx b/src/components/ModalTags.tsx index c885d65..5adbf6e 100644 --- a/src/components/ModalTags.tsx +++ b/src/components/ModalTags.tsx @@ -2,9 +2,11 @@ import { IAPITag } from "@/pages/profile_tasks.dto"; import apiClient from "@/services/api"; import { cn } from "@/utils/class-merge"; import { BookOpenIcon, CheckIcon, DocumentDuplicateIcon, PlusCircleIcon } from "@heroicons/react/24/outline"; +import { XMarkIcon } from "@heroicons/react/24/solid"; import { FunctionComponent } from "preact"; import { Dispatch, StateUpdater, useEffect, useRef, useState } from "preact/hooks"; import Button from "./ui/Button"; +import Dialog from "./ui/Dialog"; import ModalWindow, { ModalWindowProps } from "./ui/Modal"; export interface ITags { @@ -40,6 +42,8 @@ const ModalTags: FunctionComponent = ({ const [showSecondTags, setShowSecondTags] = useState(false); const [showAddFirstTag, setShowAddFirstTag] = useState(false); const [showAddSecondTag, setShowAddSecondTag] = useState(false); + const [showErrorDialog, setShowErrorDialog] = useState(false); + const [errorMessage, setErrorMessage] = useState([]); const addFirstTagRef = useRef(null); const addSecondTagRef = useRef(null); useEffect(() => { @@ -51,6 +55,7 @@ const ModalTags: FunctionComponent = ({ const handleCreateTag = async () => { if (!addFirstTagRef.current?.value && !addSecondTagRef.current?.value) return; + const data: { subject_name?: string; taskType_name?: string } = {}; if (addFirstTagRef.current && addFirstTagRef.current.value) data.subject_name = addFirstTagRef.current.value; if (addSecondTagRef.current && addSecondTagRef.current.value) data.taskType_name = addSecondTagRef.current.value; @@ -71,139 +76,193 @@ const ModalTags: FunctionComponent = ({ setShowAddSecondTag(false); } } + if (addFirstTagRef.current) addFirstTagRef.current.value = ""; + if (addSecondTagRef.current) addSecondTagRef.current.value = ""; + }; + + const handleDeleteTag = async (id: number) => { + const data: { subject_id?: number; taskType_id?: number } = {}; + if (showFirstTags) data.subject_id = id; + if (showSecondTags) data.taskType_id = id; + const response = await apiClient<{ error?: string }>(`/api/tags/delete_tag/`, { + method: "DELETE", + body: JSON.stringify(data), + }); + if (!response.error) { + refreshTags(); + } else { + setShowErrorDialog(true); + const match = response.error?.match(/\[(.+)\]/); + if (match) setErrorMessage(match[1].split(", ").map((s) => s.trim().replace(/'/g, ""))); + } }; return ( - { - onClose!(); - setShowFirstTags(false); - setShowSecondTags(false); - setShowAddFirstTag(false); - setShowAddSecondTag(false); - }} - className="relative h-[14rem] justify-between py-4 md:h-[14rem] md:w-[25rem]" - zIndex={70} - > -

Теги

-
- - - {showFirstTags && ( -
-
- {tagsList?.first.map((tag) => ( -
- onChange?.((prev) => { - return { ...prev, first: tag.id }; - }) - } - > + <> + +
+

+ Данный тег есть в других задачах. Поменяйте теги в них и повторите операцию. +

+

Задачи с этим тегом:

+
    + {errorMessage.map((s, i) => ( +
  • {s}
  • + ))} +
+
+
+ { + onClose!(); + setShowFirstTags(false); + setShowSecondTags(false); + setShowAddFirstTag(false); + setShowAddSecondTag(false); + }} + className="relative h-[14rem] justify-between py-4 md:h-[14rem] md:w-[25rem]" + zIndex={70} + > +

Теги

+
+ + + {showFirstTags && ( +
+
+ {tagsList?.first.map((tag) => (
+ onChange?.((prev) => { + return { ...prev, first: tag.id }; + }) + } > - ✓ +
+ ✓ +
+

{tag.name}

+ { + e.stopPropagation(); + handleDeleteTag(tag.id); + }} + />
-

{tag.name}

-
- ))} - -
- {showAddFirstTag && ( -
- - -
- )} -
- )} - {showSecondTags && ( -
-
- {tagsList?.second.map((tag) => ( -
- onChange?.((prev) => { - return { ...prev, second: tag.id }; - }) - } + ))} +
- ))} - -
- {showAddSecondTag && ( -
- - + + Добавить +
- )} -
- )} -
- + {showAddFirstTag && ( +
+ + +
+ )} +
+ )} + {showSecondTags && ( +
+
+ {tagsList?.second.map((tag) => ( +
+ onChange?.((prev) => { + return { ...prev, second: tag.id }; + }) + } + > +
+ ✓ +
+

{tag.name}

+ { + e.stopPropagation(); + handleDeleteTag(tag.id); + }} + /> +
+ ))} + +
+ {showAddSecondTag && ( +
+ + +
+ )} +
+ )} +
+ + ); }; diff --git a/src/components/ui/Dialog.tsx b/src/components/ui/Dialog.tsx index a6090a6..ac4a0ee 100644 --- a/src/components/ui/Dialog.tsx +++ b/src/components/ui/Dialog.tsx @@ -5,20 +5,21 @@ interface DialogProps { isOpen: boolean; setIsOpen: (isOpen: boolean) => void; title: string; - content: string; - onConfirm: () => void; + onConfirm?: () => void; confirmText?: string; cancelText?: string; + confirmation?: boolean; } const Dialog: FunctionComponent = ({ isOpen, setIsOpen, title, - content, - onConfirm, + children, + onConfirm = () => {}, confirmText = "Подтвердить", cancelText = "Отмена", + confirmation = true, }) => { if (!isOpen) return null; @@ -26,20 +27,28 @@ const Dialog: FunctionComponent = ({

{title}

-

{content}

+ {children}
- - + {confirmation ? ( + <> + + + + ) : ( + + )}
diff --git a/src/pages/profile_calendar.tsx b/src/pages/profile_calendar.tsx index a179943..45a1350 100644 --- a/src/pages/profile_calendar.tsx +++ b/src/pages/profile_calendar.tsx @@ -538,11 +538,12 @@ const ProfileCalendar: FunctionComponent = () => { isOpen={showDeleteDialog} setIsOpen={setShowDeleteDialog} title="Удаление задачи" - content="Вы уверены, что хотите удалить эту задачу?" onConfirm={handleDeleteTask} confirmText="Удалить" cancelText="Отмена" - /> + > +

"Вы уверены, что хотите удалить эту задачу?"

+ setCurrentDate(e ? e.value! : new Date())} diff --git a/src/pages/profile_tasks.tsx b/src/pages/profile_tasks.tsx index 52b7e8f..b9398a9 100644 --- a/src/pages/profile_tasks.tsx +++ b/src/pages/profile_tasks.tsx @@ -154,7 +154,6 @@ const ProfileTasks: FunctionComponent = () => { } if ((!editContent?.subject.id || !editContent.taskType.id) && (!tags.first || !tags.second)) { setError("subject", { message: "Выберите теги" }); - setError("taskType", { message: "Выберите теги" }); return; } @@ -631,11 +630,12 @@ const ProfileTasks: FunctionComponent = () => { isOpen={showDeleteDialog} setIsOpen={setShowDeleteDialog} title="Удаление задачи" - content="Вы уверены, что хотите удалить эту задачу?" onConfirm={handleDeleteTask} confirmText="Удалить" cancelText="Отмена" - /> + > +

"Вы уверены, что хотите удалить эту задачу?"

+ {!searchQuery && !filterTags.first && !filterTags.second && !filterTags.overdue ? ( filteredTasks.length > 0 ? ( <> @@ -892,7 +892,7 @@ const ProfileTasks: FunctionComponent = () => { {subjectChoices.find((s) => s.id === filterTags.first)?.name || "Предмет"}
{openFirstList && ( -
+
{example_tags.first.map((tag) => { return (
{ {taskTypeChoices.find((s) => s.id === filterTags.second)?.name || "Задача"}
{openSecondList && ( -
+
{example_tags.second.map((tag) => (