diff --git a/src/pages/profile_calendar.tsx b/src/pages/profile_calendar.tsx index 7d505d6..d83f28c 100644 --- a/src/pages/profile_calendar.tsx +++ b/src/pages/profile_calendar.tsx @@ -1,15 +1,389 @@ -import BigCalendar from "@/components/calendar"; import { withTitle } from "@/constructors/Component"; import { UrlsTitle } from "@/enums/urls"; import { FunctionComponent } from "preact"; +import { useState, useEffect } from "preact/hooks"; +import { Calendar, CalendarDateTemplateEvent } from "primereact/calendar"; +import { cn } from "@/utils/class-merge"; +import { ITask } from "./profile_tasks.dto"; +import Task from "@/components/task"; +import ModalWindow from "@/components/ui/Modal"; +import ModalCalendar from "@/components/ModalCalendar"; +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, + InboxArrowDownIcon, + CalendarDaysIcon, + BookOpenIcon, + DocumentDuplicateIcon +} from "@heroicons/react/24/outline"; + +const example_tags: { first: string[]; second: string[] } = { + first: ["Программирование", "Информатика", "Физика", "Математика"], + second: ["Лабораторная работа", "Практическая работа", "Домашнее задание", "Экзамен"], +}; + +const calendarStyles = { + root: "inline-flex w-full relative", + input: "font-sans text-base text-gray-600 bg-white p-3", + panel: "bg-white min-w-full p-2", + header: "flex items-center justify-between p-2 text-gray-700 font-semibold m-0 mb-4", + title: "leading-8 mx-auto text-xl", + previousButton: "flex items-center justify-center cursor-pointer w-8 h-8 text-gray-600", + nextButton: "flex items-center justify-center cursor-pointer w-8 h-8 text-gray-600", + table: "border-collapse w-full", + tableHeaderCell: "p-2 text-center", + weekDay: "text-gray-600 font-normal pb-4", + monthTitle: "text-gray-700 font-semibold mr-2", + 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)]" +}; const ProfileCalendar: FunctionComponent = () => { - const onDateSelect = (date: Date) => { - console.log(date); + const [currentDate, setCurrentDate] = useState(new Date()); + const [tasks, setTasks] = useState([]); + const [selectedTasks, setSelectedTasks] = useState([]); + const [openModal, setIsOpen] = useState(false); + const [openModalCalendar, setOpenModalCalendar] = useState(false); + const [openModalTags, setOpenModalTags] = useState(false); + const [isEdit, setIsEdit] = useState(false); + const [isEditModal, setIsEditModal] = useState(false); + const [editContent, setEditContent] = useState(null); + const [calendarDate, setCalendarDate] = useState>(); + const [tags, setTags] = useState({ first: "", second: "" }); + + const { + handleSubmit, + register, + reset, + setError, + formState: { errors }, + } = useForm({ + defaultValues: { + tags: [], + }, + }); + + useEffect(() => { + const storedTasks = localStorage.getItem("tasks"); + if (storedTasks) { + const parsedTasks: ITask[] = JSON.parse(storedTasks).map((task: any) => ({ + ...task, + 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); + }, []); + + useEffect(() => { + if (!currentDate) return; + + const tasksForDate = tasks.filter(task => { + const taskDate = task.date; + return taskDate.getDate() === currentDate.getDate() && + taskDate.getMonth() === currentDate.getMonth() && + taskDate.getFullYear() === currentDate.getFullYear(); + }); + + setSelectedTasks(tasksForDate); + }, [currentDate, tasks]); + + useEffect(() => { + if (editContent) reset({ ...editContent, date: editContent.date.toISOString().slice(0, 16) }); + else reset(); + }, [editContent]); + + useEffect(() => { + if (!editContent) return; + const newEditContent = editContent; + if (tags.first) newEditContent.tags = [tags.first, newEditContent.tags[1]]; + if (tags.second) newEditContent.tags = [newEditContent.tags[0], tags.second]; + setEditContent(newEditContent); + }, [tags]); + + const hasTasksOnDate = (date: CalendarDateTemplateEvent) => { + return tasks.some(task => { + const taskDate = task.date; + 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 && + currentDate.getFullYear() === date.year; + const isToday = new Date().getDate() === date.day && + new Date().getMonth() === date.month && + new Date().getFullYear() === date.year; + + return ( +
+ {date.day} + {isHighlighted && } +
+ ); + }; + + const handleTaskCheck = (taskId: string) => { + 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", { + day: "numeric", + month: "long", + year: "numeric" + }).format(date); + }; + + const saveTask = (data: ITaskForm) => { + if (!calendarDate) { + setError("date", { message: "Выберите дату" }); + return; + } + if ((!editContent?.tags[0] || !editContent.tags[1]) && (!tags.first || !tags.second)) { + setError("tags", { message: "Выберите теги" }); + return; + } + const eTask: ITask = { + ...data, + date: calendarDate, + tags: editContent?.tags.length ? editContent.tags : [tags.first, tags.second], + new: true, + }; + setTasks(tasks.map((task) => (task.id === eTask.id ? eTask : task))); + localStorage.setItem("tasks", JSON.stringify(tasks.map((task) => (task.id === eTask.id ? eTask : task)))); + setTags({ first: "", second: "" }); + }; + + const pt = { + root: { className: calendarStyles.root }, + input: { root: { className: calendarStyles.input }}, + panel: { className: calendarStyles.panel }, + header: { className: calendarStyles.header }, + title: { className: calendarStyles.title }, + previousButton: { className: calendarStyles.previousButton }, + nextButton: { className: calendarStyles.nextButton }, + table: { className: calendarStyles.table }, + tableHeaderCell: { className: calendarStyles.tableHeaderCell }, + weekDay: { className: calendarStyles.weekDay }, + monthTitle: { className: calendarStyles.monthTitle }, + yearTitle: { className: calendarStyles.yearTitle }, + monthPicker: { className: calendarStyles.monthPicker }, + yearPicker: { className: calendarStyles.yearPicker }, + month: { className: calendarStyles.month }, + year: { className: calendarStyles.year } + }; + return (
- + { + setTags({ first: "", second: "" }); + }} + onChange={setTags} + /> + { + if (isEdit && !isEditModal) setCalendarDate(null); + }} + onChange={(e) => isEditModal && setCalendarDate(e.value)} + value={calendarDate!} + /> + { + setIsEdit(false); + setEditContent(null); + setIsEditModal(false); + setTags({ first: "", second: "" }); + setCalendarDate(null); + }} + > + {isEdit && editContent && ( +
{ + e.preventDefault(); + if (isEditModal) handleSubmit(saveTask)(); + else setIsEditModal(!isEditModal); + }} + > +
+
+ +