Skip to content

Commit

Permalink
fix(datepicker): advance calendar only if date is not isInView (uber#…
Browse files Browse the repository at this point in the history
  • Loading branch information
foodforarabbit authored and nadiia committed Jan 23, 2020
1 parent e0f3ead commit 6a59155
Show file tree
Hide file tree
Showing 9 changed files with 135 additions and 5 deletions.
4 changes: 2 additions & 2 deletions documentation-site/components/yard/config/datepicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ const DatepickerConfig: TConfig = {
},
},
autoFocusCalendar: {
value: undefined,
type: PropTypes.Function,
value: false,
type: PropTypes.Boolean,
description:
'Defines if the calendar is set to be focused on an initial render.',
hidden: true,
Expand Down
36 changes: 36 additions & 0 deletions src/datepicker/__tests__/datepicker-range-multi-month.scenario.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
Copyright (c) 2018-2020 Uber Technologies, Inc.
This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
// @flow

import * as React from 'react';

import {StyledDay, StatefulDatepicker} from '../index.js';

export const name = 'datepicker-range-multi-month';

export const component = () => (
<StatefulDatepicker
aria-label="Select a date"
initialState={{value: []}}
range
monthsShown={2}
highlightedDate={new Date('March 10, 2019')}
clearable={true}
overrides={{
Day: {
// eslint-disable-next-line react/display-name
component: props => (
<StyledDay data-highlighted={props.$isHighlighted} {...props} />
),
},
MonthYearSelectButton: {props: {'data-id': 'monthYearSelectButton'}},
MonthYearSelectStatefulMenu: {
props: {overrides: {List: {props: {'data-id': 'monthYearSelectMenu'}}}},
},
}}
/>
);
56 changes: 56 additions & 0 deletions src/datepicker/__tests__/datepicker-range.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const selectors = {
day: '[aria-label="Choose Sunday, March 10th 2019. It\'s available."]',
day2: '[aria-label="Choose Thursday, March 28th 2019. It\'s available."]',
day4: '[aria-label="Choose Monday, April 1st 2019. It\'s available."]',
day5: '[aria-label="Choose Wednesday, May 1st 2019. It\'s available."]',
rightArrow: '[aria-label="Next month"]',
monthYearSelectButton: '[data-id="monthYearSelectButton"]',
monthYearSelectMenu: '[data-id="monthYearSelectMenu"]',
Expand Down Expand Up @@ -77,4 +78,59 @@ describe('Datepicker, Range', () => {
);
expect(selectedValue2).toBe('2019/03/10 – 2019/03/28');
});

it('selects range in multi-month', async () => {
await mount(page, 'datepicker-range-multi-month');
await page.waitFor(selectors.input);
await page.click(selectors.input);
await page.waitFor(selectors.calendar);
await page.click(selectors.day);
await page.waitFor(selectors.calendar);
const selectedValue1 = await page.$eval(
selectors.input,
input => input.value,
);
expect(selectedValue1).toBe('2019/03/10 – / / ');

await page.click(selectors.day4);
await page.waitFor(selectors.calendar, {
hidden: true,
});
const selectedValue2 = await page.$eval(
selectors.input,
input => input.value,
);
expect(selectedValue2).toBe('2019/03/10 – 2019/04/01');
});

it('selects range in multi-month - do not autoAdvance calendar months since selected date is in view', async () => {
await mount(page, 'datepicker-range-multi-month');
await page.waitFor(selectors.input);
await page.click(selectors.input);
await page.waitFor(selectors.calendar);
// datepicker should show 2 months - March and April
// we can see both a day in March and a day in April are rendered
await page.waitFor(selectors.day);
await page.click(selectors.day4);
await page.waitFor(selectors.calendar);
const selectedValue1 = await page.$eval(
selectors.input,
input => input.value,
);
expect(selectedValue1).toBe('2019/04/01 – / / ');

// after clicking on a date in April, in the second month, the months should NOT change at all. March should still be visible, and May should not be rendered
// we finish off the test by clicking on a day in March (simulating clicking the "end" of the range first, then the "beginning" of the range last)
// await page.waitFor(selectors.day5, {hidden: true});
await page.waitFor(selectors.day);
await page.click(selectors.day);
await page.waitFor(selectors.calendar, {
hidden: true,
});
const selectedValue2 = await page.$eval(
selectors.input,
input => input.value,
);
expect(selectedValue2).toBe('2019/03/10 – 2019/04/01');
});
});
19 changes: 19 additions & 0 deletions src/datepicker/__tests__/datepicker.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,25 @@ describe('Datepicker', () => {
expect(selectedValue).toBe('2019/07/01');
});

it('input causes calendar to switch to appropriate month', async () => {
await mount(page, 'datepicker');
await page.waitFor(selectors.input);
await page.click(selectors.input);
await page.waitFor(selectors.calendar);
// march should be visible
await page.waitFor(selectors.day);

// we want to enter entire date but the onChange functionality only fires on key press so...
await page.$eval(selectors.input, el => (el.value = '2019/07/0'));
// also make sure the selected date isn't the date we're testing - selected/non-selected dates have different aria-labels
await page.keyboard.press('2');

// make sure march is gone
await page.waitFor(selectors.day, {hidden: true});
// and make sure july is now visible
await page.waitFor(selectors.day6);
});

it('month year dropdown opens on arrow down', async () => {
await mount(page, 'datepicker');
await page.waitFor(selectors.input);
Expand Down
1 change: 1 addition & 0 deletions src/datepicker/__tests__/datepicker.scenario.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const component = () => {
aria-label="Select a date"
highlightedDate={new Date('March 10, 2019')}
value={date}
onChange={({date}) => setDate(date)}
overrides={{
MonthYearSelectButton: {props: {'data-id': 'monthYearSelectButton'}},
MonthYearSelectStatefulMenu: {
Expand Down
24 changes: 21 additions & 3 deletions src/datepicker/calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,30 @@ export default class Calendar extends React.Component<
}

if (prevProps.value !== this.props.value) {
this.setState({
date: this.getDateInView(),
});
const nextDate = this.getDateInView();
if (!this.isInView(nextDate)) {
this.setState({
date: nextDate,
});
}
}
}

isInView(date: Date): boolean {
// we calculate the month delta between the date arg and the date in the state.
const currentDate = this.state.date;

// First we get the year delta
const yearDelta = date.getFullYear() - currentDate.getFullYear();

// then we convert it to months. Then we simply add the date-without-year month delta back in.
const monthDelta =
yearDelta * 12 + date.getMonth() - currentDate.getMonth();

// we just check that the delta is between the range given by "this month" (i.e. 0) and "the last month" (i.e. monthsShown)
return monthDelta >= 0 && monthDelta < (this.props.monthsShown || 1);
}

getSingleDate(value: ?Date | Array<Date>): ?Date {
// need to check this.props.range but flow would complain
// at the return value in the else clause
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 6a59155

Please sign in to comment.