From a2fe9bcfd7c6bdce82a7a76035cc6e4d813738c1 Mon Sep 17 00:00:00 2001 From: Sergey Elpashev Date: Sun, 27 Apr 2025 14:04:51 +0300 Subject: [PATCH] feat: new tasks calendar --- src/pages/profile_calendar.tsx | 185 ++++++++++++++++++--------------- 1 file changed, 102 insertions(+), 83 deletions(-) diff --git a/src/pages/profile_calendar.tsx b/src/pages/profile_calendar.tsx index d83f28c..bee7b42 100644 --- a/src/pages/profile_calendar.tsx +++ b/src/pages/profile_calendar.tsx @@ -12,13 +12,15 @@ import ModalTags, { ITags } from "@/components/ModalTags"; import { useForm } from "react-hook-form"; import { ITaskForm } from "./profile_tasks.dto"; import { Nullable } from "primereact/ts-helpers"; -import { - PencilIcon, +import { + PencilIcon, InboxArrowDownIcon, CalendarDaysIcon, BookOpenIcon, - DocumentDuplicateIcon + DocumentDuplicateIcon, + TrashIcon, } from "@heroicons/react/24/outline"; +import Dialog from "@/components/ui/Dialog"; const example_tags: { first: string[]; second: string[] } = { first: ["Программирование", "Информатика", "Физика", "Математика"], @@ -40,8 +42,9 @@ const calendarStyles = { yearTitle: "text-gray-700 font-semibold", monthPicker: "grid grid-cols-3 gap-2", yearPicker: "grid grid-cols-2 gap-2", - month: "p-2 text-center cursor-pointer rounded-lg hover:bg-[rgba(251,194,199,0.1)] [&.p-highlight]:bg-[rgba(251,194,199,0.2)]", - year: "p-2 text-center cursor-pointer rounded-lg hover:bg-[rgba(251,194,199,0.1)] [&.p-highlight]:bg-[rgba(251,194,199,0.2)]" + month: + "p-2 text-center cursor-pointer rounded-lg hover:bg-[rgba(251,194,199,0.1)] [&.p-highlight]:bg-[rgba(251,194,199,0.2)]", + year: "p-2 text-center cursor-pointer rounded-lg hover:bg-[rgba(251,194,199,0.1)] [&.p-highlight]:bg-[rgba(251,194,199,0.2)]", }; const ProfileCalendar: FunctionComponent = () => { @@ -56,6 +59,8 @@ const ProfileCalendar: FunctionComponent = () => { const [editContent, setEditContent] = useState(null); const [calendarDate, setCalendarDate] = useState>(); const [tags, setTags] = useState({ first: "", second: "" }); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const { handleSubmit, @@ -72,37 +77,33 @@ const ProfileCalendar: FunctionComponent = () => { useEffect(() => { const storedTasks = localStorage.getItem("tasks"); if (storedTasks) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any const parsedTasks: ITask[] = JSON.parse(storedTasks).map((task: any) => ({ ...task, - date: new Date(task.date) + date: new Date(task.date), })); setTasks(parsedTasks); } - - const handleStorageChange = (e: StorageEvent) => { - if (e.key === "tasks" && e.newValue) { - const updatedTasks: ITask[] = JSON.parse(e.newValue).map((task: any) => ({ - ...task, - date: new Date(task.date) - })); - setTasks(updatedTasks); - } - }; - - window.addEventListener("storage", handleStorageChange); - return () => window.removeEventListener("storage", handleStorageChange); }, []); + const handleDeleteTask = () => { + if (!editContent) return; + setTasks(tasks.filter((task) => task.id !== editContent.id)); + setIsOpen(false); + setShowDeleteDialog(false); + }; useEffect(() => { if (!currentDate) return; - - const tasksForDate = tasks.filter(task => { + + const tasksForDate = tasks.filter((task) => { const taskDate = task.date; - return taskDate.getDate() === currentDate.getDate() && - taskDate.getMonth() === currentDate.getMonth() && - taskDate.getFullYear() === currentDate.getFullYear(); + return ( + taskDate.getDate() === currentDate.getDate() && + taskDate.getMonth() === currentDate.getMonth() && + taskDate.getFullYear() === currentDate.getFullYear() + ); }); - + setSelectedTasks(tasksForDate); }, [currentDate, tasks]); @@ -110,6 +111,9 @@ const ProfileCalendar: FunctionComponent = () => { if (editContent) reset({ ...editContent, date: editContent.date.toISOString().slice(0, 16) }); else reset(); }, [editContent]); + useEffect(() => { + localStorage.setItem("tasks", JSON.stringify(tasks)); + }, [tasks]); useEffect(() => { if (!editContent) return; @@ -120,52 +124,54 @@ const ProfileCalendar: FunctionComponent = () => { }, [tags]); const hasTasksOnDate = (date: CalendarDateTemplateEvent) => { - return tasks.some(task => { + return tasks.some((task) => { const taskDate = task.date; - return taskDate.getDate() === date.day && - taskDate.getMonth() === date.month && - taskDate.getFullYear() === date.year; + return ( + taskDate.getDate() === date.day && taskDate.getMonth() === date.month && taskDate.getFullYear() === date.year + ); }); }; const dateTemplate = (date: CalendarDateTemplateEvent) => { const isHighlighted = hasTasksOnDate(date); - const isSelected = currentDate && - currentDate.getDate() === date.day && - currentDate.getMonth() === date.month && + const isSelected = + currentDate && + currentDate.getDate() === date.day && + currentDate.getMonth() === date.month && currentDate.getFullYear() === date.year; - const isToday = new Date().getDate() === date.day && - new Date().getMonth() === date.month && + const isToday = + new Date().getDate() === date.day && + new Date().getMonth() === date.month && new Date().getFullYear() === date.year; return ( -
+
{date.day} - {isHighlighted && } + {isHighlighted && }
); }; const handleTaskCheck = (taskId: string) => { - const updatedTasks = tasks.map(task => - task.id === taskId ? { ...task, checked: !task.checked } : task - ); + const updatedTasks = tasks.map((task) => (task.id === taskId ? { ...task, checked: !task.checked } : task)); setTasks(updatedTasks); localStorage.setItem("tasks", JSON.stringify(updatedTasks)); }; const formatDate = (date: Date) => { - return new Intl.DateTimeFormat("ru-RU", { + return new Intl.DateTimeFormat("ru-RU", { day: "numeric", month: "long", - year: "numeric" + year: "numeric", }).format(date); }; @@ -191,7 +197,7 @@ const ProfileCalendar: FunctionComponent = () => { const pt = { root: { className: calendarStyles.root }, - input: { root: { className: calendarStyles.input }}, + input: { root: { className: calendarStyles.input } }, panel: { className: calendarStyles.panel }, header: { className: calendarStyles.header }, title: { className: calendarStyles.title }, @@ -205,7 +211,7 @@ const ProfileCalendar: FunctionComponent = () => { monthPicker: { className: calendarStyles.monthPicker }, yearPicker: { className: calendarStyles.yearPicker }, month: { className: calendarStyles.month }, - year: { className: calendarStyles.year } + year: { className: calendarStyles.year }, }; return ( @@ -276,26 +282,35 @@ const ProfileCalendar: FunctionComponent = () => { />
-
{ - 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}

} @@ -347,23 +362,29 @@ const ProfileCalendar: FunctionComponent = () => { )} - - setCurrentDate(e ? e.value! : new Date())} + + setCurrentDate(e ? e.value! : new Date())} inline pt={pt} dateTemplate={dateTemplate} - className="[&_.p-datepicker-calendar]:border-separate [&_.p-datepicker-calendar]:border-spacing-2 [&_td]:border [&_td]:border-[rgba(251,194,199,0.38)] [&_td]:rounded-lg [&_.p-datepicker]:!border-0" + className="[&_.p-datepicker]:!border-0 [&_.p-datepicker-calendar]:border-separate [&_.p-datepicker-calendar]:border-spacing-2 [&_td]:rounded-lg [&_td]:border [&_td]:border-[rgba(251,194,199,0.38)]" /> - +
-

- Задачи на {formatDate(currentDate)} -

+

Задачи на {formatDate(currentDate)}

{selectedTasks.length > 0 ? (
- {selectedTasks.map(task => ( + {selectedTasks.map((task) => ( { ))}
) : ( -
- На этот день задач нет -
+
На этот день задач нет
)}