Files
anti-hvost/src/components/ModalCalendar.tsx

220 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 { cn } from "@/utils/class-merge";
import { ClockIcon } from "@heroicons/react/24/outline";
import { FunctionComponent } from "preact";
import { Dispatch, StateUpdater, useEffect, useState } from "preact/hooks";
import { Calendar, CalendarPassThroughMethodOptions } from "primereact/calendar";
import { FormEvent } from "primereact/ts-helpers";
import Button from "./ui/Button";
import ModalWindow, { ModalWindowProps } from "./ui/Modal";
interface ModalCalendarProps extends ModalWindowProps {
isOpen?: boolean;
setIsOpen?: Dispatch<StateUpdater<boolean>>;
onClose?: () => void;
value?: Date;
onChange?: (e: FormEvent<Date>) => void;
}
const TRANSITIONS = {
overlay: {
timeout: 150,
cn: {
enter: "opacity-0 scale-75",
enterActive: "opacity-100 !scale-100 transition-[transform,opacity] duration-150 ease-in",
exit: "opacity-100",
exitActive: "!opacity-0 transition-opacity duration-150 ease-linear",
},
},
};
const ModalCalendar: FunctionComponent<ModalCalendarProps> = ({
isOpen,
setIsOpen,
onClose,
onChange,
value,
...rest
}) => {
const [showTime, setShowTime] = useState(false);
const [minDate, setMinDate] = useState(new Date());
useEffect(() => {
const interval = setInterval(() => {
setMinDate(new Date());
}, 1000);
return () => clearInterval(interval);
}, []);
return (
<ModalWindow
{...rest}
isOpen={isOpen}
setIsOpen={setIsOpen}
onClose={() => {
onClose!();
setShowTime(false);
}}
className="md:h-[40rem] md:w-[30rem]"
>
<div class="w-full flex-1 self-start">
<Calendar
inline
onChange={onChange}
value={value}
hourFormat="24"
minDate={minDate}
showTime={showTime}
pt={{
root: ({ props }: CalendarPassThroughMethodOptions) => ({
className: cn("inline-flex w-full relative", {
"opacity-60 select-none pointer-events-none cursor-default": props.disabled,
}),
}),
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(
"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"
),
},
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,
}
),
}),
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,
}
),
}),
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,
}}
/>
<p class={cn("mt-2 text-center text-xl font-semibold", { hidden: !value })}>
{value && Intl.DateTimeFormat("ru-RU", { day: "2-digit", month: "2-digit", year: "numeric" }).format(value)}
</p>
</div>
<Button
className="flex w-full flex-row items-center justify-center gap-2 self-end"
onClick={() => {
setShowTime(!showTime);
}}
>
<ClockIcon class="h-8" /> <p>Время</p>
</Button>
</ModalWindow>
);
};
ModalCalendar.displayName = "AHModalCalendar";
export default ModalCalendar;