Skip to content

Commit 2ffa7c8

Browse files
authored
Merge pull request hypeserver#221 from thijssteel/master
Enable disabling of certain dates
2 parents ca5ddd8 + 39f5c59 commit 2ffa7c8

File tree

6 files changed

+70
-6
lines changed

6 files changed

+70
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ Momentjs: `moment(dateString).toDate()`
114114
- `specialDays` prop removed.
115115

116116
### Added
117+
- `disabledDates` prop: It's a set of disabled dates.
117118
- `DefinedRanges` component: It's a set of date presets. Receives `inputRanges`, `staticRanges` for setting date ranges.
118119
- `DateRangePicker` component. It's combined version of `DateRange` with `DefinedRanges` component.
119120
- Date range selection by drag.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ shownDate | Date | | initial fo
109109
minDate | Date | | defines minimum date. Disabled earlier dates
110110
maxDate | Date | | defines maximum date. Disabled later dates
111111
direction | String | 'vertical' | direction of calendar months. can be `vertical` or `horizontal`
112+
disabledDates | Date[] | [] | dates that are disabled
112113
scroll | Object | { enabled: false }| infinite scroll behaviour configuration. Check out [Infinite Scroll](#infinite-scrolled-mode) section
113114
showMonthArrow | Boolean | true | show/hide month arrow button
114115
navigatorRenderer | Func | | renderer for focused date navigation area. fn(currentFocusedDate: Date, changeShownDate: func, props: object)

demo/src/components/Main.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ export default class Main extends Component {
7272
key: 'selection',
7373
},
7474
},
75+
dateRangeWithDisabled: {
76+
selection: {
77+
startDate: addDays(new Date(), 4),
78+
endDate: null,
79+
key: 'selection',
80+
},
81+
},
7582
definedRange: {
7683
selection: {
7784
startDate: new Date(),
@@ -316,6 +323,32 @@ export default class Main extends Component {
316323
className={'centered'}
317324
/>
318325
</Section>
326+
<Section title="RangePicker with disabled dates">
327+
<div>
328+
<input
329+
type="text"
330+
readOnly
331+
value={formatDateDisplay(this.state.dateRangeWithDisabled.selection.startDate)}
332+
/>
333+
<input
334+
type="text"
335+
readOnly
336+
value={formatDateDisplay(
337+
this.state.dateRangeWithDisabled.selection.endDate,
338+
'Continuous'
339+
)}
340+
/>
341+
</div>
342+
343+
<DateRange
344+
onChange={this.handleRangeChange.bind(this, 'dateRangeWithDisabled')}
345+
moveRangeOnFirstSelection={false}
346+
ranges={[this.state.dateRangeWithDisabled.selection]}
347+
className={'PreviewArea'}
348+
disabledDates={[new Date(), addDays(new Date(), 3)]}
349+
minDate={addDays(new Date(), -3)}
350+
/>
351+
</Section>
319352
</main>
320353
);
321354
}

src/components/Calendar.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ class Calendar extends PureComponent {
351351
onPreviewChange,
352352
scroll,
353353
direction,
354+
disabledDates,
354355
maxDate,
355356
minDate,
356357
rangeColors,
@@ -409,6 +410,7 @@ class Calendar extends PureComponent {
409410
key={key}
410411
drag={this.state.drag}
411412
dateOptions={this.dateOptions}
413+
disabledDates={disabledDates}
412414
month={monthStep}
413415
onDragSelectionStart={this.onDragSelectionStart}
414416
onDragSelectionEnd={this.onDragSelectionEnd}
@@ -445,6 +447,7 @@ class Calendar extends PureComponent {
445447
key={i}
446448
drag={this.state.drag}
447449
dateOptions={this.dateOptions}
450+
disabledDates={disabledDates}
448451
month={monthStep}
449452
onDragSelectionStart={this.onDragSelectionStart}
450453
onDragSelectionEnd={this.onDragSelectionEnd}
@@ -466,6 +469,7 @@ class Calendar extends PureComponent {
466469
Calendar.defaultProps = {
467470
showMonthArrow: true,
468471
showMonthAndYearPickers: true,
472+
disabledDates: [],
469473
classNames: {},
470474
locale: defaultLocale,
471475
ranges: [],
@@ -490,6 +494,7 @@ Calendar.defaultProps = {
490494
Calendar.propTypes = {
491495
showMonthArrow: PropTypes.bool,
492496
showMonthAndYearPickers: PropTypes.bool,
497+
disabledDates: PropTypes.array,
493498
minDate: PropTypes.object,
494499
maxDate: PropTypes.object,
495500
date: PropTypes.object,

src/components/DateRange.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
33
import Calendar from './Calendar.js';
44
import { rangeShape } from './DayCell';
55
import { findNextRangeIndex, generateStyles } from '../utils.js';
6-
import { isBefore, differenceInCalendarDays, addDays, min } from 'date-fns';
6+
import { isBefore, differenceInCalendarDays, addDays, min, isWithinInterval, max } from 'date-fns';
77
import classnames from 'classnames';
88
import coreStyles from '../styles';
99

@@ -22,7 +22,7 @@ class DateRange extends Component {
2222
}
2323
calcNewSelection(value, isSingleValue = true) {
2424
const focusedRange = this.props.focusedRange || this.state.focusedRange;
25-
const { ranges, onChange, maxDate, moveRangeOnFirstSelection } = this.props;
25+
const { ranges, onChange, maxDate, moveRangeOnFirstSelection, disabledDates } = this.props;
2626
const focusedRangeIndex = focusedRange[0];
2727
const selectedRange = ranges[focusedRangeIndex];
2828
if (!selectedRange || !onChange) return {};
@@ -43,16 +43,35 @@ class DateRange extends Component {
4343
} else {
4444
endDate = value;
4545
}
46+
4647
// reverse dates if startDate before endDate
48+
let isStartDateSelected = focusedRange[1] === 0;
4749
if (isBefore(endDate, startDate)) {
50+
isStartDateSelected = !isStartDateSelected;
4851
[startDate, endDate] = [endDate, startDate];
4952
}
5053

54+
const inValidDatesWithinRange = disabledDates.filter(disabledDate =>
55+
isWithinInterval(disabledDate, {
56+
start: startDate,
57+
end: endDate,
58+
})
59+
);
60+
61+
if (inValidDatesWithinRange.length > 0) {
62+
if (isStartDateSelected) {
63+
startDate = addDays(max(inValidDatesWithinRange), 1);
64+
} else {
65+
endDate = addDays(min(inValidDatesWithinRange), -1);
66+
}
67+
}
68+
5169
if (!nextFocusRange) {
5270
const nextFocusRangeIndex = findNextRangeIndex(this.props.ranges, focusedRange[0]);
5371
nextFocusRange = [nextFocusRangeIndex, 0];
5472
}
5573
return {
74+
wasValid: !(inValidDatesWithinRange.length > 0),
5675
range: { startDate, endDate },
5776
nextFocusRange: nextFocusRange,
5877
};
@@ -88,7 +107,7 @@ class DateRange extends Component {
88107
const { rangeColors, ranges } = this.props;
89108
const focusedRange = this.props.focusedRange || this.state.focusedRange;
90109
const color = ranges[focusedRange[0]].color || rangeColors[focusedRange[0]] || color;
91-
this.setState({ preview: { ...val, color } });
110+
this.setState({ preview: { ...val.range, color } });
92111
}
93112
render() {
94113
return (
@@ -97,7 +116,7 @@ class DateRange extends Component {
97116
onRangeFocusChange={this.handleRangeFocusChange}
98117
preview={this.state.preview}
99118
onPreviewChange={value => {
100-
this.updatePreview(value ? this.calcNewSelection(value).range : null);
119+
this.updatePreview(value ? this.calcNewSelection(value) : null);
101120
}}
102121
{...this.props}
103122
displayMode="dateRange"
@@ -117,6 +136,7 @@ DateRange.defaultProps = {
117136
ranges: [],
118137
moveRangeOnFirstSelection: false,
119138
rangeColors: ['#3d91ff', '#3ecf8e', '#fed14c'],
139+
disabledDates: [],
120140
};
121141

122142
DateRange.propTypes = {

src/components/Month.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function renderWeekdays(styles, dateOptions) {
3636
class Month extends PureComponent {
3737
render() {
3838
const now = new Date();
39-
const { displayMode, focusedRange, drag, styles } = this.props;
39+
const { displayMode, focusedRange, drag, styles, disabledDates } = this.props;
4040
const minDate = this.props.minDate && startOfDay(this.props.minDate);
4141
const maxDate = this.props.maxDate && endOfDay(this.props.maxDate);
4242
const monthDisplay = getMonthDisplayRange(this.props.month, this.props.dateOptions);
@@ -68,6 +68,9 @@ class Month extends PureComponent {
6868
const isEndOfMonth = isSameDay(day, monthDisplay.endDateOfMonth);
6969
const isOutsideMinMax =
7070
(minDate && isBefore(day, minDate)) || (maxDate && isAfter(day, maxDate));
71+
const isDisabledSpecifically = disabledDates.some(disabledDate =>
72+
isSameDay(disabledDate, day)
73+
);
7174
return (
7275
<DayCell
7376
{...this.props}
@@ -81,7 +84,7 @@ class Month extends PureComponent {
8184
isStartOfMonth={isStartOfMonth}
8285
isEndOfMonth={isEndOfMonth}
8386
key={index}
84-
disabled={isOutsideMinMax}
87+
disabled={isOutsideMinMax || isDisabledSpecifically}
8588
isPassive={
8689
!isWithinInterval(day, {
8790
start: monthDisplay.startDateOfMonth,
@@ -112,6 +115,7 @@ Month.propTypes = {
112115
month: PropTypes.object,
113116
drag: PropTypes.object,
114117
dateOptions: PropTypes.object,
118+
disabledDates: PropTypes.array,
115119
preview: PropTypes.shape({
116120
startDate: PropTypes.object,
117121
endDate: PropTypes.object,

0 commit comments

Comments
 (0)