diff --git a/.vscode/settings.json b/.vscode/settings.json index 2dacf6c..0bbb0e8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,5 +8,6 @@ "([\"'`][^\"'`]*.*?[\"'`])", "[\"'`]([^\"'`]*).*?[\"'`]" ] - ] + ], + "editor.formatOnSave": true } \ No newline at end of file diff --git a/src/pages/profile_tasks.tsx b/src/pages/profile_tasks.tsx index da96cf0..bd8a441 100644 --- a/src/pages/profile_tasks.tsx +++ b/src/pages/profile_tasks.tsx @@ -19,9 +19,10 @@ import { MagnifyingGlassIcon, PencilIcon, TrashIcon, + XMarkIcon, } from "@heroicons/react/24/outline"; import { FunctionComponent } from "preact"; -import { useEffect, useMemo, useState } from "preact/hooks"; +import { useEffect, useMemo, useRef, useState } from "preact/hooks"; import { Nullable } from "primereact/ts-helpers"; import { SubmitHandler, useForm } from "react-hook-form"; import { v4 as uuid } from "uuid"; @@ -37,6 +38,8 @@ const ProfileTasks: FunctionComponent = () => { const [openModal, setIsOpen] = useState(false); // Открыта модалка const [openModalCalendar, setOpenModalCalendar] = useState(false); // Открыта модалка календаря const [openModalTags, setOpenModalTags] = useState(false); // Открыта модалка тегов + const [openSearchModal, setOpenSearchModal] = useState(false); // Открыто окно поиска + const [openFilterModal, setOpenFilterModal] = useState(false); const [isEdit, setIsEdit] = useState(false); // Открыта задача const [isEditModal, setIsEditModal] = useState(false); // Включено редактирование задачи const [isCreating, setIsCreating] = useState(false); // Включено создание задачи @@ -44,6 +47,10 @@ const ProfileTasks: FunctionComponent = () => { const [calendarDate, setCalendarDate] = useState>(); // Выбранная в календаре дата const [tags, setTags] = useState({ first: "", second: "" }); const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const [searchQuery, setSearchQuery] = useState(""); // Текст поиска + const [filterTags, setFilterTags] = useState({ first: "", second: "" }); + const [openFirstList, setOpenFirstList] = useState(false); + const [openSecondList, setOpenSecondList] = useState(false); const getDate = useMemo(() => { const date = new Date(); const formatter = new Intl.DateTimeFormat("ru-RU", { month: "long", day: "numeric" }); @@ -172,6 +179,35 @@ const ProfileTasks: FunctionComponent = () => { setShowDeleteDialog(false); }; + const filteredTasks = useMemo(() => { + let filtered = tasks; + + // Фильтрация по поиску + if (searchQuery) { + filtered = filtered.filter( + (task) => + task.name.toLowerCase().includes(searchQuery.toLowerCase()) || + task.description?.toLowerCase().includes(searchQuery.toLowerCase()) + ); + } + + // Фильтрация по тегам + if (filterTags.first || filterTags.second) { + filtered = filtered.filter( + (task) => + (!filterTags.first || task.tags[0] === filterTags.first) && + (!filterTags.second || task.tags[1] === filterTags.second) + ); + } + + return filtered; + }, [tasks, searchQuery, filterTags]); + + const searchInputRef = useRef(null); + + useEffect(() => { + if (searchInputRef.current && openSearchModal) searchInputRef.current.focus(); + }, [searchInputRef, openSearchModal]); return (
{ confirmText="Удалить" cancelText="Отмена" /> - {tasks.length > 0 ? ( - <> -
Сегодня: {getDate}
-
- {groupTasksByDate.today.length > 0 ? ( -
- {groupTasksByDate.today.map((task) => ( - { - setIsOpen(true); - setIsEdit(true); - setEditContent(task); - setCalendarDate(task.date); - }} - onMarkClick={() => { - setTasks(tasks.map((t) => (t.id === task.id ? { ...t, checked: !t.checked } : t))); - }} - /> - ))} -
- ) : ( -
Задач на сегодня нет
- )} - {groupTasksByDate.tomorrow.length > 0 && ( -
-
Завтра
- {groupTasksByDate.tomorrow.map((task) => ( - { - setIsOpen(true); - setIsEdit(true); - setEditContent(task); - setCalendarDate(task.date); - }} - onMarkClick={() => { - setTasks(tasks.map((t) => (t.id === task.id ? { ...t, checked: !t.checked } : t))); - }} - /> - ))} -
- )} - {groupTasksByDate.future.map((group) => ( -
-
{formatDate(group.date)}
- {group.tasks.map((task) => ( - { - setIsOpen(true); - setIsEdit(true); - setEditContent(task); - setCalendarDate(task.date); - }} - onMarkClick={() => { - setTasks(tasks.map((t) => (t.id === task.id ? { ...t, checked: !t.checked } : t))); - }} - /> - ))} -
- ))} -
-
-
{ - setIsCreating(true); - setIsOpen(true); - }} - > - + {!searchQuery && !filterTags.first && !filterTags.second ? ( + filteredTasks.length > 0 ? ( + <> +
Сегодня: {getDate}
+
+ {groupTasksByDate.today.length > 0 ? ( +
+ {groupTasksByDate.today.map((task) => ( + { + setIsOpen(true); + setIsEdit(true); + setEditContent(task); + setCalendarDate(task.date); + }} + onMarkClick={() => { + setTasks(tasks.map((t) => (t.id === task.id ? { ...t, checked: !t.checked } : t))); + }} + /> + ))} +
+ ) : ( +
Задач на сегодня нет
+ )} + {groupTasksByDate.tomorrow.length > 0 && ( +
+
Завтра
+ {groupTasksByDate.tomorrow.map((task) => ( + { + setIsOpen(true); + setIsEdit(true); + setEditContent(task); + setCalendarDate(task.date); + }} + onMarkClick={() => { + setTasks(tasks.map((t) => (t.id === task.id ? { ...t, checked: !t.checked } : t))); + }} + /> + ))} +
+ )} + {groupTasksByDate.future.map((group) => ( +
+
{formatDate(group.date)}
+ {group.tasks.map((task) => ( + { + setIsOpen(true); + setIsEdit(true); + setEditContent(task); + setCalendarDate(task.date); + }} + onMarkClick={() => { + setTasks(tasks.map((t) => (t.id === task.id ? { ...t, checked: !t.checked } : t))); + }} + /> + ))} +
+ ))}
- -
- - ) : ( - <> + + ) : (
Начни уже сегодня!
-
-
{ - setIsCreating(true); - setIsOpen(true); + ) + ) : ( +
+
+ {searchQuery ? "Результаты поиска" : "Результаты фильтрации"} +
+ {filteredTasks.length > 0 ? ( + filteredTasks.map((task) => ( + { + setIsOpen(true); + setIsEdit(true); + setEditContent(task); + setCalendarDate(task.date); + }} + onMarkClick={() => { + setTasks(tasks.map((t) => (t.id === task.id ? { ...t, checked: !t.checked } : t))); + }} + /> + )) + ) : ( +
+ {searchQuery ? "Ничего не найдено" : "Нет задач с выбранными фильтрами"} +
+ )} +
+ )} +
+
{ + setIsCreating(true); + setIsOpen(true); + }} + > + +
+ +
+ {openSearchModal && ( +
+ {/* Пофиксить разфокус при вводе */} +
+ + { + setSearchQuery((e.target as HTMLInputElement).value); + }} + /> + {searchQuery && ( + setSearchQuery("")} + /> + )} +
+
+ )} + {openFilterModal && ( +
+
+
Фильтры
+
+
+
{ + setOpenFirstList(!openFirstList); + setOpenSecondList(false); + }} + > + + {filterTags.first || "Предмет"} +
+ {openFirstList && ( +
+ {example_tags.first.map((tag) => ( +
{ + setFilterTags({ ...filterTags, first: tag }); + setOpenFirstList(false); + }} + > +
+ {filterTags.first === tag &&
} +
+ {tag} +
+ ))} +
+ )} +
+ +
+
{ + setOpenSecondList(!openSecondList); + setOpenFirstList(false); + }} + > + + {filterTags.second || "Задача"} +
+ {openSecondList && ( +
+ {example_tags.second.map((tag) => ( +
{ + setFilterTags({ ...filterTags, second: tag }); + setOpenSecondList(false); + }} + > +
+ {filterTags.second === tag &&
} +
+ {tag} +
+ ))} +
+ )} +
+ + {(filterTags.first || filterTags.second) && ( + + )}
- +
)}
);