Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exclude out of bounds times #1718

Closed
wants to merge 1 commit into from

Conversation

PaulRBerg
Copy link
Contributor

@PaulRBerg PaulRBerg commented Apr 22, 2019

Description

Implements #1135. Use it by setting the excludeOutOfBoundsTimes prop on the DatePicker component. Example:

<DatePicker
  selected={this.state.startDate}
  excludeOutOfBoundsTimes
  onChange={this.handleChange}
  minDate={new Date()}
  placeholderText="Click to select a date"
  showTimeSelect
/>

How it works:

  • If you set a minDate or a maxDate, all times before that date's time will be deselected (if the active date matches the minDate or maxDate)
  • If you switch dates and select an available time, but then come back to the minDate or maxDate, that time will not be highlighted. I accomplished this by going to the renderTimes function of the Time component and change the base to be activeTime instead of new Date() - I hope there won't be any unexpected side effects.

Caveat: I didn't have time to add tests, but I added examples in the documentation site.

Result

Min Date

Screen Shot 2019-04-21 at 16 28 25

Max Date

Screen Shot 2019-04-21 at 16 28 44

@codecov
Copy link

codecov bot commented Apr 22, 2019

Codecov Report

Merging #1718 into master will decrease coverage by 0.44%.
The diff coverage is 30%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1718      +/-   ##
==========================================
- Coverage   90.29%   89.84%   -0.45%     
==========================================
  Files          17       17              
  Lines        1205     1211       +6     
  Branches      208      208              
==========================================
  Hits         1088     1088              
- Misses         10       16       +6     
  Partials      107      107
Impacted Files Coverage Δ
src/calendar.jsx 90% <ø> (+0.19%) ⬆️
src/index.jsx 90.58% <ø> (-0.54%) ⬇️
src/date_utils.js 97.18% <16.66%> (-1.99%) ⬇️
src/time.jsx 84.21% <50%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f22cb5c...239e47d. Read the comment docs.

@PaulRBerg PaulRBerg force-pushed the feat-exclude-times branch 3 times, most recently from ebbe988 to ab62cf3 Compare April 22, 2019 10:43
@Akash187
Copy link

Akash187 commented May 4, 2019

I guess "excludeOutOfBoundsTimes" is not implemented now in the official package. That's why it's not working for me.

@pcaplan-teladoc
Copy link

Great, I need this, when can it be merged and released?

@alfonmga
Copy link

We need to get this merged, it makes so much sense to have it.

@@ -379,6 +379,16 @@ export function isTimeInDisabledRange(time, { minTime, maxTime }) {
return valid;
}

