import * as React from 'react'; import { isNil, isDate } from 'lodash'; import { Div } from '../../components/Div'; import { LedaContext } from '../../components/LedaProvider'; import { Span } from '../../components/Span'; import { useElement } from '../../utils'; import { VIEW_TYPES } from '../Calendar/constants'; import { MaskedInputBase } from '../MaskedInputBase'; import { setDate, setViewDate } from './actions'; import { stringToDate, } from './helpers'; import { stateReducer } from './reducer'; import { AllActions, CustomElements, DateTimeInputProps, DateTimeInputState, EffectData, } from './types'; export const useDateTimeInputEffects = ({ conditions, dispatch, props, state, }: EffectData): void => { const { value: valueProp, format = 'dd.MM.yyyy', min, max, } = props; const { date: dateState, isFocused, } = state; React.useEffect(() => { const dateValue = isDate(valueProp) || valueProp == null ? valueProp : null; if (dateValue && !isFocused) { dispatch(setDate(dateValue)); } }, [valueProp, dispatch, isFocused]); React.useEffect(() => { // синхронизируем отображение календаря с value if (dateState && conditions.isValueInRange) dispatch(setViewDate(dateState)); }, [conditions.isValueInRange, dispatch, dateState]); React.useEffect(() => { // если в value пустая строка - нужно обнулить date для валидации if (isDate(valueProp) || isNil(valueProp) || isFocused) return; if (valueProp.length === 0) { dispatch(setDate(null)); } const newDate = stringToDate(valueProp, format); // если в инпуте валидная дата - записываем в date, иначе - запиываем null if (newDate && newDate.getDate()) dispatch(setDate(newDate)); else dispatch(setDate(null)); }, [dispatch, format, isFocused, max, min, valueProp]); }; export const useDateTimeInputState = (props: DateTimeInputProps): [DateTimeInputState, React.Dispatch<AllActions>] => { const { value: valueProp, format, min, max, } = props; // если сегодняшняя дата за пределами min/max - открываем календарь с датой min или max const todayIsMin = (min && new Date() < min) ? min : null; const todayIsMax = (max && new Date() > max) ? max : null; // сегодня, время берется равно 00:00 const today = new Date(); const stringValue = isDate(valueProp) || valueProp === null ? '' : valueProp; const initialState = { date: null, value: '', isValid: true, isFocused: false, isOpen: false, viewDate: todayIsMin || todayIsMax || stringToDate(stringValue, format) || today, viewType: VIEW_TYPES.DATES, }; const [state, dispatch] = React.useReducer(stateReducer, initialState); return [state, dispatch]; }; export const useCustomElements = (props: DateTimeInputProps, state: DateTimeInputState): CustomElements => { const { wrapperRender, iconRender, inputRender } = props; const { renders: { dateTimeInput: dateTimeInputRenders } } = React.useContext(LedaContext); const Wrapper = useElement( 'Wrapper', Div, wrapperRender || dateTimeInputRenders.wrapperRender, props, state, ); const Icon = useElement( 'Icon', Span, iconRender || dateTimeInputRenders.iconRender, props, state, ); const Input = useElement( 'Input', MaskedInputBase, inputRender || dateTimeInputRenders.inputRender, props, state, ); return { Wrapper, Input, Icon, }; };