Skip to content

Commit

Permalink
Merge pull request hypeserver#492 from strada/master
Browse files Browse the repository at this point in the history
Update range selection behavior
  • Loading branch information
kamyar authored Jun 13, 2021
2 parents 66b385a + 67aee9f commit 17a7900
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 9 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ scroll | Object | { enabled: false }| infinite
showMonthArrow | Boolean | true | show/hide month arrow button
navigatorRenderer | Func | | renderer for focused date navigation area. fn(currentFocusedDate: Date, changeShownDate: func, props: object)
ranges | *Object[] | [] | Defines ranges. array of range object
moveRangeOnFirstSelection(DateRange) | Boolean | false | move range on startDate selection. Otherwise endDate will replace with startDate.
moveRangeOnFirstSelection(DateRange) | Boolean | false | move range on startDate selection. Otherwise endDate will replace with startDate unless `retainEndDateOnFirstSelection` is set to true.
retainEndDateOnFirstSelection(DateRange) | Boolean | false | Retain end date when the start date is changed, unless start date is later than end date. Ignored if `moveRangeOnFirstSelection` is set to true.
onChange(Calendar) | Func | | callback function for date changes. fn(date: Date)
onChange(DateRange) | Func | | callback function for range changes. fn(changes). changes contains changed ranges with new `startDate`/`endDate` properties.
color(Calendar) | String | `#3d91ff` | defines color for selected date in Calendar
Expand Down
7 changes: 4 additions & 3 deletions src/components/DateRange/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ This component extends all the props of **[Calendar](#calendar)** component. In
| Prop Name | Type |
|---|---|
| **moveRangeOnFirstSelection** | boolean |
| **onRangeFocusChange** | function |
| **rangeColors** | array |
| **ranges** | array |
| **retainEndDateOnFirstSelection** | boolean |
| **onRangeFocusChange** | function |
| **rangeColors** | array |
| **ranges** | array |


#### Example: Editable Date Inputs
Expand Down
30 changes: 25 additions & 5 deletions src/components/DateRange/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,40 @@ class DateRange extends Component {
}
calcNewSelection = (value, isSingleValue = true) => {
const focusedRange = this.props.focusedRange || this.state.focusedRange;
const { ranges, onChange, maxDate, moveRangeOnFirstSelection, disabledDates } = this.props;
const {
ranges,
onChange,
maxDate,
moveRangeOnFirstSelection,
retainEndDateOnFirstSelection,
disabledDates,
} = this.props;
const focusedRangeIndex = focusedRange[0];
const selectedRange = ranges[focusedRangeIndex];
if (!selectedRange || !onChange) return {};

let { startDate, endDate } = selectedRange;
if (!endDate) endDate = new Date(startDate);
const now = new Date();
let nextFocusRange;
if (!isSingleValue) {
startDate = value.startDate;
endDate = value.endDate;
} else if (focusedRange[1] === 0) {
// startDate selection
const dayOffset = differenceInCalendarDays(endDate, startDate);
const dayOffset = differenceInCalendarDays(endDate || now, startDate);
const calculateEndDate = () => {
if (moveRangeOnFirstSelection) {
return addDays(value, dayOffset);
}
if (retainEndDateOnFirstSelection) {
if (!endDate || isBefore(value, endDate)) {
return endDate;
}
return value;
}
return value || now;
};
startDate = value;
endDate = moveRangeOnFirstSelection ? addDays(value, dayOffset) : value;
endDate = calculateEndDate();
if (maxDate) endDate = min([endDate, maxDate]);
nextFocusRange = [focusedRange[0], 1];
} else {
Expand Down Expand Up @@ -131,6 +149,7 @@ DateRange.defaultProps = {
classNames: {},
ranges: [],
moveRangeOnFirstSelection: false,
retainEndDateOnFirstSelection: false,
rangeColors: ['#3d91ff', '#3ecf8e', '#fed14c'],
disabledDates: [],
};
Expand All @@ -142,6 +161,7 @@ DateRange.propTypes = {
className: PropTypes.string,
ranges: PropTypes.arrayOf(rangeShape),
moveRangeOnFirstSelection: PropTypes.bool,
retainEndDateOnFirstSelection: PropTypes.bool,
};

export default DateRange;
77 changes: 77 additions & 0 deletions src/components/DateRange/index.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,84 @@
import React from 'react';
import { subDays, addDays, isSameDay } from 'date-fns';
import DateRange from '../DateRange';
import renderer from 'react-test-renderer';

let testRenderer = null;
let instance = null;
const endDate = new Date();
const startDate = subDays(endDate, 7);

const commonProps = {
ranges: [{ startDate, endDate, key: 'selection' }],
onChange: () => {},
moveRangeOnFirstSelection: false,
};

const compareRanges = (newRange, assertionRange) => {
['startDate', 'endDate'].forEach(key => {
if (!newRange[key] || !assertionRange[key]) {
return expect(newRange[key]).toEqual(assertionRange[key]);
}
return expect(isSameDay(newRange[key], assertionRange[key])).toEqual(true);
});
};

beforeEach(() => {
testRenderer = renderer.create(<DateRange {...commonProps} />);
instance = testRenderer.getInstance();
});

describe('DateRange', () => {
test('Should resolve', () => {
expect(DateRange).toEqual(expect.anything());
});

test('calculate new selection by resetting end date', () => {
const methodResult = instance.calcNewSelection(subDays(endDate, 10), true);
compareRanges(methodResult.range, {
startDate: subDays(endDate, 10),
endDate: subDays(endDate, 10),
});
});

test('calculate new selection by resetting end date if start date is not before', () => {
const methodResult = instance.calcNewSelection(addDays(endDate, 2), true);
compareRanges(methodResult.range, {
startDate: addDays(endDate, 2),
endDate: addDays(endDate, 2),
});
});

test('calculate new selection based on moveRangeOnFirstSelection prop', () => {
testRenderer.update(<DateRange {...commonProps} moveRangeOnFirstSelection />);
const methodResult = instance.calcNewSelection(subDays(endDate, 10), true);
compareRanges(methodResult.range, {
startDate: subDays(endDate, 10),
endDate: subDays(endDate, 3),
});
});

test('calculate new selection by retaining end date, based on retainEndDateOnFirstSelection prop', () => {
testRenderer.update(<DateRange {...commonProps} retainEndDateOnFirstSelection />);
const methodResult = instance.calcNewSelection(subDays(endDate, 10), true);
compareRanges(methodResult.range, {
startDate: subDays(endDate, 10),
endDate,
});
});

test('calculate new selection by retaining the unset end date, based on retainEndDateOnFirstSelection prop', () => {
testRenderer.update(
<DateRange
{...commonProps}
ranges={[{ ...commonProps.ranges[0], endDate: null }]}
retainEndDateOnFirstSelection
/>
);
const methodResult = instance.calcNewSelection(subDays(endDate, 10), true);
compareRanges(methodResult.range, {
startDate: subDays(endDate, 10),
endDate: null,
});
});
});

0 comments on commit 17a7900

Please sign in to comment.