import { useEntity, useReplicache } from "src/replicache"; import { BlockProps } from "./Block"; import { ChevronProps, DayPicker } from "react-day-picker"; import { Popover } from "components/Popover"; import { useEffect, useMemo, useState } from "react"; import { useEntitySetContext } from "components/EntitySetProvider"; import { useUIState } from "src/useUIState"; import { setHours, setMinutes } from "date-fns"; import { Separator } from "react-aria-components"; import { Checkbox } from "components/Checkbox"; import { useHasPageLoaded } from "components/InitialPageLoadProvider"; import { useSpring, animated } from "@react-spring/web"; import { ArrowRightTiny } from "components/Icons/ArrowRightTiny"; import { BlockCalendarSmall } from "components/Icons/BlockCalendarSmall"; export function DateTimeBlock(props: BlockProps) { const [isClient, setIsClient] = useState(false); let initialPageLoad = useHasPageLoaded(); useEffect(() => { setIsClient(true); }, []); if (!isClient && !initialPageLoad) return (
); return ; } export function BaseDateTimeBlock( props: BlockProps & { initalLoad?: boolean }, ) { let { rep } = useReplicache(); let { permissions } = useEntitySetContext(); let dateFact = useEntity(props.entityID, "block/date-time"); let selectedDate = useMemo(() => { if (!dateFact) return new Date(); let d = new Date(dateFact.data.value); return d; }, [dateFact]); const [timeValue, setTimeValue] = useState( () => `${selectedDate.getHours().toString().padStart(2, "0")}:${selectedDate.getMinutes().toString().padStart(2, "0")}`, ); let isSelected = useUIState((s) => s.selectedBlocks.find((b) => b.value === props.entityID), ); let isLocked = !!useEntity(props.entityID, "block/is-locked")?.data.value; let alignment = useEntity(props.entityID, "block/text-alignment")?.data.value; const handleTimeChange: React.ChangeEventHandler = (e) => { const time = e.target.value; setTimeValue(time); if (!dateFact) { return; } const [hours, minutes] = time.split(":").map((str) => parseInt(str, 10)); const newSelectedDate = setHours(setMinutes(selectedDate, minutes), hours); rep?.mutate.assertFact({ entity: props.entityID, data: { type: "date-time", value: newSelectedDate.toISOString(), dateOnly: dateFact?.data.dateOnly, originalTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone, }, attribute: "block/date-time", }); }; const handleDaySelect = (date: Date | undefined) => { if (!timeValue || !date) { if (date) rep?.mutate.assertFact({ entity: props.entityID, data: { originalTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone, type: "date-time", value: date.toISOString(), dateOnly: dateFact?.data.dateOnly, }, attribute: "block/date-time", }); return; } const [hours, minutes] = timeValue .split(":") .map((str) => parseInt(str, 10)); const newDate = new Date( date.getFullYear(), date.getMonth(), date.getDate(), hours, minutes, ); rep?.mutate.assertFact({ entity: props.entityID, data: { type: "date-time", value: newDate.toISOString(), originalTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone, dateOnly: dateFact?.data.dateOnly, }, attribute: "block/date-time", }); }; return ( {dateFact ? (
{selectedDate.toLocaleDateString(undefined, { month: "short", year: new Date().getFullYear() !== selectedDate.getFullYear() ? "numeric" : undefined, day: "numeric", })}{" "} {!dateFact.data.dateOnly ? ( |{" "} {selectedDate.toLocaleTimeString([], { hour: "numeric", minute: "numeric", })} ) : null}
) : (
{permissions.write ? "add a date and time..." : "TBD..."}
)}
} >
, }} classNames={{ months: "relative", month_caption: "font-bold text-center w-full bg-border-light mb-2 py-1 rounded-md", button_next: "absolute right-0 top-1 p-1 text-secondary hover:text-accent-contrast flex align-center", button_previous: "absolute left-0 top-1 p-1 text-secondary hover:text-accent-contrast rotate-180 flex align-center ", chevron: "text-inherit", month_grid: "w-full table-fixed", weekdays: "text-secondary text-sm", selected: "bg-accent-1! text-accent-2 rounded-md font-bold", day: "h-[34px] text-center rounded-md sm:hover:bg-border-light", outside: "text-border", today: "font-bold", }} mode="single" selected={dateFact ? selectedDate : undefined} onSelect={handleDaySelect} />
{ rep?.mutate.assertFact({ entity: props.entityID, data: { type: "date-time", value: dateFact?.data.value || new Date().toISOString(), originalTimezone: dateFact?.data.originalTimezone || Intl.DateTimeFormat().resolvedOptions().timeZone, dateOnly: e.currentTarget.checked, }, attribute: "block/date-time", }); }} > All day
); } let FadeIn = (props: { children: React.ReactNode; active: boolean }) => { let spring = useSpring({ opacity: props.active ? 1 : 0 }); return {props.children}; }; const CustomChevron = (props: ChevronProps) => { return (
); };