Search code examples
javascriptreactjsreact-date-range

How to auto close date range modal after date range select in react-date-range


Date range should be automatically closed when i click on any date or after selecting date range.

import React, { useState, useCallback } from 'react'
import { DateRange } from 'react-date-range'
import { withStyles } from '@material-ui/styles'
import {
    TextField,
    Popover,
    InputAdornment,
    IconButton,
} from '@material-ui/core'
import DateRangeIcon from '@material-ui/icons/DateRange'
import ClearIcon from '@material-ui/icons/Clear'
import moment from 'moment'
import { useSelector } from 'react-redux'
import 'react-date-range/dist/styles.css'
import 'react-date-range/dist/theme/default.css'
import { getLocaleDateString } from '../../../utils/date'
import './style.css'


const styles = {
    calendarWrapper: {
        padding: '16px',
    },
}


const BasicDateRangePicker = ({ onChange, label, onClear, value }) => {

    const { countryCode } = useSelector(state => state.authentication)
    const formatDate = date => moment(date).format(getLocaleDateString(countryCode, 'date'))
    const initialState = {
        anchorEl: null,
        calendarConfig: [ value ],
        displayCalendar: false,
        focusedRange: [ 0, 0 ],
        inputValue: value.startDate !== null ? formatDate(value.startDate) + '         to        ' + formatDate(value.endDate) : ''
    }
    const divRef = React.useRef()
    const [ state, setState ] = useState(initialState)

    const handleClear = useCallback(() => {
        onClear({clear: true})
        setState(state => {
            return {
                ...state,
                calendarConfig: [ {
                    endDate: new Date(),
                    key: 'selection',
                    startDate: new Date()
                } ],
                inputValue: '',
            }
        })
        // setState(initialState)

    })

    const setFocusedRange = useCallback(focusedRange => {
        setState(state => {
            return { ...state, focusedRange }
        })
    })

    const handleOnChange = useCallback(item => {
        const startDate = formatDate(item.selection.startDate)
        const endDate = formatDate(item.selection.endDate)
        const inputValue = `${startDate}         to         ${endDate}`
        onChange(item)
        setState(state => {
            return {
                ...state,
                calendarConfig: [ item.selection ],
                inputValue: inputValue,
            }
        })
    })
    const onAdornmentClick = useCallback(() => {
        setState(state => {
            return {
                ...state,
                anchorEl: divRef.current,
                displayCalendar: true,
            }
        })
    })

    const onPopoverClose = useCallback(() => {
        setState(state => {
            return {
                ...state,
                anchorEl: null,
                displayCalendar: false,
            }
        })
    })

    return (
        <div style={{ display: 'flex', flexDirection: 'column' }} ref={divRef}>
            <TextField
                label={label}
                value={state.inputValue}
                InputProps={{
                    endAdornment: (
                        <InputAdornment position='end'>
                            <IconButton style={{ padding: '3px' }}>
                                {state.inputValue?.length > 1 ? (
                                    <ClearIcon onClick={handleClear} />
                                ) : (
                                    <DateRangeIcon onClick={onAdornmentClick} />
                                )}
                            </IconButton>
                        </InputAdornment>
                    ),
                }}
            />
            <Popover
                open={state.displayCalendar}
                anchorEl={state.anchorEl}
                anchorOrigin={{
                    horizontal: 'center',
                    vertical: 'bottom',
                }}
                transformOrigin={{
                    horizontal: 'center',
                    vertical: 'top',
                }}
                onClose={onPopoverClose}
            >
                <DateRange
                    focusedRange={state.focusedRange}
                    onRangeFocusChange={setFocusedRange}
                    onChange={handleOnChange}
                    showSelectionPreview={false}
                    moveRangeOnFirstSelection={false}
                    ranges={state.calendarConfig}
                    editableDateInputs={false}
                    months={1}
                />
            </Popover>
        </div>
    )
}

export default withStyles(styles, { name: 'BasicDateRangePicker' })(
    BasicDateRangePicker
)

