import React, { ComponentPropsWithoutRef, Fragment, MouseEvent, useRef, } from 'react'; import {parseAbsoluteToLocal, ZonedDateTime} from '@internationalized/date'; import {useController} from 'react-hook-form'; import {mergeProps} from '@react-aria/utils'; import { DatePickerValueProps, useDatePickerState, } from './use-date-picker-state'; import {DialogTrigger} from '@common/ui/overlays/dialog/dialog-trigger'; import {DateRangeIcon} from '@common/icons/material/DateRange'; import {Dialog} from '@common/ui/overlays/dialog/dialog'; import {DialogBody} from '@common/ui/overlays/dialog/dialog-body'; import {Calendar} from '../calendar/calendar'; import { DatePickerField, DatePickerFieldProps, } from '../date-range-picker/date-picker-field'; import {DateSegmentList} from '../segments/date-segment-list'; import {useDateFormatter} from '@common/i18n/use-date-formatter'; import {useTrans} from '@common/i18n/use-trans'; import clsx from 'clsx'; import {DialogFooter} from '@common/ui/overlays/dialog/dialog-footer'; import {Button} from '@common/ui/buttons/button'; import {Trans} from '@common/i18n/trans'; import {useCurrentDateTime} from '@common/i18n/use-current-date-time'; export interface DatePickerProps extends Omit, DatePickerValueProps {} export function DatePicker({showCalendarFooter, ...props}: DatePickerProps) { const state = useDatePickerState(props); const inputRef = useRef(null); const now = useCurrentDateTime(); const footer = showCalendarFooter && ( { state.clear(); }} > } > ); const dialog = ( {footer} ); const openOnClick: ComponentPropsWithoutRef<'div'> = { onClick: e => { e.stopPropagation(); e.preventDefault(); if (!isHourSegment(e)) { state.setCalendarIsOpen(true); } else { state.setCalendarIsOpen(false); } }, }; return ( } {...props} > {dialog} ); } interface FormDatePickerProps extends DatePickerProps { name: string; } export function FormDatePicker(props: FormDatePickerProps) { const {min, max} = props; const {trans} = useTrans(); const {format} = useDateFormatter(); const { field: {onChange, onBlur, value = null, ref}, fieldState: {invalid, error}, } = useController({ name: props.name, rules: { validate: v => { if (!v) return; const date = parseAbsoluteToLocal(v); if (min && date.compare(min) < 0) { return trans({ message: 'Enter a date after :date', values: {date: format(v)}, }); } if (max && date.compare(max) > 0) { return trans({ message: 'Enter a date before :date', values: {date: format(v)}, }); } }, }, }); const parsedValue: null | ZonedDateTime = value ? parseAbsoluteToLocal(value) : null; const formProps: Partial = { onChange: e => { onChange(e ? e.toAbsoluteString() : e); }, onBlur, value: parsedValue, invalid, errorMessage: error?.message, inputRef: ref, }; return ; } function isHourSegment(e: MouseEvent): boolean { return ['hour', 'minute', 'dayPeriod'].includes( (e.currentTarget as HTMLElement).ariaLabel || '' ); }