Files
anti-hvost/src/pages/profile_tasks.tsx

231 lines
9.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Task from "@/components/task";
import Button from "@/components/ui/Button";
import ModalWindow from "@/components/ui/Modal";
import { withTitle } from "@/constructors/Component";
import { UrlsTitle } from "@/enums/urls";
import { PlusIcon } from "@heroicons/react/20/solid";
import {
BookmarkIcon,
BookOpenIcon,
CalendarDaysIcon,
DocumentDuplicateIcon,
FunnelIcon,
MagnifyingGlassIcon,
PencilIcon,
} from "@heroicons/react/24/outline";
import { FunctionComponent } from "preact";
import { useEffect, useMemo, useRef, useState } from "preact/hooks";
import { ITask } from "./profile_tasks.dto";
import classes from "./profile_tasks.module.scss";
const example_tasks: ITask[] = [
{
checked: false,
date: new Date(),
description: "test",
id: 1,
name: "test1",
tags: ["Программирование", "Лабораторная работа"],
},
{
checked: true,
date: new Date(2025, 6, 2),
description: "test2",
id: 3,
name: "test3",
tags: ["Информатика", "Практическая работа"],
},
{
checked: false,
date: new Date(2025, 5, 1),
description: "test3",
id: 2,
name: "test2",
tags: ["Математика", "Домашнее задание"],
},
];
const ProfileTasks: FunctionComponent = () => {
const getDate = useMemo(() => {
const date = new Date();
const formatter = new Intl.DateTimeFormat("ru-RU", { month: "long", day: "numeric" });
return formatter.format(date);
}, []);
const init_tasks: ITask[] = localStorage.getItem("tasks")
? JSON.parse(localStorage.getItem("tasks") as string)
: example_tasks;
init_tasks.forEach((task) => {
task.date = new Date(task.date);
});
const [tasks, setTasks] = useState<ITask[]>(init_tasks);
useEffect(() => {
localStorage.setItem("tasks", JSON.stringify(tasks));
}, [tasks]);
const [openModal, setIsOpen] = useState(false);
const [isEdit, setIsEdit] = useState(false);
const [isCreating, setIsCreating] = useState(false);
const [editContent, setEditContent] = useState<ITask | null>(null);
const taskNameRef = useRef<HTMLInputElement>(null);
const taskDescriptionRef = useRef<HTMLTextAreaElement>(null);
return (
<div class={classes.container}>
<ModalWindow
isOpen={openModal}
setIsOpen={setIsOpen}
onClose={() => {
setIsEdit(false);
setEditContent(null);
setIsCreating(false);
}}
>
{isEdit && editContent && (
<div class="flex h-full w-full flex-col items-start justify-between">
<div class="flex w-full flex-row items-start justify-between">
<div class="flex flex-col">
<p class="text-2xl">{editContent.name}</p>
<p>{editContent.description}</p>
</div>
<div className="flex cursor-pointer flex-col items-center gap-3">
<PencilIcon class="size-6" />
<p class="text-[0.7rem]">Редактировать</p>
</div>
</div>
<div class="flex flex-col items-center gap-6 self-center md:flex-row md:justify-start md:self-start">
<div class="flex h-full flex-row items-center gap-1 rounded-2xl bg-[rgba(251,194,199,0.38)] px-2 py-1">
<CalendarDaysIcon class="size-10" />
<p>
{Intl.DateTimeFormat("ru-RU", {
day: "2-digit",
month: "2-digit",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
}).format(editContent.date)}
</p>
</div>
<div class="flex h-full flex-col items-start gap-1 rounded-2xl bg-[rgba(251,194,199,0.38)] px-4 py-2">
<p class="flex flex-row gap-2">
<BookOpenIcon class="size-5" />
{editContent.tags[0]}
</p>
<p class="flex flex-row gap-2">
<DocumentDuplicateIcon class="size-5" />
{editContent.tags[1]}
</p>
</div>
</div>
</div>
)}
{isCreating && (
<div class="flex h-full w-full flex-col items-start justify-between">
<div class="flex w-full flex-row items-start justify-between">
<div class="me-4 flex flex-1 flex-col gap-1">
<input class="text-2xl outline-0" maxLength={20} placeholder="Название" ref={taskNameRef} />
<textarea
class="h-[5rem] w-full resize-none outline-0"
maxLength={200}
placeholder="Описание"
ref={taskDescriptionRef}
/>
</div>
<CalendarDaysIcon class="size-10 cursor-pointer" />
<BookmarkIcon class="ms-4 size-10 cursor-pointer" />
</div>
<div className="flex h-16 flex-row gap-6">
<Button
className="text-sm"
onClick={() => {
setIsOpen(false);
}}
>
Отмена
</Button>
<Button
color="red"
onClick={() => {
if (taskNameRef.current && taskDescriptionRef.current) {
if (!taskNameRef.current.value || !taskDescriptionRef.current.value) {
alert("Заполните все поля");
return;
}
const task: ITask = {
id: tasks.length + 1,
name: taskNameRef.current.value,
description: taskDescriptionRef.current.value,
date: new Date(),
checked: false,
tags: ["Математика", "Домашнее задание"],
};
setTasks([...tasks, task]);
setIsOpen(false);
}
}}
>
Добавить задачу
</Button>
</div>
</div>
)}
</ModalWindow>
{tasks.length > 0 ? (
<>
<div class={classes.header}>Сегодня: {getDate}</div>
<div class={classes.tasks_container}>
{tasks
.sort((a, b) => b.id - a.id)
.map((task) => (
<Task
name={task.name}
key={task.id}
checked={task.checked}
onClick={() => {
setIsOpen(true);
setIsEdit(true);
setEditContent(task);
}}
/>
))}
</div>
<div class="group fixed right-[22rem] bottom-4 hidden flex-row items-center justify-start space-x-3 overflow-x-hidden py-2 md:flex">
<div
class="flex aspect-square h-20 cursor-pointer items-center justify-center rounded-full bg-[rgb(251,194,199,0.53)] text-9xl text-white shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)] transition-all duration-300 ease-out group-hover:ml-[12rem] hover:bg-[rgb(251,194,199,0.7)]"
onClick={() => {
setIsCreating(true);
setIsOpen(true);
}}
>
<PlusIcon />
</div>
<div class="absolute left-0 my-auto flex flex-row space-x-3 opacity-0 transition-opacity duration-100 group-hover:opacity-100">
<div class="pointer-events-none flex aspect-square h-20 cursor-pointer flex-col items-center justify-center rounded-full bg-[rgba(206,232,251,0.7)] text-xl text-gray-600 shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)] group-hover:pointer-events-auto hover:bg-[rgba(206,232,251,0.9)]">
<MagnifyingGlassIcon class="size-12" />
</div>
<div class="pointer-events-none flex aspect-square h-20 cursor-pointer flex-col items-center justify-center rounded-full bg-[rgba(206,232,251,0.7)] text-xl text-gray-600 shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)] group-hover:pointer-events-auto hover:bg-[rgba(206,232,251,0.9)]">
<FunnelIcon class="size-12" />
</div>
</div>
</div>
</>
) : (
<>
<div class="flex w-full flex-1 flex-col items-center justify-center text-2xl">Начни уже сегодня!</div>
<div class="fixed right-[22rem] bottom-4 hidden flex-row items-center justify-start overflow-x-hidden py-2 md:flex">
<div
class="flex aspect-square h-20 cursor-pointer items-center justify-center rounded-full bg-[rgb(251,194,199,0.53)] text-9xl text-white shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)] transition-all duration-300 ease-out hover:bg-[rgb(251,194,199,0.7)]"
onClick={() => {
setIsCreating(true);
setIsOpen(true);
}}
>
<PlusIcon />
</div>
</div>
</>
)}
</div>
);
};
export default withTitle(UrlsTitle.TASKS, ProfileTasks);