diff --git a/src/components/ui/Dialog.tsx b/src/components/ui/Dialog.tsx new file mode 100644 index 0000000..1cbe407 --- /dev/null +++ b/src/components/ui/Dialog.tsx @@ -0,0 +1,52 @@ +import { FunctionComponent } from "preact"; +import Button from "./Button"; + +interface DialogProps { + isOpen: boolean; + setIsOpen: (isOpen: boolean) => void; + title: string; + content: string; + onConfirm: () => void; + confirmText?: string; + cancelText?: string; +} + +const Dialog: FunctionComponent = ({ + isOpen, + setIsOpen, + title, + content, + onConfirm, + confirmText = "Подтвердить", + cancelText = "Отмена", +}) => { + if (!isOpen) return null; + + return ( +
+
+

{title}

+

{content}

+
+ + +
+
+
+ ); +}; + +export default Dialog; \ No newline at end of file diff --git a/src/pages/profile_tasks.tsx b/src/pages/profile_tasks.tsx index 3c5ce01..109aa7a 100644 --- a/src/pages/profile_tasks.tsx +++ b/src/pages/profile_tasks.tsx @@ -17,6 +17,7 @@ import { InboxArrowDownIcon, MagnifyingGlassIcon, PencilIcon, + TrashIcon, } from "@heroicons/react/24/outline"; import { FunctionComponent } from "preact"; import { useEffect, useMemo, useState } from "preact/hooks"; @@ -25,6 +26,7 @@ import { SubmitHandler, useForm } from "react-hook-form"; import { v4 as uuid } from "uuid"; import { ITask, ITaskForm } from "./profile_tasks.dto"; import classes from "./profile_tasks.module.scss"; +import Dialog from "@/components/ui/Dialog"; const example_tags: { first: string[]; second: string[] } = { first: ["Программирование", "Информатика", "Физика", "Математика"], @@ -41,6 +43,7 @@ const ProfileTasks: FunctionComponent = () => { const [editContent, setEditContent] = useState(null); // Содержимое редактируемой задачи const [calendarDate, setCalendarDate] = useState>(); // Выбранная в календаре дата const [tags, setTags] = useState({ first: "", second: "" }); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); const getDate = useMemo(() => { const date = new Date(); const formatter = new Intl.DateTimeFormat("ru-RU", { month: "long", day: "numeric" }); @@ -110,6 +113,67 @@ const ProfileTasks: FunctionComponent = () => { if (tags.second) newEditContent.tags = [newEditContent.tags[0], tags.second]; setEditContent(newEditContent); }, [tags]); + + const groupTasksByDate = useMemo(() => { + const today = new Date(); + today.setHours(0, 0, 0, 0); + + const tomorrow = new Date(today); + tomorrow.setDate(tomorrow.getDate() + 1); + + const groupedTasks = { + today: [] as ITask[], + tomorrow: [] as ITask[], + future: [] as { date: Date; tasks: ITask[] }[], + }; + + tasks.forEach(task => { + const taskDate = new Date(task.date); + taskDate.setHours(0, 0, 0, 0); + + if (taskDate.getTime() === today.getTime()) { + groupedTasks.today.push(task); + } else if (taskDate.getTime() === tomorrow.getTime()) { + groupedTasks.tomorrow.push(task); + } else if (taskDate > tomorrow) { + const existingGroup = groupedTasks.future.find(group => + group.date.getTime() === taskDate.getTime() + ); + + if (existingGroup) { + existingGroup.tasks.push(task); + } else { + groupedTasks.future.push({ date: taskDate, tasks: [task] }); + } + } + }); + + // Sort tasks within each group + groupedTasks.today.sort((a, b) => a.date.getTime() - b.date.getTime()); + groupedTasks.tomorrow.sort((a, b) => a.date.getTime() - b.date.getTime()); + groupedTasks.future.sort((a, b) => a.date.getTime() - b.date.getTime()); + groupedTasks.future.forEach(group => { + group.tasks.sort((a, b) => a.date.getTime() - b.date.getTime()); + }); + + return groupedTasks; + }, [tasks]); + + const formatDate = (date: Date) => { + return new Intl.DateTimeFormat("ru-RU", { + day: "numeric", + month: "long", + year: "numeric" + }).format(date); + }; + + const handleDeleteTask = () => { + if (!editContent) return; + setTasks(tasks.filter((task) => task.id !== editContent.id)); + setIsOpen(false); + setShowDeleteDialog(false); + }; + return (
{ />
-
{ - if (isEditModal) { - handleSubmit(saveTask)(); - setIsEditModal(!isEditModal); - } else setIsEditModal(!isEditModal); - }} - > - {isEditModal ? ( - <> - -

Сохранить

- - ) : ( - <> - {" "} - -

Редактировать

- - )} +
+
{ + if (isEditModal) { + handleSubmit(saveTask)(); + setIsEditModal(!isEditModal); + } else setIsEditModal(!isEditModal); + }} + > + {isEditModal ? ( + <> + +

Сохранить

+ + ) : ( + <> + +

Редактировать

+ + )} +
+
setShowDeleteDialog(true)} + > + +

Удалить

+
{errors.name &&

{errors.name.message}

} @@ -310,28 +382,83 @@ const ProfileTasks: FunctionComponent = () => { )} + {tasks.length > 0 ? ( <>
Сегодня: {getDate}
- {tasks - .sort((a, b) => b.date.getTime() - a.date.getTime()) - .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.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))); + }} + /> + ))} +
+ ))}