Skip to content

Commit

Permalink
Add localization to DateRangePicker (#988)
Browse files Browse the repository at this point in the history
* add localization to DateRangePicker

* bump version to make breaking change

* downgrade version

* remove unused comment

* small aria update for drawer

---------

Co-authored-by: Steph Stamm <stephanie.stamm@mx.com>
  • Loading branch information
smstamm and Steph Stamm committed Oct 19, 2023
1 parent b59464e commit ecef535
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 76 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mx-react-components",
"version": "8.5.1",
"version": "8.6.0",
"description": "A collection of generic React UI components",
"main": "dist/index.js",
"files": [
Expand Down
118 changes: 64 additions & 54 deletions src/components/DateRangePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const PropTypes = require('prop-types');
const keycode = require('keycode');

import { withTheme } from './Theme';
import 'moment/locale/es'
import 'moment/locale/fr'
const moment = require('moment');
const _merge = require('lodash/merge');

Expand Down Expand Up @@ -32,6 +34,7 @@ class DateRangePicker extends React.Component {
elementRef: PropTypes.func,
focusTrapProps: PropTypes.object,
format: PropTypes.string,
getTranslation: PropTypes.func.isRequired,
isRelative: PropTypes.bool,
locale: PropTypes.string,
minimumDate: PropTypes.number,
Expand All @@ -49,46 +52,13 @@ class DateRangePicker extends React.Component {
};

static defaultProps = {
defaultRanges: [
{
displayValue: 'This Month',
getEndDate: () => moment().endOf('month').unix(),
getStartDate: () => moment().startOf('month').unix()
},
{
displayValue: 'Last 30 Days',
getEndDate: () => moment().endOf('day').unix(),
getStartDate: () => moment().subtract(29, 'days').startOf('day').unix()
},
{
displayValue: 'Last Month',
getEndDate: () => moment().subtract(1, 'months').endOf('month').unix(),
getStartDate: () => moment().subtract(1, 'months').startOf('month').unix()
},
{
displayValue: 'Last 90 Days',
getEndDate: () => moment().endOf('day').unix(),
getStartDate: () => moment().subtract(89, 'days').startOf('day').unix()
},
{
displayValue: 'Year To Date',
getEndDate: () => moment().endOf('day').unix(),
getStartDate: () => moment().startOf('year').unix()
},
{
displayValue: 'Last Year',
getEndDate: () => moment().endOf('year').subtract(1, 'y').unix(),
getStartDate: () => moment().startOf('year').subtract(1, 'y').unix()
}
],
focusTrapProps: {},
format: 'MMM D, YYYY',
isRelative: true,
locale: 'en',
onCancel: () => {},
onClose: () => {},
onOpen: () => {},
placeholderText: 'Select A Date Range',
showDefaultRanges: false
};

Expand All @@ -106,6 +76,10 @@ class DateRangePicker extends React.Component {
};
}

componentDidMount() {
moment.locale(this.props.locale)
}

UNSAFE_componentWillReceiveProps (newProps) {
const isUpdatedSelectedEndDate = newProps.selectedEndDate && newProps.selectedEndDate !== this.props.selectedEndDate;
const isUpdatedSelectedStartDate = newProps.selectedStartDate && newProps.selectedStartDate !== this.props.selectedStartDate;
Expand Down Expand Up @@ -269,6 +243,12 @@ class DateRangePicker extends React.Component {
return isActive;
};

_formatMomentDate = (date, format = 'MMMM Do, YYYY') => {
const d = moment.unix(date).format(format)

return d.charAt(0).toUpperCase() + d.slice(1)
}

_getDateRangePosition = (selectedStart, selectedEnd, active, date) => {
const start = selectedStart || active;
const end = selectedEnd || active;
Expand Down Expand Up @@ -306,15 +286,49 @@ class DateRangePicker extends React.Component {
};

render () {
const { children, placeholderText } = this.props;
const { children, getTranslation, placeholderText } = this.props;
const theme = StyleUtils.mergeTheme(this.props.theme);
const isLargeOrMediumWindowSize = this._isLargeOrMediumWindowSize(theme);
const styles = this.styles(theme, isLargeOrMediumWindowSize);
const shouldShowCalendarIcon = StyleUtils.getWindowSize(theme.BreakPoints) !== 'small';
const showCalendar = isLargeOrMediumWindowSize || this.state.showCalendar;
const { selectedDefaultRange, selectedEndDate, selectedStartDate } = this.state;
const selectedEndDateFromPropsAsMoment = moment.unix(this.props.selectedEndDate);
const selectedStartDateFromPropsAsMoment = moment.unix(this.props.selectedStartDate);

const defaultRangesWithCopy = [
{
displayValue: getTranslation('This Month',),
getEndDate: () => moment().endOf('month').unix(),
getStartDate: () => moment().startOf('month').unix()
},
{
displayValue: getTranslation('Last 30 Days',),
getEndDate: () => moment().endOf('day').unix(),
getStartDate: () => moment().subtract(29, 'days').startOf('day').unix()
},
{
displayValue: getTranslation('Last Month',),
getEndDate: () => moment().subtract(1, 'months').endOf('month').unix(),
getStartDate: () => moment().subtract(1, 'months').startOf('month').unix()
},
{
displayValue: getTranslation('Last 90 Days',),
getEndDate: () => moment().endOf('day').unix(),
getStartDate: () => moment().subtract(89, 'days').startOf('day').unix()
},
{
displayValue: getTranslation('Year To Date',),
getEndDate: () => moment().endOf('day').unix(),
getStartDate: () => moment().startOf('year').unix()
},
{
displayValue: getTranslation('Last Year',),
getEndDate: () => moment().endOf('year').subtract(1, 'y').unix(),
getStartDate: () => moment().startOf('year').subtract(1, 'y').unix()
}
]

const weekDayNames = moment.weekdays()
const weekDayObject = moment.weekdaysMin().map((d, index) => ({ label: d.charAt(0).toUpperCase(), value: weekDayNames[index].charAt(0).toUpperCase()}))

const mergedFocusTrapProps = {
focusTrapOptions: {
Expand All @@ -329,7 +343,7 @@ class DateRangePicker extends React.Component {
'aria-haspopup': true,
'aria-label': `${placeholderText}${
this.props.selectedStartDate && this.props.selectedEndDate
? `, ${selectedStartDateFromPropsAsMoment.format('MMMM Do, YYYY')} to ${selectedEndDateFromPropsAsMoment.format('MMMM Do, YYYY')} currently selected`
? getTranslation(`%1 to %2 currently selected`, this._formatMomentDate(this.props.selectedStartDate), this._formatMomentDate(this.props.selectedEndDate))
: ''
}`,
onClick: this._toggleSelectionPane,
Expand All @@ -355,9 +369,9 @@ class DateRangePicker extends React.Component {
<div className='mx-date-range-picker-selected-date-text' style={styles.selectedDateText}>
{this.props.selectedStartDate && this.props.selectedEndDate ? (
<div>
<span>{selectedStartDateFromPropsAsMoment.format(this._getDateFormat(isLargeOrMediumWindowSize))}</span>
<span>{this._formatMomentDate(this.props.selectedStartDate, this._getDateFormat(isLargeOrMediumWindowSize))}</span>
<span> - </span>
<span>{selectedEndDateFromPropsAsMoment.format(this._getDateFormat(isLargeOrMediumWindowSize))}</span>
<span>{this._formatMomentDate(this.props.selectedEndDate, this._getDateFormat(isLargeOrMediumWindowSize))}</span>
</div>
) : placeholderText}
</div>
Expand Down Expand Up @@ -391,9 +405,10 @@ class DateRangePicker extends React.Component {
<div>
{this.props.showDefaultRanges && (
<SelectionPane
defaultRanges={this.props.defaultRanges}
defaultRanges={this.props.defaultRanges || defaultRangesWithCopy}
getFromButtonRef={ref => (this._fromButton = ref)}
getToButtonRef={ref => (this._toButton = ref)}
getTranslation={this.props.getTranslation}
handleDefaultRangeSelection={
this._handleDefaultRangeSelection
}
Expand All @@ -420,6 +435,7 @@ class DateRangePicker extends React.Component {
<div className='mx-date-range-picker-calendar-header' style={styles.calendarHeader}>
<MonthSelector
currentDate={this.state.currentDate}
getTranslation={this.props.getTranslation}
setCurrentDate={currentDate =>
this.setState({
currentDate,
Expand All @@ -428,6 +444,7 @@ class DateRangePicker extends React.Component {
/>
<YearSelector
currentDate={this.state.currentDate}
getTranslation={this.props.getTranslation}
setCurrentDate={currentDate =>
this.setState({
currentDate,
Expand All @@ -436,19 +453,11 @@ class DateRangePicker extends React.Component {
/>
</div>
<div className='mx-date-range-picker-week-label' style={styles.calendarWeek}>
{[
{ label: 'S', value: 'Sunday' },
{ label: 'M', value: 'Monday' },
{ label: 'T', value: 'Tuesday' },
{ label: 'W', value: 'Wednesday' },
{ label: 'T', value: 'Thursday' },
{ label: 'F', value: 'Friday' },
{ label: 'S', value: 'Saturday' }
].map(day => {
{weekDayObject.map((day, index) => {
return (
<div
aria-hidden={true}
key={day.value}
key={`${day.value}-${index}`}
style={styles.calendarWeekDay}
>
{day.label}
Expand All @@ -466,6 +475,7 @@ class DateRangePicker extends React.Component {
getDateRangePosition={
this._getDateRangePosition
}
getTranslation={this.props.getTranslation}
handleDateHover={this._handleDateHover}
handleDateSelect={this._handleDateSelect}
handleKeyDown={this._handleDayKeyDown}
Expand All @@ -482,18 +492,18 @@ class DateRangePicker extends React.Component {
</div>
<div style={styles.bottomPane}>
<Button
aria-label='Cancel Date Range Selection'
aria-label={getTranslation('Cancel Date Range Selection')}
onClick={() => {
this.props.onCancel()
this._resetToPropValuesAndClose();
}}
theme={this.props.theme}
type='secondary'
>
Cancel
{getTranslation('Cancel')}
</Button>
<Button
aria-label='Apply Date Range Selection'
aria-label={getTranslation('Apply Date Range Selection')}
onClick={() => {
this.props.onDateRangeSelect(
selectedStartDate,
Expand All @@ -507,7 +517,7 @@ class DateRangePicker extends React.Component {
theme={this.props.theme}
type={selectedStartDate && selectedEndDate ? 'primary' : 'disabled'}
>
Apply
{getTranslation('Apply')}
</Button>
</div>
</div>
Expand Down
12 changes: 7 additions & 5 deletions src/components/DateRangePicker/MonthTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class MonthTable extends React.Component {
currentDate,
focusedDay,
getDateRangePosition,
getTranslation,
handleDateHover,
handleDateSelect,
handleKeyDown,
Expand Down Expand Up @@ -72,20 +73,20 @@ class MonthTable extends React.Component {
* Thursday, April 13th, 2018, selected end date for range.
* */
let ariaLabelStateText = '';
const ariaLabelBeginningText = `Select ${selectedBox === SelectedBox.FROM ? 'start' : 'end'} date for range, `;
const ariaLabelBeginningText = `Select ${selectedBox === SelectedBox.FROM ? 'start' : 'end'} date for range`;
const ariaLabelDateText = moment(startDate).format('dddd, MMMM Do, YYYY');

if (!isSelectedDay && isActiveRange) {
ariaLabelStateText = ', within selected range';
ariaLabelStateText = 'within selected range.';
} else if (isSelectedStartDay) {
ariaLabelStateText = ', selected start date for range.';
ariaLabelStateText = 'selected start date for range.';
} else if (isSelectedEndDay) {
ariaLabelStateText = ', selected end date for range.';
ariaLabelStateText = 'selected end date for range.';
}

const day = (
<a
aria-label={ariaLabelBeginningText + ariaLabelDateText + ariaLabelStateText}
aria-label={getTranslation(`${ariaLabelBeginningText}, %1, ${ariaLabelStateText}`, ariaLabelDateText)}
aria-pressed={isSelectedDay}
className={`${css({
...styles.calendarDay,
Expand Down Expand Up @@ -121,6 +122,7 @@ MonthTable.propTypes = {
currentDate: PropTypes.number,
focusedDay: PropTypes.number,
getDateRangePosition: PropTypes.func,
getTranslation: PropTypes.func,
handleDateHover: PropTypes.func,
handleDateSelect: PropTypes.func,
handleKeyDown: PropTypes.func,
Expand Down
28 changes: 20 additions & 8 deletions src/components/DateRangePicker/SelectionPane.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ class SelectionPane extends React.Component {
defaultRanges: PropTypes.array,
getFromButtonRef: PropTypes.func,
getToButtonRef: PropTypes.func,
getTranslation: PropTypes.func,
locale: PropTypes.string,
onDateBoxClick: PropTypes.func,
selectedBox: PropTypes.string,
selectedEndDate: PropTypes.number,
Expand All @@ -24,43 +26,53 @@ class SelectionPane extends React.Component {
theme: themeShape
};

componentDidMount() {
moment.locale(this.props.locale)
}

_handleDateBoxClick = (date, selectedBox) => {
this.props.onDateBoxClick(date, selectedBox);
}

_formatDate = (date) => {
const d = moment.unix(date).format('MMM D, YYYY')

return d.charAt(0).toUpperCase() + d.slice(1)
}

render () {
const theme = StyleUtils.mergeTheme(this.props.theme);
const styles = this.styles(theme);
const { selectedStartDate, selectedEndDate } = this.props;
const { getTranslation, selectedStartDate, selectedEndDate } = this.props;

return (
<div className='mx-selection-pane' style={styles.container}>
<div>
<label style={styles.boxLabel}>From</label>
<label style={styles.boxLabel}>{getTranslation('From')}</label>
<button
aria-label={`Select Start Date, ${selectedStartDate ? 'Current start date is ' + moment.unix(selectedStartDate).format('MMM D, YYYY') : ''}`}
aria-label={getTranslation(`Select Start Date${selectedStartDate ? ', Current start date is' : ''} %1`, this._formatDate(selectedStartDate))}
className='mx-selection-pane-from-field'
onClick={() => this._handleDateBoxClick(selectedStartDate, SelectedBox.FROM)}
ref={this.props.getFromButtonRef}
style={{ ...styles.dateSelectBox, ...this.props.selectedBox === SelectedBox.FROM ? styles.selectedDateSelectBox : {}}}
>
{selectedStartDate ? moment.unix(selectedStartDate).format('MMM D, YYYY') : 'Select Start Date'}
{selectedStartDate ? this._formatDate(selectedStartDate) : getTranslation('Select Start Date')}
</button>

<label style={styles.boxLabel}>To</label>
<label style={styles.boxLabel}>{getTranslation('To')}</label>
<button
aria-label={`Select End Date, ${selectedEndDate ? 'Current end date is ' + moment.unix(selectedEndDate).format('MMM D, YYYY') : ''}`}
aria-label={getTranslation(`Select End Date${selectedEndDate ? ', Current end date is' : ''} %1`, this._formatDate(selectedEndDate))}
className='mx-selection-pane-to-field'
onClick={() => this._handleDateBoxClick(selectedEndDate, SelectedBox.TO)}
ref={this.props.getToButtonRef}
style={{ ...styles.dateSelectBox, ...this.props.selectedBox === SelectedBox.TO ? styles.selectedDateSelectBox : {}}}
>
{selectedEndDate ? moment.unix(selectedEndDate).format('MMM D, YYYY') : 'Select End Date'}
{selectedEndDate ? this._formatDate(selectedEndDate) : getTranslation('Select End Date')}
</button>
</div>
<div>
<div style={{ ...styles.defaultRangesTitle, color: theme.Colors.PRIMARY }}>
Select a Range
{getTranslation('Select a Range')}
</div>
<DefaultRanges {...this.props} styles={styles} theme={theme} />
</div>
Expand Down

0 comments on commit ecef535

Please sign in to comment.