Solution

  • I have resolve the auto close popover after selecting date reange selection by applying condition on datechange event in the following way

           if (startDate !== endDate) {
                const inputValue = `${startDate}         to         ${endDate}`
                onChange(item)
                setState(state => {
                    return {
                        ...state,
                        anchorEl: null,
                        calendarConfig: [ item.selection ],
                        displayCalendar: false,
                        inputValue: inputValue,
                    }
                })
            } else {
                setState(state => {
                    return {
                        ...state,
                        calendarConfig: [ item.selection ],
                    }
                })
            }
    

    complete code:

    import React, { useState, useCallback } from 'react'
    import { DateRange } from 'react-date-range'
    import { withStyles } from '@material-ui/styles'
    import {
        TextField,
        Popover,
        InputAdornment,
        IconButton,
    } from '@material-ui/core'
    import DateRangeIcon from '@material-ui/icons/DateRange'
    import ClearIcon from '@material-ui/icons/Clear'
    import moment from 'moment'
    import { useSelector } from 'react-redux'
    import 'react-date-range/dist/styles.css'
    import 'react-date-range/dist/theme/default.css'
    import { getLocaleDateString } from '../../../utils/date'
    import './style.css'
    
    
    const styles = {
        calendarWrapper: {
            padding: '16px',
        },
    }
    
    
    const BasicDateRangePicker = ({ onChange, label, onClear, value }) => {
    
        const { countryCode } = useSelector(state => state.authentication)
        const formatDate = date => moment(date).format(getLocaleDateString(countryCode, 'date'))
        const initialState = {
            anchorEl: null,
            calendarConfig: [ value ],
            displayCalendar: false,
            focusedRange: [ 0, 0 ],
            inputValue: value.startDate !== null ? formatDate(value.startDate) + '         to        ' + formatDate(value.endDate) : ''
        }
        const divRef = React.useRef()
        const [ state, setState ] = useState(initialState)
    
        const handleClear = useCallback(() => {
            onClear({clear: true})
            setState(state => {
                return {
                    ...state,
                    calendarConfig: [ {
                        endDate: new Date(),
                        key: 'selection',
                        startDate: new Date()
                    } ],
                    inputValue: '',
                }
            })
            // setState(initialState)
    
        })
    
        const setFocusedRange = useCallback(focusedRange => {
            setState(state => {
                return { ...state, focusedRange }
            })
        })
    
        const handleOnChange = useCallback(item => {
            const startDate = formatDate(item.selection.startDate)
            const endDate = formatDate(item.selection.endDate)
            if (startDate !== endDate) {
                const inputValue = `${startDate}         to         ${endDate}`
                onChange(item)
                setState(state => {
                    return {
                        ...state,
                        anchorEl: null,
                        calendarConfig: [ item.selection ],
                        displayCalendar: false,
                        inputValue: inputValue,
                    }
                })
            } else {
                setState(state => {
                    return {
                        ...state,
                        calendarConfig: [ item.selection ],
                    }
                })
            }
        })
        const onAdornmentClick = useCallback(() => {
            setState(state => {
                return {
                    ...state,
                    anchorEl: divRef.current,
                    displayCalendar: true,
                }
            })
        })
    
        const onPopoverClose = useCallback(() => {
            setState(state => {
                return {
                    ...state,
                    anchorEl: null,
                    displayCalendar: false,
                }
            })
        })
    
        return (
            <div style={{ display: 'flex', flexDirection: 'column' }} ref={divRef}>
                <TextField
                    label={label}
                    value={state.inputValue}
                    InputProps={{
                        endAdornment: (
                            <InputAdornment position='end' onClick={state.inputValue?.length > 1 ? handleClear : onAdornmentClick}>
                                <IconButton style={{ padding: '3px' }}>
                                    {state.inputValue?.length > 1 ? (
                                     <ClearIcon/>
                                     ) : (
                                     <DateRangeIcon/>
                                    )}
                                </IconButton>
                            </InputAdornment>
                        ),
                    }}
                />
                <Popover
                    open={state.displayCalendar}
                    anchorEl={state.anchorEl}
                    anchorOrigin={{
                        horizontal: 'center',
                        vertical: 'bottom',
                    }}
                    transformOrigin={{
                        horizontal: 'center',
                        vertical: 'top',
                    }}
                    onClose={onPopoverClose}
                >
                    <DateRange
                        focusedRange={state.focusedRange}
                        onRangeFocusChange={setFocusedRange}
                        onChange={handleOnChange}
                        showSelectionPreview={false}
                        moveRangeOnFirstSelection={false}
                        ranges={state.calendarConfig}
                        editableDateInputs={false}
                        months={1}
                    />
                </Popover>
            </div>
        )
    }
    
    export default withStyles(styles, { name: 'BasicDateRangePicker' })(
        BasicDateRangePicker
    )