woocommerce/plugins/woocommerce-admin/client/components/calendar/index.js

180 lines
4.8 KiB
JavaScript
Raw Normal View History

2018-05-28 10:55:19 +00:00
/** @format */
/**
* External dependencies
*/
import { Component, Fragment } from '@wordpress/element';
import moment from 'moment';
import {
DayPickerRangeController,
isInclusivelyAfterDay,
isInclusivelyBeforeDay,
} from 'react-dates';
import { partial } from 'lodash';
import { __, sprintf } from '@wordpress/i18n';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import 'react-dates/lib/css/_datepicker.css';
/**
* Internal dependencies
*/
import { toMoment } from 'lib/date';
import phrases from './phrases';
import './style.scss';
const START_DATE = 'startDate';
const END_DATE = 'endDate';
// 782px is the width designated by Gutenberg's `</ Popover>` component.
// * https://github.com/WordPress/gutenberg/blob/c8f8806d4465a83c1a0bc62d5c61377b56fa7214/components/popover/utils.js#L6
const isMobileViewport = () => window.innerWidth < 782;
const shortDateFormat = __( 'MM/DD/YYYY', 'wc-admin' );
2018-05-28 10:55:19 +00:00
class DateRange extends Component {
constructor( props ) {
super( props );
const { after, before } = props;
2018-05-28 10:55:19 +00:00
this.state = {
focusedInput: START_DATE,
afterText: after ? after.format( shortDateFormat ) : '',
beforeText: before ? before.format( shortDateFormat ) : '',
2018-05-28 10:55:19 +00:00
};
this.onDatesChange = this.onDatesChange.bind( this );
this.onFocusChange = this.onFocusChange.bind( this );
this.onInputChange = this.onInputChange.bind( this );
this.getOutsideRange = this.getOutsideRange.bind( this );
}
onDatesChange( { startDate, endDate } ) {
this.setState( {
afterText: startDate ? startDate.format( shortDateFormat ) : '',
beforeText: endDate ? endDate.format( shortDateFormat ) : '',
2018-05-28 10:55:19 +00:00
} );
this.props.onSelect( {
after: startDate,
before: endDate,
2018-05-28 10:55:19 +00:00
} );
}
onFocusChange( focusedInput ) {
this.setState( {
focusedInput: ! focusedInput ? START_DATE : focusedInput,
} );
}
onInputChange( input, event ) {
const value = event.target.value;
this.setState( { [ input + 'Text' ]: value } );
2018-06-27 03:54:01 +00:00
const date = toMoment( shortDateFormat, value );
2018-05-28 10:55:19 +00:00
if ( date ) {
this.props.onSelect( {
[ input ]: date,
} );
2018-05-28 10:55:19 +00:00
}
}
getOutsideRange() {
const { inValidDays } = this.props;
if ( 'string' === typeof inValidDays ) {
switch ( inValidDays ) {
case 'past':
return day => isInclusivelyBeforeDay( day, moment() );
case 'future':
return day => isInclusivelyAfterDay( day, moment() );
case 'none':
default:
return undefined;
}
}
return 'function' === typeof inValidDays ? inValidDays : undefined;
}
render() {
const { focusedInput, afterText, beforeText } = this.state;
const { after, before } = this.props;
2018-05-28 10:55:19 +00:00
const isOutsideRange = this.getOutsideRange();
const isMobile = isMobileViewport();
return (
<Fragment>
<div className="woocommerce-date-picker__date-inputs">
<input
value={ afterText }
2018-05-28 10:55:19 +00:00
type="text"
onChange={ partial( this.onInputChange, 'after' ) }
aria-label={ __( 'Start Date', 'wc-admin' ) }
id="after-date-string"
aria-describedby="after-date-string-message"
2018-05-28 10:55:19 +00:00
/>
<p className="screen-reader-text" id="after-date-string-message">
2018-05-28 10:55:19 +00:00
{ sprintf(
__(
"Date input describing a selected date range's start date in format %s",
'wc-admin'
2018-05-28 10:55:19 +00:00
),
2018-06-27 03:54:01 +00:00
shortDateFormat
2018-05-28 10:55:19 +00:00
) }
</p>
<span>{ __( 'to', 'wc-admin' ) }</span>
2018-05-28 10:55:19 +00:00
<input
value={ beforeText }
2018-05-28 10:55:19 +00:00
type="text"
onChange={ partial( this.onInputChange, 'before' ) }
aria-label={ __( 'End Date', 'wc-admin' ) }
id="before-date-string"
aria-describedby="before-date-string-message"
2018-05-28 10:55:19 +00:00
/>
<p className="screen-reader-text" id="before-date-string-message">
2018-05-28 10:55:19 +00:00
{ sprintf(
__(
"Date input describing a selected date range's end date in format %s",
'wc-admin'
2018-05-28 10:55:19 +00:00
),
2018-06-27 03:54:01 +00:00
shortDateFormat
2018-05-28 10:55:19 +00:00
) }
</p>
</div>
<div
className={ classnames( 'woocommerce-calendar', {
'is-mobile': isMobile,
} ) }
>
<DayPickerRangeController
onDatesChange={ this.onDatesChange }
onFocusChange={ this.onFocusChange }
focusedInput={ focusedInput }
startDate={ after }
2018-05-28 10:55:19 +00:00
startDateId={ START_DATE }
startDatePlaceholderText={ 'Start Date' }
endDate={ before }
2018-05-28 10:55:19 +00:00
endDateId={ END_DATE }
endDatePlaceholderText={ 'End Date' }
orientation={ 'horizontal' }
numberOfMonths={ 1 }
isOutsideRange={ isOutsideRange }
minimumNights={ 0 }
hideKeyboardShortcutsPanel
noBorder
initialVisibleMonth={ () => after || moment() }
2018-05-28 10:55:19 +00:00
phrases={ phrases }
2018-07-04 01:50:12 +00:00
firstDayOfWeek={ Number( wcSettings.date.dow ) }
2018-05-28 10:55:19 +00:00
/>
</div>
</Fragment>
);
}
}
DateRange.propTypes = {
after: PropTypes.object,
before: PropTypes.object,
2018-05-28 10:55:19 +00:00
onSelect: PropTypes.func.isRequired,
inValidDays: PropTypes.oneOfType( [
PropTypes.oneOf( [ 'past', 'future', 'none' ] ),
PropTypes.func,
] ),
};
export { DateRange };