diff --git a/src/components/ModalCalendar.tsx b/src/components/ModalCalendar.tsx index 0c8e3a5..16316f9 100644 --- a/src/components/ModalCalendar.tsx +++ b/src/components/ModalCalendar.tsx @@ -1,13 +1,18 @@ import { cn } from "@/utils/class-merge"; +import { ClockIcon } from "@heroicons/react/24/outline"; import { FunctionComponent } from "preact"; -import { Dispatch, StateUpdater } from "preact/hooks"; -import { Calendar } from "primereact/calendar"; +import { Dispatch, StateUpdater, useState } from "preact/hooks"; +import { Calendar, CalendarPassThroughMethodOptions } from "primereact/calendar"; +import { FormEvent } from "primereact/ts-helpers"; +import Button from "./ui/Button"; import ModalWindow from "./ui/Modal"; interface ModalCalendarProps { isOpen?: boolean; setIsOpen?: Dispatch>; onClose?: () => void; + value?: Date; + onChange?: (e: FormEvent) => void; } const TRANSITIONS = { @@ -22,143 +27,171 @@ const TRANSITIONS = { }, }; -const ModalCalendar: FunctionComponent = ({ isOpen, setIsOpen, onClose }) => { +const ModalCalendar: FunctionComponent = ({ isOpen, setIsOpen, onClose, onChange, value }) => { + const [showTime, setShowTime] = useState(false); return ( - - ({ - className: cn("inline-flex max-w-full relative", { - "opacity-60 select-none pointer-events-none cursor-default": props.disabled, + +
+ ({ + className: cn("inline-flex w-full relative", { + "opacity-60 select-none pointer-events-none cursor-default": props.disabled, + }), }), - }), - input: ({ props }) => ({ - root: { + input: ({ props }: CalendarPassThroughMethodOptions) => ({ + root: { + className: cn( + "font-sans text-base text-gray-600 bg-white p-3 border border-gray-300 transition-colors duration-200 appearance-none", + "hover:border-blue-500", + { + "rounded-lg": !props.showIcon, + "border-r-0 rounded-l-lg": props.showIcon, + } + ), + }, + }), + dropdownButton: { + root: ({ props }: CalendarPassThroughMethodOptions) => ({ + className: cn({ "rounded-l-none": props.icon }), + }), + }, + panel: ({ props }: CalendarPassThroughMethodOptions) => ({ + className: cn("bg-[rgba(251,194,199,0.38)]", "min-w-full", { + "shadow-md border-0 absolute": !props.inline, + "inline-block overflow-x-auto border border-gray-300 p-2 rounded-lg": props.inline, + }), + }), + header: { className: cn( - "font-sans text-base text-gray-600 bg-white p-3 border border-gray-300 transition-colors duration-200 appearance-none", - "hover:border-blue-500", - { - "rounded-lg": !props.showIcon, - "border-r-0 rounded-l-lg": props.showIcon, - } + "flex items-center justify-between", + "p-2 text-gray-700 bg-[rgba(251,194,199,0.38)] font-semibold m-0 border-b border-gray-300 rounded-t-lg" ), }, - }), - dropdownButton: { - root: ({ props }) => ({ - className: cn({ "rounded-l-none": props.icon }), + previousButton: { + className: cn( + "flex items-center justify-center cursor-pointer overflow-hidden relative", + "w-8 h-8 text-gray-600 border-0 bg-transparent rounded-full transition-colors duration-200 ease-in-out", + "hover:text-gray-700 hover:border-transparent hover:bg-gray-200 " + ), + }, + title: { className: "leading-8 mx-auto" }, + monthTitle: { + className: cn("text-gray-700 transition duration-200 font-semibold p-2", "mr-2", "hover:text-blue-500"), + }, + yearTitle: { + className: cn("text-gray-700 transition duration-200 font-semibold p-2", "hover:text-blue-500"), + }, + nextButton: { + className: cn( + "flex items-center justify-center cursor-pointer overflow-hidden relative", + "w-8 h-8 text-gray-600 border-0 bg-transparent rounded-full transition-colors duration-200 ease-in-out", + "hover:text-gray-700 hover:border-transparent hover:bg-gray-200 " + ), + }, + table: { + className: cn("border-collapse w-full", "my-2"), + }, + tableHeaderCell: { className: "p-2" }, + weekDay: { className: "text-gray-600 " }, + day: { className: "p-2" }, + dayLabel: ({ context }: CalendarPassThroughMethodOptions) => ({ + className: cn( + "w-6 h-6 rounded-full transition-shadow duration-200 border-transparent border", + "flex items-center justify-center mx-auto overflow-hidden relative", + "focus:outline-none focus:outline-offset-0 focus:shadow-[0_0_0_0.2rem_rgba(191,219,254,1)] ", + { + "opacity-60 cursor-default": context.disabled, + "cursor-pointer": !context.disabled, + }, + { + "text-gray-600 bg-transparent hover:bg-gray-200 ": !context.selected && !context.disabled, + "text-blue-700 bg-blue-100 hover:bg-blue-200": context.selected && !context.disabled, + } + ), }), - }, - panel: ({ props }) => ({ - className: cn("bg-[rgba(251,194,199,0.38)]", "min-w-full", { - "shadow-md border-0 absolute": !props.inline, - "inline-block overflow-x-auto border border-gray-300 p-2 rounded-lg": props.inline, + monthPicker: { className: "my-2" }, + month: ({ context }: CalendarPassThroughMethodOptions) => ({ + className: cn( + "w-1/3 inline-flex items-center justify-center cursor-pointer overflow-hidden relative", + "p-2 transition-shadow duration-200 rounded-lg", + "focus:outline-none focus:outline-offset-0 focus:shadow-[0_0_0_0.2rem_rgba(191,219,254,1)] ", + { + "text-gray-600 bg-transparent hover:bg-gray-200 ": !context.selected && !context.disabled, + "text-blue-700 bg-blue-100 hover:bg-blue-200": context.selected && !context.disabled, + } + ), }), - }), - header: { - className: cn( - "flex items-center justify-between", - "p-2 text-gray-700 bg-white font-semibold m-0 border-b border-gray-300 rounded-t-lg" - ), - }, - previousButton: { - className: cn( - "flex items-center justify-center cursor-pointer overflow-hidden relative", - "w-8 h-8 text-gray-600 border-0 bg-transparent rounded-full transition-colors duration-200 ease-in-out", - "hover:text-gray-700 hover:border-transparent hover:bg-gray-200 " - ), - }, - title: { className: "leading-8 mx-auto" }, - monthTitle: { - className: cn("text-gray-700 transition duration-200 font-semibold p-2", "mr-2", "hover:text-blue-500"), - }, - yearTitle: { - className: cn("text-gray-700 transition duration-200 font-semibold p-2", "hover:text-blue-500"), - }, - nextButton: { - className: cn( - "flex items-center justify-center cursor-pointer overflow-hidden relative", - "w-8 h-8 text-gray-600 border-0 bg-transparent rounded-full transition-colors duration-200 ease-in-out", - "hover:text-gray-700 hover:border-transparent hover:bg-gray-200 " - ), - }, - table: { - className: cn("border-collapse w-full", "my-2"), - }, - tableHeaderCell: { className: "p-2" }, - weekDay: { className: "text-gray-600 " }, - day: { className: "p-2" }, - dayLabel: ({ context }) => ({ - className: cn( - "w-10 h-10 rounded-full transition-shadow duration-200 border-transparent border", - "flex items-center justify-center mx-auto overflow-hidden relative", - "focus:outline-none focus:outline-offset-0 focus:shadow-[0_0_0_0.2rem_rgba(191,219,254,1)] ", - { - "opacity-60 cursor-default": context.disabled, - "cursor-pointer": !context.disabled, - }, - { - "text-gray-600 bg-transparent hover:bg-gray-200 ": !context.selected && !context.disabled, - "text-blue-700 bg-blue-100 hover:bg-blue-200": context.selected && !context.disabled, - } - ), - }), - monthPicker: { className: "my-2" }, - month: ({ context }) => ({ - className: cn( - "w-1/3 inline-flex items-center justify-center cursor-pointer overflow-hidden relative", - "p-2 transition-shadow duration-200 rounded-lg", - "focus:outline-none focus:outline-offset-0 focus:shadow-[0_0_0_0.2rem_rgba(191,219,254,1)] ", - { - "text-gray-600 bg-transparent hover:bg-gray-200 ": !context.selected && !context.disabled, - "text-blue-700 bg-blue-100 hover:bg-blue-200": context.selected && !context.disabled, - } - ), - }), - yearPicker: { - className: cn("my-2"), - }, - year: ({ context }) => ({ - className: cn( - "w-1/2 inline-flex items-center justify-center cursor-pointer overflow-hidden relative", - "p-2 transition-shadow duration-200 rounded-lg", - "focus:outline-none focus:outline-offset-0 focus:shadow-[0_0_0_0.2rem_rgba(191,219,254,1)] ", - { - "text-gray-600 bg-transparent hover:bg-gray-200 ": !context.selected && !context.disabled, - "text-blue-700 bg-blue-100 hover:bg-blue-200": context.selected && !context.disabled, - } - ), - }), - timePicker: { - className: cn("flex justify-center items-center", "border-t-1 border-solid border-gray-300 p-2"), - }, - separatorContainer: { className: "flex items-center flex-col px-2" }, - separator: { className: "text-xl" }, - hourPicker: { className: "flex items-center flex-col px-2" }, - minutePicker: { className: "flex items-center flex-col px-2" }, - ampmPicker: { className: "flex items-center flex-col px-2" }, - incrementButton: { - className: cn( - "flex items-center justify-center cursor-pointer overflow-hidden relative", - "w-8 h-8 text-gray-600 border-0 bg-transparent rounded-full transition-colors duration-200 ease-in-out", - "hover:text-gray-700 hover:border-transparent hover:bg-gray-200 " - ), - }, - decrementButton: { - className: cn( - "flex items-center justify-center cursor-pointer overflow-hidden relative", - "w-8 h-8 text-gray-600 border-0 bg-transparent rounded-full transition-colors duration-200 ease-in-out", - "hover:text-gray-700 hover:border-transparent hover:bg-gray-200 " - ), - }, - groupContainer: { className: "flex" }, - group: { - className: cn("flex-1", "border-l border-gray-300 pr-0.5 pl-0.5 pt-0 pb-0", "first:pl-0 first:border-l-0"), - }, - transition: TRANSITIONS.overlay, + yearPicker: { + className: cn("my-2"), + }, + year: ({ context }: CalendarPassThroughMethodOptions) => ({ + className: cn( + "w-1/2 inline-flex items-center justify-center cursor-pointer overflow-hidden relative", + "p-2 transition-shadow duration-200 rounded-lg", + "focus:outline-none focus:outline-offset-0 focus:shadow-[0_0_0_0.2rem_rgba(191,219,254,1)] ", + { + "text-gray-600 bg-transparent hover:bg-gray-200 ": !context.selected && !context.disabled, + "text-blue-700 bg-blue-100 hover:bg-blue-200": context.selected && !context.disabled, + } + ), + }), + timePicker: { + className: cn("flex justify-center items-center", "border-t-1 border-solid border-gray-300"), + }, + separatorContainer: { className: "flex items-center flex-col px-2" }, + separator: { className: "text-xl" }, + hourPicker: { className: "flex items-center flex-col px-2" }, + minutePicker: { className: "flex items-center flex-col px-2" }, + ampmPicker: { className: "flex items-center flex-col px-2" }, + incrementButton: { + className: cn( + "flex items-center justify-center cursor-pointer overflow-hidden relative", + "w-8 h-8 text-gray-600 border-0 bg-transparent rounded-full transition-colors duration-200 ease-in-out", + "hover:text-gray-700 hover:border-transparent hover:bg-gray-200 " + ), + }, + decrementButton: { + className: cn( + "flex items-center justify-center cursor-pointer overflow-hidden relative", + "w-8 h-8 text-gray-600 border-0 bg-transparent rounded-full transition-colors duration-200 ease-in-out", + "hover:text-gray-700 hover:border-transparent hover:bg-gray-200 " + ), + }, + groupContainer: { className: "flex" }, + group: { + className: cn( + "flex-1", + "border-l border-gray-300 pr-0.5 pl-0.5 pt-0 pb-0", + "first:pl-0 first:border-l-0" + ), + }, + transition: TRANSITIONS.overlay, + }} + /> +

+ {value && Intl.DateTimeFormat("ru-RU", { day: "2-digit", month: "2-digit", year: "numeric" }).format(value)} +

+
+
); }; diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal.tsx index 3108974..8c6997d 100644 --- a/src/components/ui/Modal.tsx +++ b/src/components/ui/Modal.tsx @@ -7,35 +7,43 @@ interface ModalWindowProps { setIsOpen?: Dispatch>; onClose?: () => void; className?: string; + zIndex?: number; } -const ModalWindow: FunctionComponent = ({ isOpen, children, setIsOpen, onClose, className = "" }) => { +const ModalWindow: FunctionComponent = ({ + isOpen, + children, + setIsOpen, + onClose, + className = "", + zIndex, +}) => { useEffect(() => { if (isOpen) return; if (onClose) onClose(); }, [isOpen]); return ( -
{ - e.stopPropagation(); - if (setIsOpen) setIsOpen(false); - }} - class={cn( - "fixed top-0 left-0 z-50 flex h-screen w-screen cursor-pointer flex-col items-center justify-center bg-black/50", - { - hidden: !isOpen, - } - )} - > + isOpen && (
{ + e.stopPropagation(); + if (setIsOpen) setIsOpen(false); + }} class={cn( - "h-[40rem] w-[95%] cursor-auto rounded-[4rem] bg-white px-8 py-12 md:me-[20rem] md:h-[20rem] md:w-[65%] md:px-16", - className + "fixed top-0 left-0 z-50 flex h-screen w-screen cursor-pointer flex-col items-center justify-center bg-black/50" )} - onClick={(e) => e.stopPropagation()} + style={{ zIndex: zIndex }} > - {children} +
e.stopPropagation()} + > + {children} +
-
+ ) ); }; diff --git a/src/pages/profile_tasks.tsx b/src/pages/profile_tasks.tsx index 3f6d4aa..e656585 100644 --- a/src/pages/profile_tasks.tsx +++ b/src/pages/profile_tasks.tsx @@ -17,6 +17,7 @@ import { } from "@heroicons/react/24/outline"; import { FunctionComponent } from "preact"; import { useEffect, useMemo, useRef, useState } from "preact/hooks"; +import { Nullable } from "primereact/ts-helpers"; import { ITask } from "./profile_tasks.dto"; import classes from "./profile_tasks.module.scss"; @@ -64,14 +65,24 @@ const ProfileTasks: FunctionComponent = () => { localStorage.setItem("tasks", JSON.stringify(tasks)); }, [tasks]); const [openModal, setIsOpen] = useState(false); + const [openModalCalendar, setOpenModalCalendar] = useState(false); const [isEdit, setIsEdit] = useState(false); const [isCreating, setIsCreating] = useState(false); const [editContent, setEditContent] = useState(null); const taskNameRef = useRef(null); const taskDescriptionRef = useRef(null); + const [calendarDate, setCalendarDate] = useState>(); return (
- + { + setCalendarDate(null); + }} + onChange={(e) => isCreating && setCalendarDate(e.value)} + value={calendarDate!} + /> {
-
+
{ + setOpenModalCalendar(true); + setCalendarDate(editContent.date); + }} + >

{Intl.DateTimeFormat("ru-RU", {