export function isTimeInExcludedRange(time, { minDate, maxDate }) {
Copy link

@CruseCtrl CruseCtrl Jun 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function could be simplified to

return (isDate(minDate) && getDate(minDate) === getDate(time) && getTime(minDate) > getTime(time))
    || (isDate(maxDate) && getDate(maxDate) === getDate(time) && getTime(maxDate) < getTime(time))

@rdrnt
Copy link

rdrnt commented Oct 9, 2019

Any updates on this?

@stale
Copy link

stale bot commented Jan 7, 2020

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jan 7, 2020
@stale stale bot closed this Jan 21, 2020
@danielcardoso5
Copy link

It would be really useful to have this merged. I can't block times selection for the current day without blocking them for every other day.

@jotak
Copy link

jotak commented Jan 30, 2020

Hi @martijnrusschen , @CruseCtrl ,

Is there some reason to block this PR beside the only comment made by @CruseCtrl about a small simplification?
If that can help, I'm happy to take over this PR if there's more that needs to be worked on.

Thanks

@CruseCtrl
Copy link

I don't have any problem with it being merged

@thatguyjono94
Copy link

Please merge

@kylepeeler
Copy link

PLEASE merge it...

@khiner
Copy link

khiner commented Apr 12, 2020

Also looking for this feature to enforce min/max datetime. Anything holding this up? @PaulRBerg

@PaulRBerg
Copy link
Contributor Author

Hi @khiner, I am neither the author nor a maintainer of this library. I implemented the PR because I needed it for my own purposes at the time. @Hacker0x01 is the one to talk to.

@abhisaha1
Copy link

abhisaha1 commented Apr 20, 2020

I made it work this way:

const [startDate, setStartDate] = useState(new Date());

const isSelectedDateToday = new Date().getDate() === startDate.getDate();

let minTimeHour = new Date().getHours();
if (!isSelectedDateToday) minTimeHour = 0;

return (
  <DatePicker
      showTimeSelect
      selected={startDate}
      onChange={date => setStartDate(date)}
      minDate={new Date()}
      minTime={new Date(new Date().setHours(currentHour, 0, 0, 0))}
      maxTime={new Date(new Date().setHours(23, 59, 0, 0))}
      placeholderText="Select date and time"
   />
);

@ericvanular
Copy link

Please merge this...

Thanks @ajaxtown for the makeshift solution. Assuming you mean minTimeHour instead of currentHour in the minTime parameter. It will also set the min time as the hour you're currently in, so its still possible to set a time in the past.

@ghost
Copy link

ghost commented Sep 30, 2020

I made it work this way:

const [startDate, setStartDate] = useState(new Date());

const isSelectedDateToday = new Date().getDate() === startDate.getDate();

let minTimeHour = new Date().getHours();
if (!isSelectedDateToday) minTimeHour = 0;

return (
  <DatePicker
      showTimeSelect
      selected={startDate}
      onChange={date => setStartDate(date)}
      minDate={new Date()}
      minTime={new Date(new Date().setHours(currentHour, 0, 0, 0))}
      maxTime={new Date(new Date().setHours(23, 59, 0, 0))}
      placeholderText="Select date and time"
   />
);

This is extremely helpful, thank you. As mentioned in the comment below, the problem is that if you are within the same hour for example it still shows the time when it shouldn't. So, if it is 17:23 it is still allowing me to select 17:00 which it shouldn't. Any suggestions on how to fix that?

@ghost
Copy link

ghost commented Sep 30, 2020

Please merge this...

Thanks @ajaxtown for the makeshift solution. Assuming you mean minTimeHour instead of currentHour in the minTime parameter. It will also set the min time as the hour you're currently in, so its still possible to set a time in the past.

I have asked ajaxTown if they have a solution for the being able to set a time in the past but also asking you in case you had a solution?

@abhisaha1
Copy link

abhisaha1 commented Oct 1, 2020

So, if it is 17:23 it is still allowing me to select 17:00 which it shouldn't. Any suggestions on how to fix that?

@ericvanular @Jonofat you can manage the time this way:

const [startDate, setStartDate] = useState(new Date());

const isSelectedDateToday = new Date().getDate() === startDate.getDate();
const isSelectedDateInFuture = +startDate > +new Date();

let minTimeHour = new Date().getHours();
if (!isSelectedDateToday) minTimeHour = 0;

const date = new Date();
let currentMins = date.getMinutes();
let currentHour = date.getHours();
if (isSelectedDateInFuture) {
  currentHour = 0;
  currentMins = 0;
}
return (
  <DatePicker
    showTimeSelect
    selected={startDate}
    onChange={date => setStartDate(date)}
    minDate={new Date()}
    minTime={new Date(new Date().setHours(currentHour, currentMins, 0, 0))}
    maxTime={new Date(new Date().setHours(23, 59, 0, 0))}
    placeholderText="Select date and time"
  />
);

Edit: @Jonofat pointed out that this would not work for the future date. Because the time is still being treat as if its today. I have changed the solution to tackle that.

@ghost
Copy link

ghost commented Oct 1, 2020

@ajaxtown, thank you! This looks pretty good and is working for the current date. However if I choose tomorrow or any day in the future it still limits the time to what it is now eg: If it is 3:30pm it shows from 4pm. So I can't pick anything before 3:00pm for tomorrow which I should be able to.

I have had to change my code unfortunately before you posted your answer:

const DatePickerField = ({ ...props }) => {
  const { setFieldValue } = useFormikContext();
  const [field, meta] = useField(props);
  const [startDate, setStartDate] = useState(new Date());

  const isSelectedDateToday = new Date().getDate() === startDate.getDate();
  const isSelectedDateInFuture = +startDate > +new Date();

  let minTimeHour = new Date().getHours();
  if (!isSelectedDateToday) minTimeHour = 8;

  const date = new Date();
  let currentMins = date.getMinutes();
  let currentHour = date.getHours();
  if (isSelectedDateInFuture) {
    currentHour = 0;
    currentMins = 0;
  }

  return (
    <span className="input-field">
      <DatePicker
        {...field}
        {...props}
        selected={(field.value && new Date(field.value)) || null}
        onChange={(val) => {
          setFieldValue(field.name, val);
        }}
        value={(field.value && new Date(field.value)) || null}
        minTime={new Date(new Date().setHours(currentHour, currentMins, 0, 0))}
        maxTime={new Date(new Date().setHours(17, 0, 0))}
        maxDate={addDays(new Date(), 3)}
        excludeTimes={excluded.map((exclude) => {
          if (field.value && field.value.getDay() === exclude.day) {
            return new Date(new Date().setHours(exclude.time, 0, 0));
          }
          return null;
        })}
        className="date-input"
      />
      <span className="input-error">
        {meta.error && meta.touched && meta.error}
      </span>
    </span>
  );
};

export default DatePickerField;

@abhisaha1
Copy link

@Jonofat ah yes, I missed that one out. Thanks for testing and letting me know. I have edited my answer to tackle that scenario as well.

@ghost
Copy link

ghost commented Oct 1, 2020

@ajaxtown, thanks once again! I have edited my code above with your changes but it seems to still be doing the same thing ie: issue not resolved. I am trying to troubleshoot...

EDIT: Okay, found my problem. Now seems to work really nicely :) Thanks so much!

