hypeserver / react-date-range

A React component for choosing dates and date ranges.
MIT License
2.6k stars 679 forks source link

Maximum days restriction #449

Open Yashas0796 opened 3 years ago

Yashas0796 commented 3 years ago

Subject of the issue

Max days restriction

[BUG] Bug Reproduce Steps

How to add max. no. of days restriction. Ex. I should be able to select only max of one day.

[BUG] Expected behaviour

Environment

Package Version: React version: Node version: Browser:

kamyar commented 3 years ago

I should be able to select only max of one day.

I am confused what you intend to do, is it:

  1. Maximum date user can select is is before a specific date lik 2023-04-01
  2. Range user can select can not include more than a numbers of days
    • e.g. 14 days, so (2021-05-01, 2021-05-15) is acceptable ✅ but not (2021-05-01, 2021-05-30) is not ❌
lhimstedt commented 2 years ago

I should be able to select only max of one day.

I am confused what you intend to do, is it:

  1. Maximum date user can select is is before a specific date lik 2023-04-01
  2. Range user can select can not include more than a numbers of days

    • e.g. 14 days, so (2021-05-01, 2021-05-15) is acceptable ✅ but not (2021-05-01, 2021-05-30) is not ❌

@kamyar I think he has the same problem as me. We need to restrict the selected date range to 30 days. Min and max date are not applicable because you should be allowed to choose, for example, the last month, not only 30 days in the past. An option would be to update the min and max date dynamically, but I found no prop to detect a running selection.

PetrisorIustin commented 2 years ago

@kamyar @lhimstedt I am also having the same problem. I want to restrict the number of days for the range starting from any date.

ghost commented 2 years ago

Exactly for the same please check my post with full code at https://stackoverflow.com/a/70403423/3574669

This will restrict to selection before and after from the range startDate by a maxDays.

However, reproducing the code below as well,

import React, {useState, useEffect} from "react"
import {makeStyles} from "@material-ui/core/styles";
import { DateRangePicker } from 'react-date-range';
import 'react-date-range/dist/styles.css'; // main style file
import 'react-date-range/dist/theme/default.css';
import { addDays, subDays } from "date-fns"; // theme css file

const useStyles = makeStyles(theme => ({
  root:{
    // padding: 16
  }
}))

const selectionRange = {
  startDate: new Date(),
  endDate: new Date(),
  key: 'dateRange',
}

const DateRange = (props) => {
  const classes = useStyles();
  const {
    dateRange, 
    onSelectPeriod, 
    hides, 
    minDate, 
    maxDate,
    maxDays
  } = props
  const [period, setPeriod] = useState(selectionRange)
  const [miDate, setMiDate] = useState(new Date(1970, 1, 1))
  const [maDate, setMaDate] = useState(new Date(2100, 1, 1))

  useEffect(()=>{
    if(dateRange) {
      setPeriod(dateRange)
    } 

    if(hides)
      hides.map((num, index) => {
        (document.getElementsByClassName('rdrStaticRanges')[0]).childNodes[num-index].remove();
      })

    if(minDate != null) setMiDate(minDate)
    if(maxDate != null) setMaDate(maxDate)
  },[])

  useEffect(()=>{
    onSelectPeriod(period)
  },[period])

  const handleSelect = (ranges) => {
    if(ranges === undefined) return
    // console.log("DateRangePicker: ", ranges)    
    setPeriod(ranges.dateRange)

    // set to restrict only maxDays range selection; post selection it reset to as initial for further selection
    if(maxDays != null) {
      if(ranges.dateRange.startDate.getTime() === ranges.dateRange.endDate.getTime()){
        // REstrict maxDays before or after for selection
        setMiDate(subDays(ranges.dateRange.startDate, maxDays-1))
        const mDate = addDays(ranges.dateRange.startDate, maxDays-1)
        if(mDate.getTime() <= maxDate.getTime()) setMaDate(mDate)
      } else {
        // RESET as INITIAL
        if(minDate != null) {
          setMiDate(minDate) 
        } else {
          setMiDate(new Date(1970, 1, 1))
        }

        if(maxDate != null) {
          setMaDate(maxDate)
        } else {
          setMaDate(new Date(2100, 1, 1))
        }
      }
    }
  }

  return (
    <div className={classes.root}>
      <DateRangePicker
        ranges={[period]}
        onChange={handleSelect}
        minDate={miDate}
        maxDate={maDate}
      />
    </div>
  )
}

export default DateRange
danny-dang commented 10 months ago

To achieve this, we can easily set minDate and maxDate when user select date. Just need to check if the startDate and endDate of the selected is the same. Example:


const [tempDateLimit, setTempDateLimit] = useState<
  | {
      minDate: Date;
      maxDate: Date;
    }
  | undefined
>();

const handleOnChange = (keyDict: RangeKeyDict) => {
  const selected = keyDict.selection;
  const isSameDate =
    selected.startDate?.getTime() === selected.endDate?.getTime();
  setSelectedDate({ ...selected });
  if (isSameDate && selected.startDate && selected.startDate) {
    const tempMinDate = moment(selected.startDate)
      .subtract(30, 'days')
      .toDate();
    const tempMaxDate = moment(selected.startDate)
      .add(30, 'days')
      .toDate();
    setTempDateLimit({
      minDate: tempMinDate,
      maxDate: tempMaxDate,
    });
  } else {
    setTempDateLimit(undefined);
  }
};

return ( <DateRangePicker
              {...props}
              onChange={handleOnChange}
              minDate={tempDateLimit?.minDate}
              maxDate={tempDateLimit?.maxDate}
            />)