@ghost
Copy link

ghost commented Oct 1, 2020

@ajaxtown Ah, I spoke too soon! One last issue I think. If I have my max time is 5pm (ie: I should not be able to choose a time past 5pm on any given day ) and it is now 5:37 pm, it should show no times for today but it is showing everything from 00:00 to 23:00. It was working 100% when it was before 5pm today.

@abhisaha1
Copy link

@Jonofat can this be a timezone issue ?

@ghost
Copy link

ghost commented Oct 4, 2020

@ajaxtown, I don't think it is a time zone issue ( I am working on my localhost). I have only allowed times between 8am and 5pm on Monday - Friday and 8am - 1pm on Saturday. But it is showing times for a whole 24 hours and ignoring my allowed times so I think it might be something else?

const excluded = [
  {
    time: "14",
    day: 6,
  },
  {
    time: "15",
    day: 6,
  },
  {
    time: "16",
    day: 6,
  },
  {
    time: "17",
    day: 6,
  },
];

  const isSelectedDateToday = new Date().getDate() === startDate.getDate();
  const isSelectedDateInFuture = +field.value > +new Date();

  const date = new Date();
  let currentMins = date.getMinutes();
  let currentHour = date.getHours();
  if (isSelectedDateInFuture) {
    currentHour = 8;
    currentMins = 0;
  }

//Only showing minTime/maxTime & excludedTimes for date picker below
minTime={new Date(new Date().setHours(currentHour, currentMins, 0, 0))}
maxTime={new Date(new Date().setHours(17, 0, 0))}

        excludeTimes={excluded.map((exclude) => {
          if (field.value && field.value.getDay() === exclude.day) {
            return new Date(new Date().setHours(exclude.time, 0, 0));
          }
          return null;
        })}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet