From 286003e6ca3537899b6cfba2bd299e7ecfa2d1d4 Mon Sep 17 00:00:00 2001
From: Maxim Kudryavtsev
Date: Tue, 7 May 2019 11:06:55 +0300
Subject: [PATCH] feat(react-scheduler): support scheduler localization
capability (#1985)
---
.../material-ui/custom-formatting.jsx | 61 +++++++
.../material-ui/locale.jsx | 108 ++++++++++++
.../api/dx-react-scheduler-material-ui.api.ts | 1 +
.../templates/appointment-tooltip/layout.jsx | 12 +-
.../appointment-tooltip/layout.test.jsx | 17 +-
.../appointment/appointment-content.test.jsx | 1 +
.../appointment/horizontal-appointment.jsx | 3 +
.../appointment/vertical-appointment.jsx | 8 +-
.../appointment/vertical-appointment.test.jsx | 20 ++-
.../date-navigator/calendar/navigator.jsx | 4 +-
.../calendar/navigator.test.jsx | 5 +-
.../date-navigator/calendar/root.jsx | 4 +
.../date-navigator/calendar/root.test.jsx | 12 +-
.../date-navigator/calendar/table.jsx | 7 +-
.../date-navigator/calendar/table.test.jsx | 1 +
.../date-navigator/calendar/text.jsx | 6 +-
.../date-navigator/calendar/text.test.jsx | 17 +-
.../views/common/day-scale/layout.jsx | 3 +
.../views/horizontal/day-scale/cell.jsx | 27 ++-
.../views/horizontal/day-scale/cell.test.jsx | 13 ++
.../views/horizontal/time-table/cell.jsx | 8 +-
.../views/horizontal/time-table/cell.test.jsx | 13 ++
.../views/horizontal/time-table/layout.jsx | 3 +
.../horizontal/time-table/layout.test.jsx | 1 +
.../views/vertical/day-scale/cell.jsx | 51 +++---
.../views/vertical/day-scale/cell.test.jsx | 17 ++
.../views/vertical/time-scale/cell.jsx | 27 ++-
.../views/vertical/time-scale/cell.test.jsx | 13 ++
.../views/vertical/time-scale/layout.jsx | 3 +
.../views/vertical/time-scale/layout.test.jsx | 1 +
.../views/vertical/time-table/layout.jsx | 2 +
.../api/dx-react-scheduler.api.ts | 17 ++
.../docs/guides/localization.md | 24 +++
.../docs/reference/appointment-tooltip.md | 1 +
.../docs/reference/appointments.md | 1 +
.../docs/reference/day-view.md | 5 +
.../docs/reference/month-view.md | 4 +
.../docs/reference/scheduler.md | 1 +
.../docs/reference/week-view.md | 5 +
.../src/plugins/appointment-tooltip.jsx | 5 +-
.../src/plugins/appointment-tooltip.test.jsx | 5 +
.../src/plugins/appointments.jsx | 33 ++--
.../src/plugins/appointments.test.jsx | 7 +-
.../src/plugins/date-navigator.jsx | 3 +
.../src/plugins/date-navigator.test.jsx | 37 ++--
.../src/plugins/day-view.jsx | 9 +-
.../src/plugins/day-view.test.jsx | 26 ++-
.../src/plugins/month-view.jsx | 6 +-
.../src/plugins/month-view.test.jsx | 9 +-
.../src/plugins/scheduler-core.jsx | 5 +-
.../src/plugins/scheduler-core.test.jsx | 19 +-
.../src/plugins/week-view.jsx | 9 +-
.../src/plugins/week-view.test.jsx | 13 +-
packages/dx-react-scheduler/src/scheduler.jsx | 4 +
packages/dx-scheduler-core/src/constants.ts | 16 ++
.../plugins/date-navigator/helpers.test.ts | 37 ++--
.../src/plugins/date-navigator/helpers.ts | 63 +++++--
.../plugins/scheduler-core/computeds.test.ts | 165 +++++++++++++-----
.../src/plugins/scheduler-core/computeds.ts | 21 ++-
.../plugins/scheduler-core/helpers.test.ts | 14 ++
.../src/plugins/scheduler-core/helpers.ts | 5 +
.../src/types/date-navigator.types.ts | 3 +-
.../src/types/scheduler-core.types.ts | 10 ++
site/_data/docs/navigation.yml | 2 +
64 files changed, 836 insertions(+), 217 deletions(-)
create mode 100644 packages/dx-react-scheduler-demos/src/demo-sources/scheduler-localization/material-ui/custom-formatting.jsx
create mode 100644 packages/dx-react-scheduler-demos/src/demo-sources/scheduler-localization/material-ui/locale.jsx
create mode 100644 packages/dx-react-scheduler/docs/guides/localization.md
create mode 100644 packages/dx-scheduler-core/src/plugins/scheduler-core/helpers.test.ts
create mode 100644 packages/dx-scheduler-core/src/plugins/scheduler-core/helpers.ts
diff --git a/packages/dx-react-scheduler-demos/src/demo-sources/scheduler-localization/material-ui/custom-formatting.jsx b/packages/dx-react-scheduler-demos/src/demo-sources/scheduler-localization/material-ui/custom-formatting.jsx
new file mode 100644
index 0000000000..a027883338
--- /dev/null
+++ b/packages/dx-react-scheduler-demos/src/demo-sources/scheduler-localization/material-ui/custom-formatting.jsx
@@ -0,0 +1,61 @@
+import * as React from 'react';
+import Paper from '@material-ui/core/Paper';
+import moment from 'moment';
+import { ViewState } from '@devexpress/dx-react-scheduler';
+import {
+ Scheduler,
+ WeekView,
+ Toolbar,
+ Appointments,
+} from '@devexpress/dx-react-scheduler-material-ui';
+import { appointments } from '../../../demo-data/appointments';
+
+const formatDayScaleDate = (date, options) => {
+ const momentDate = moment(date);
+ const { weekday } = options;
+ return momentDate.format(weekday ? 'dddd' : 'D');
+};
+const formatTimeScaleDate = date => moment(date).format('hh:mm:ss');
+
+const DayScaleCell = (
+ { formatDate, ...restProps },
+) => ;
+const TimeScaleCell = (
+ { formatDate, ...restProps },
+) => ;
+
+export default class Demo extends React.PureComponent {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ data: appointments,
+ currentDate: '2018-06-27',
+ };
+ }
+
+ render() {
+ const { data, currentDate, locale } = this.state;
+
+ return (
+
+
+
+
+
+
+
+
+ );
+ }
+}
diff --git a/packages/dx-react-scheduler-demos/src/demo-sources/scheduler-localization/material-ui/locale.jsx b/packages/dx-react-scheduler-demos/src/demo-sources/scheduler-localization/material-ui/locale.jsx
new file mode 100644
index 0000000000..2221b7f211
--- /dev/null
+++ b/packages/dx-react-scheduler-demos/src/demo-sources/scheduler-localization/material-ui/locale.jsx
@@ -0,0 +1,108 @@
+import * as React from 'react';
+import Paper from '@material-ui/core/Paper';
+import TextField from '@material-ui/core/TextField';
+import MenuItem from '@material-ui/core/MenuItem';
+import { ViewState } from '@devexpress/dx-react-scheduler';
+import { withStyles } from '@material-ui/core/styles';
+import {
+ Scheduler,
+ WeekView,
+ Toolbar,
+ DateNavigator,
+ Appointments,
+ AllDayPanel,
+} from '@devexpress/dx-react-scheduler-material-ui';
+
+import { appointments } from '../../../demo-data/appointments';
+
+const allDayLocalizationMessages = {
+ 'fr-FR': {
+ allDay: "Autour de l'horloge",
+ },
+ 'de-GR': {
+ allDay: 'Rund um die Uhr',
+ },
+ 'en-US': {
+ allDay: 'All Day',
+ },
+};
+
+const getAllDayMessages = locale => allDayLocalizationMessages[locale];
+
+const styles = theme => ({
+ container: {
+ display: 'flex',
+ marginBottom: theme.spacing.unit * 2,
+ justifyContent: 'flex-end',
+ },
+ text: {
+ ...theme.typography.h6,
+ marginRight: theme.spacing.unit * 2,
+ },
+});
+
+const LocaleSwitcher = withStyles(styles, { name: 'LocaleSwitcher' })(
+ ({ onLocaleChange, currentLocale, classes }) => (
+
+
+ Locale:
+
+
+
+
+
+
+
+ ),
+);
+
+export default class Demo extends React.PureComponent {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ data: appointments,
+ currentDate: '2018-06-27',
+ locale: 'fr-FR',
+ };
+
+ this.changeLocale = event => this.setState({ locale: event.target.value });
+ }
+
+ render() {
+ const { data, currentDate, locale } = this.state;
+
+ return (
+
+ );
+ }
+}
diff --git a/packages/dx-react-scheduler-material-ui/api/dx-react-scheduler-material-ui.api.ts b/packages/dx-react-scheduler-material-ui/api/dx-react-scheduler-material-ui.api.ts
index 885468ee0e..5c3a1f41f5 100644
--- a/packages/dx-react-scheduler-material-ui/api/dx-react-scheduler-material-ui.api.ts
+++ b/packages/dx-react-scheduler-material-ui/api/dx-react-scheduler-material-ui.api.ts
@@ -551,6 +551,7 @@ declare const Scheduler: React.ComponentType & {
// @public (undocumented)
interface SchedulerProps {
data?: Array;
+ locale?: string;
rootComponent?: React.ComponentType;
}
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/appointment-tooltip/layout.jsx b/packages/dx-react-scheduler-material-ui/src/templates/appointment-tooltip/layout.jsx
index 72a7b86ca4..86f7adbdf3 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/appointment-tooltip/layout.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/appointment-tooltip/layout.jsx
@@ -3,8 +3,10 @@ import * as PropTypes from 'prop-types';
import Popover from '@material-ui/core/Popover';
import AccessTime from '@material-ui/icons/AccessTime';
import Grid from '@material-ui/core/Grid';
-import moment from 'moment';
import { withStyles } from '@material-ui/core/styles';
+import { HOUR_MINUTE_OPTIONS } from '@devexpress/dx-scheduler-core';
+
+const verticalTopHorizontalCenterOptions = { vertical: 'top', horizontal: 'center' };
const styles = theme => ({
text: {
@@ -47,6 +49,7 @@ const LayoutBase = ({
commandButtonIds,
onOpenButtonClick,
onDeleteButtonClick,
+ formatDate,
classes,
...restProps
}) => {
@@ -61,8 +64,8 @@ const LayoutBase = ({
open={visible}
anchorEl={target}
onClose={onHide}
- anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
- transformOrigin={{ vertical: 'top', horizontal: 'center' }}
+ anchorOrigin={verticalTopHorizontalCenterOptions}
+ transformOrigin={verticalTopHorizontalCenterOptions}
{...restProps}
>
@@ -92,7 +95,7 @@ const LayoutBase = ({
- {`${moment(data.startDate).format('h:mm A')} - ${moment(data.endDate).format('h:mm A')}`}
+ {`${formatDate(data.startDate, HOUR_MINUTE_OPTIONS)} - ${formatDate(data.endDate, HOUR_MINUTE_OPTIONS)}`}
@@ -110,6 +113,7 @@ LayoutBase.propTypes = {
showDeleteButton: PropTypes.bool.isRequired,
commandButtonIds: PropTypes.object.isRequired,
classes: PropTypes.object.isRequired,
+ formatDate: PropTypes.func.isRequired,
onOpenButtonClick: PropTypes.func,
onDeleteButtonClick: PropTypes.func,
appointmentMeta: PropTypes.shape({
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/appointment-tooltip/layout.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/appointment-tooltip/layout.test.jsx
index f0fa4ccf41..aaa07625ce 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/appointment-tooltip/layout.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/appointment-tooltip/layout.test.jsx
@@ -24,6 +24,7 @@ describe('Appointment Tooltip', () => {
close: 'close',
delete: 'delete',
},
+ formatDate: () => undefined,
};
beforeAll(() => {
classes = getClasses();
@@ -121,14 +122,20 @@ describe('Appointment Tooltip', () => {
.toBeTruthy();
});
- it('should render appointment dates', () => {
+ it('should call dates format function', () => {
+ const dateTimeFormat = jest.fn();
const tree = shallow((
-
+
));
- const text = tree.find(defaultProps.contentComponent).find(`.${classes.text}`).text();
- expect(text)
- .toEqual('10:00 AM - 11:00 AM');
+ expect(dateTimeFormat)
+ .toBeCalledTimes(2);
+ expect(dateTimeFormat)
+ .toHaveBeenCalledWith(defaultProps.appointmentMeta.data.startDate, { hour: 'numeric', minute: 'numeric' });
+ expect(dateTimeFormat)
+ .toHaveBeenCalledWith(defaultProps.appointmentMeta.data.endDate, { hour: 'numeric', minute: 'numeric' });
+ expect(tree.find(`.${classes.text}`).props().children)
+ .toBeTruthy();
});
});
});
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/appointment/appointment-content.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/appointment/appointment-content.test.jsx
index 34d31f44c7..ff80a3dce5 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/appointment/appointment-content.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/appointment/appointment-content.test.jsx
@@ -11,6 +11,7 @@ describe('AppointmentContent', () => {
data: {},
type: 'horizontal',
recurringIconComponent: () => ,
+ formatDate: () => undefined,
};
beforeAll(() => {
shallow = createShallow({ dive: true });
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/appointment/horizontal-appointment.jsx b/packages/dx-react-scheduler-material-ui/src/templates/appointment/horizontal-appointment.jsx
index 2fc0ba9294..100da65f92 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/appointment/horizontal-appointment.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/appointment/horizontal-appointment.jsx
@@ -39,6 +39,7 @@ const HorizontalAppointmentBase = ({
children,
className,
recurringIconComponent: RecurringIcon,
+ formatDate,
...restProps
}) => {
const repeat = !!data.rRule;
@@ -69,9 +70,11 @@ HorizontalAppointmentBase.propTypes = {
data: PropTypes.object.isRequired,
children: PropTypes.node,
className: PropTypes.string,
+ formatDate: PropTypes.func,
};
HorizontalAppointmentBase.defaultProps = {
+ formatDate: () => '',
children: undefined,
className: undefined,
};
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/appointment/vertical-appointment.jsx b/packages/dx-react-scheduler-material-ui/src/templates/appointment/vertical-appointment.jsx
index f351360af9..e1f1bc1d32 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/appointment/vertical-appointment.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/appointment/vertical-appointment.jsx
@@ -1,8 +1,8 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
-import moment from 'moment';
import { withStyles } from '@material-ui/core/styles';
import classNames from 'classnames';
+import { HOUR_MINUTE_OPTIONS } from '@devexpress/dx-scheduler-core';
const styles = ({ palette, spacing }) => ({
title: {
@@ -51,6 +51,7 @@ const VerticalAppointmentBase = ({
data,
children,
className,
+ formatDate,
recurringIconComponent: RecurringIcon,
...restProps
}) => {
@@ -64,13 +65,13 @@ const VerticalAppointmentBase = ({
- {moment(data.startDate).format('h:mm A')}
+ {formatDate(data.startDate, HOUR_MINUTE_OPTIONS)}
{' - '}
- {moment(data.endDate).format('h:mm A')}
+ {formatDate(data.endDate, HOUR_MINUTE_OPTIONS)}
@@ -88,6 +89,7 @@ VerticalAppointmentBase.propTypes = {
recurringIconComponent: PropTypes.func.isRequired,
classes: PropTypes.object.isRequired,
data: PropTypes.object.isRequired,
+ formatDate: PropTypes.func.isRequired,
children: PropTypes.node,
className: PropTypes.string,
};
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/appointment/vertical-appointment.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/appointment/vertical-appointment.test.jsx
index 67b867aed9..163f2756b8 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/appointment/vertical-appointment.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/appointment/vertical-appointment.test.jsx
@@ -10,6 +10,7 @@ describe('VerticalAppointment', () => {
endDate: new Date('2018-07-27 17:10'),
},
recurringIconComponent: () => ,
+ formatDate: () => undefined,
};
let classes;
@@ -30,19 +31,24 @@ describe('VerticalAppointment', () => {
.toBe('title');
});
- it('should render appointment times', () => {
+ it('should call time format function', () => {
+ const formatDate = jest.fn();
+ formatDate.mockImplementation(() => 'time');
const tree = mount((
));
- expect(tree.find(`.${classes.time}`).at(0).text())
- .toBe('1:10 PM');
- expect(tree.find(`.${classes.time}`).at(1).text())
- .toBe(' - ');
- expect(tree.find(`.${classes.time}`).at(2).text())
- .toBe('5:10 PM');
+ expect(formatDate)
+ .toHaveBeenCalledWith(defaultProps.data.startDate, { hour: 'numeric', minute: 'numeric' });
+ expect(formatDate)
+ .toHaveBeenCalledWith(defaultProps.data.startDate, { hour: 'numeric', minute: 'numeric' });
+ expect(tree.find(`.${classes.time}`).at(0).props().children)
+ .toBeTruthy();
+ expect(tree.find(`.${classes.time}`).at(2).props().children)
+ .toBeTruthy();
});
it('should render children', () => {
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/navigator.jsx b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/navigator.jsx
index 111d03640e..44175d53e5 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/navigator.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/navigator.jsx
@@ -18,6 +18,7 @@ const NavigatorBase = ({
textComponent: Text,
navigationButtonComponent: NavigationButton,
onNavigate,
+ formatDate,
...restProps
}) => (
{ onNavigate({ back: true }); }}
/>
-
+
{ onNavigate({ back: false }); }}
@@ -45,6 +46,7 @@ NavigatorBase.propTypes = {
PropTypes.string,
PropTypes.instanceOf(Date),
]).isRequired,
+ formatDate: PropTypes.func.isRequired,
className: PropTypes.string,
onNavigate: PropTypes.func,
};
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/navigator.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/navigator.test.jsx
index bec580c49c..b0eb28edc2 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/navigator.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/navigator.test.jsx
@@ -36,14 +36,17 @@ describe('Calendar', () => {
.toMatchObject({ a: 1 });
});
it('should render text', () => {
+ const formatDate = jest.fn();
const text = shallow((
-
+
)).find(Text);
expect(text.exists())
.toBeTruthy();
expect(text.prop('currentDate'))
.toBe('2018-07-12');
+ expect(text.prop('formatDate'))
+ .toBe(formatDate);
});
it('should render navigation buttons', () => {
const buttons = shallow((
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/root.jsx b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/root.jsx
index 0c0b56b46b..1434f48114 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/root.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/root.jsx
@@ -38,6 +38,7 @@ export class Root extends React.PureComponent {
headerRowComponent: HeaderRow,
headerCellComponent: HeaderCell,
onSelectedDateChange,
+ formatDate,
...restProps
} = this.props;
const { selectedDate: selectedDateState, currentDate } = this.state;
@@ -51,6 +52,7 @@ export class Root extends React.PureComponent {
textComponent={Text}
navigationButtonComponent={NavigationButton}
onNavigate={this.onNavigate}
+ formatDate={formatDate}
/>
);
@@ -81,6 +84,7 @@ Root.propTypes = {
PropTypes.string,
PropTypes.instanceOf(Date),
]).isRequired,
+ formatDate: PropTypes.func.isRequired,
firstDayOfWeek: PropTypes.number,
onSelectedDateChange: PropTypes.func,
};
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/root.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/root.test.jsx
index 61a911467b..7c68a5cf4e 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/root.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/root.test.jsx
@@ -19,6 +19,7 @@ describe('Calendar', () => {
selectedDate: '2018-07-16',
firstDayOfWeek: 1,
getCells: () => [],
+ formatDate: () => undefined,
};
describe('Root', () => {
let mount;
@@ -46,20 +47,23 @@ describe('Calendar', () => {
.toMatchObject({ a: 1 });
});
it('should render navigator', () => {
+ const defaultFormatDate = jest.fn();
const navigator = mount((
-
+
)).find(defaultProps.navigatorComponent);
const {
currentDate,
textComponent,
navigationButtonComponent,
+ formatDate,
} = navigator.props();
expect(navigator.exists()).toBeTruthy();
expect(currentDate).toBe('2018-07-16');
expect(textComponent).toBe(defaultProps.textComponent);
expect(navigationButtonComponent).toBe(defaultProps.navigationButtonComponent);
+ expect(formatDate).toBe(defaultFormatDate);
});
it('should navigate to the prev and next month', () => {
const tree = mount((
@@ -80,13 +84,15 @@ describe('Calendar', () => {
.toBe(defaultProps.selectedDate);
});
it('should render calendar table', () => {
- const tree = mount();
+ const defaultFormatDate = jest.fn();
+ const tree = mount();
const {
cells,
rowComponent,
cellComponent,
headerRowComponent,
headerCellComponent,
+ formatDate,
} = Table.mock.calls[0][0];
expect(tree.find('.table').exists())
@@ -101,6 +107,8 @@ describe('Calendar', () => {
.toBe(defaultProps.headerRowComponent);
expect(headerCellComponent)
.toBe(defaultProps.headerCellComponent);
+ expect(formatDate)
+ .toBe(defaultFormatDate);
});
it('should handle table cell click', () => {
const onSelectedDateChangeMock = jest.fn();
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/table.jsx b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/table.jsx
index aa57f9c04f..ef2780d6e1 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/table.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/table.jsx
@@ -6,6 +6,7 @@ import TableMUI from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableHead from '@material-ui/core/TableHead';
import { withStyles } from '@material-ui/core/styles';
+import { WEEK_DAY_OPTIONS, DAY_OPTIONS } from '@devexpress/dx-scheduler-core';
const styles = {
table: {
@@ -25,6 +26,7 @@ const TableBase = ({
headerCells,
selectedDate,
onCellClick,
+ formatDate,
...restProps
}) => {
const comparableSelectedDate = moment(selectedDate);
@@ -36,7 +38,7 @@ const TableBase = ({
{headerCells.map((cell) => {
- const key = moment(cell.startDate).format('ddd');
+ const key = formatDate(cell.startDate, WEEK_DAY_OPTIONS);
return (
- {moment(startDate).format('D')}
+ {formatDate(startDate, DAY_OPTIONS)}
);
})}
@@ -91,6 +93,7 @@ TableBase.propTypes = {
PropTypes.string,
PropTypes.number,
]),
+ formatDate: PropTypes.func.isRequired,
headerCells: PropTypes.array,
className: PropTypes.string,
onCellClick: PropTypes.func,
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/table.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/table.test.jsx
index 16d3c59e61..4f515e7278 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/table.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/table.test.jsx
@@ -19,6 +19,7 @@ describe('Calendar', () => {
cellComponent: () => | ,
headerCellComponent: () => | ,
cells: [],
+ formatDate: () => '',
};
let classes;
let shallow;
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/text.jsx b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/text.jsx
index 85a9ce2179..3955b5d0be 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/text.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/text.jsx
@@ -3,7 +3,7 @@ import * as PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import classNames from 'classnames';
-import moment from 'moment';
+import { MONTH_YEAR_OPTIONS } from '@devexpress/dx-scheduler-core';
const styles = {
text: {
@@ -16,6 +16,7 @@ const TextBase = ({
classes,
className,
currentDate,
+ formatDate,
...restProps
}) => (
- {moment(currentDate).format('MMMM YYYY')}
+ {formatDate(currentDate, MONTH_YEAR_OPTIONS)}
);
@@ -36,6 +37,7 @@ TextBase.propTypes = {
PropTypes.string,
PropTypes.instanceOf(Date),
]).isRequired,
+ formatDate: PropTypes.func.isRequired,
className: PropTypes.string,
};
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/text.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/text.test.jsx
index 8c15b8b327..355b3890f5 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/text.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/date-navigator/calendar/text.test.jsx
@@ -9,6 +9,7 @@ describe('Calendar', () => {
let shallow;
const defaultProps = {
currentDate: '2018-07-12',
+ formatDate: () => '',
};
beforeAll(() => {
classes = getClasses();
@@ -36,13 +37,17 @@ describe('Calendar', () => {
expect(tree.props().data)
.toMatchObject({ a: 1 });
});
- it('should render current date', () => {
- const currentDate = shallow((
-
- )).dive().dive().text();
+ it('should call date format function', () => {
+ const formatDate = jest.fn();
+ formatDate.mockImplementation(() => 'time');
+ const tree = shallow((
+
+ ));
- expect(currentDate)
- .toBe('July 2018');
+ expect(formatDate)
+ .toHaveBeenCalledWith(defaultProps.currentDate, { month: 'long', year: 'numeric' });
+ expect(tree.props().children)
+ .toBeTruthy();
});
});
});
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/common/day-scale/layout.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/common/day-scale/layout.jsx
index d232bdaa29..f0ad6153f0 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/common/day-scale/layout.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/common/day-scale/layout.jsx
@@ -17,6 +17,7 @@ const LayoutBase = ({
cellsData,
className,
classes,
+ formatDate,
...restProps
}) => (
))}
@@ -47,6 +49,7 @@ LayoutBase.propTypes = {
cellsData: PropTypes.arrayOf(Array).isRequired,
cellComponent: PropTypes.func.isRequired,
rowComponent: PropTypes.func.isRequired,
+ formatDate: PropTypes.func.isRequired,
className: PropTypes.string,
};
LayoutBase.defaultProps = {
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/day-scale/cell.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/day-scale/cell.jsx
index 84758f56c7..c8f47ffd9d 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/day-scale/cell.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/day-scale/cell.jsx
@@ -1,9 +1,9 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
-import moment from 'moment';
import classNames from 'classnames';
import TableCell from '@material-ui/core/TableCell';
import { withStyles } from '@material-ui/core/styles';
+import { WEEK_DAY_OPTIONS } from '@devexpress/dx-scheduler-core';
import { getBorder } from '../../../utils';
const styles = theme => ({
@@ -24,23 +24,22 @@ const CellBase = ({
startDate,
endDate,
today,
+ formatDate,
...restProps
-}) => {
- const currentDate = moment(startDate);
- return (
-
-
- {currentDate.format('ddd')}
-
-
- );
-};
+}) => (
+
+
+ {formatDate(startDate, WEEK_DAY_OPTIONS)}
+
+
+);
CellBase.propTypes = {
classes: PropTypes.object.isRequired,
+ formatDate: PropTypes.func.isRequired,
startDate: PropTypes.instanceOf(Date).isRequired,
endDate: PropTypes.instanceOf(Date),
className: PropTypes.string,
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/day-scale/cell.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/day-scale/cell.test.jsx
index 0a76291141..41cb053d1a 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/day-scale/cell.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/day-scale/cell.test.jsx
@@ -5,6 +5,7 @@ import { Cell } from './cell';
describe('Horizontal view DayScale', () => {
const defaultProps = {
startDate: new Date(2018, 6, 7, 16, 20),
+ formatDate: () => undefined,
};
let classes;
let shallow;
@@ -31,5 +32,17 @@ describe('Horizontal view DayScale', () => {
expect(tree.props().data)
.toMatchObject({ a: 1 });
});
+ it('should call formatDate function', () => {
+ const formatDate = jest.fn();
+ formatDate.mockImplementation(() => 'time');
+ const tree = shallow((
+ |
+ ));
+
+ expect(formatDate)
+ .toHaveBeenCalledWith(defaultProps.startDate, { weekday: 'short' });
+ expect(tree.find(`.${classes.dayOfWeek}`).props().children)
+ .toBeTruthy();
+ });
});
});
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/cell.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/cell.jsx
index 77a85dcea8..384f01c94d 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/cell.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/cell.jsx
@@ -1,10 +1,10 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
-import moment from 'moment';
import TableCell from '@material-ui/core/TableCell';
import { fade } from '@material-ui/core/styles/colorManipulator';
import { withStyles } from '@material-ui/core/styles';
+import { DAY_OPTIONS } from '@devexpress/dx-scheduler-core';
import { getBorder } from '../../../utils';
const styles = theme => ({
@@ -48,6 +48,7 @@ const CellBase = ({
endDate,
today,
otherMonth,
+ formatDate,
...restProps
}) => (
- {moment(startDate).format('D')}
+ {formatDate(startDate, DAY_OPTIONS)}
);
CellBase.propTypes = {
classes: PropTypes.object.isRequired,
- className: PropTypes.string,
+ formatDate: PropTypes.func.isRequired,
startDate: PropTypes.instanceOf(Date).isRequired,
endDate: PropTypes.instanceOf(Date),
+ className: PropTypes.string,
today: PropTypes.bool,
otherMonth: PropTypes.bool,
};
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/cell.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/cell.test.jsx
index 6a77bf7482..9930209f32 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/cell.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/cell.test.jsx
@@ -5,6 +5,7 @@ import { Cell } from './cell';
describe('Horizontal view TimeTable', () => {
const defaultProps = {
startDate: new Date(2018, 6, 7, 16),
+ formatDate: () => undefined,
};
let classes;
let shallow;
@@ -66,4 +67,16 @@ describe('Horizontal view TimeTable', () => {
expect(tree.find(`.${classes.otherMonth}`))
.toHaveLength(1);
});
+ it('should call date format function', () => {
+ const formatDate = jest.fn();
+ formatDate.mockImplementation(() => 'time');
+ const tree = shallow((
+ |
+ ));
+
+ expect(formatDate)
+ .toHaveBeenCalledWith(defaultProps.startDate, { day: 'numeric' });
+ expect(tree.find(`.${classes.text}`).props().children)
+ .toBeTruthy();
+ });
});
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/layout.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/layout.jsx
index 57013ebc5c..ef3feb1e83 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/layout.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/layout.jsx
@@ -19,6 +19,7 @@ const LayoutBase = ({
tableRef,
className,
cellsData,
+ formatDate,
...restProps
}) => (
@@ -41,6 +42,7 @@ const LayoutBase = ({
endDate={endDate}
today={today}
otherMonth={otherMonth}
+ formatDate={formatDate}
/>
))}
@@ -56,6 +58,7 @@ LayoutBase.propTypes = {
classes: PropTypes.object.isRequired,
cellComponent: PropTypes.func.isRequired,
rowComponent: PropTypes.func.isRequired,
+ formatDate: PropTypes.func.isRequired,
className: PropTypes.string,
};
LayoutBase.defaultProps = {
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/layout.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/layout.test.jsx
index 7325b1ebad..730658cd5d 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/layout.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/horizontal/time-table/layout.test.jsx
@@ -17,6 +17,7 @@ describe('Horizontal view TimeTable', () => {
],
cellComponent: () => undefined,
rowComponent: () => undefined,
+ formatDate: () => undefined,
};
let classes;
let shallow;
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/day-scale/cell.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/day-scale/cell.jsx
index 3a62a35ed4..54fd25f6bd 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/day-scale/cell.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/day-scale/cell.jsx
@@ -1,9 +1,9 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
-import moment from 'moment';
import classNames from 'classnames';
import TableCell from '@material-ui/core/TableCell';
import { withStyles } from '@material-ui/core/styles';
+import { WEEK_DAY_OPTIONS, DAY_OPTIONS } from '@devexpress/dx-scheduler-core';
import { getBorder } from '../../../utils';
const styles = theme => ({
@@ -29,36 +29,35 @@ const CellBase = ({
startDate,
endDate,
today,
+ formatDate,
...restProps
-}) => {
- const currentDate = moment(startDate);
- return (
- (
+
+
-
- {currentDate.format('ddd')}
-
-
- {currentDate.format('D')}
-
-
- );
-};
+ {formatDate(startDate, WEEK_DAY_OPTIONS)}
+
+
+ {formatDate(startDate, DAY_OPTIONS)}
+
+
+);
CellBase.propTypes = {
classes: PropTypes.object.isRequired,
+ formatDate: PropTypes.func.isRequired,
startDate: PropTypes.instanceOf(Date).isRequired,
endDate: PropTypes.instanceOf(Date),
className: PropTypes.string,
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/day-scale/cell.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/day-scale/cell.test.jsx
index 07b85878e6..cbfcbe2e7c 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/day-scale/cell.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/day-scale/cell.test.jsx
@@ -5,6 +5,7 @@ import { Cell } from './cell';
describe('Vertical view DayPanel', () => {
const defaultProps = {
startDate: new Date(2018, 6, 7, 16, 20),
+ formatDate: () => undefined,
};
let classes;
let shallow;
@@ -41,5 +42,21 @@ describe('Vertical view DayPanel', () => {
expect(tree.find(`span.${classes.highlightCell}`).exists())
.toBeTruthy();
});
+ it('should call formatDate function', () => {
+ const formatDate = jest.fn();
+ formatDate.mockImplementation(() => 'time');
+ const tree = shallow((
+ |
+ ));
+
+ expect(formatDate)
+ .toHaveBeenCalledWith(defaultProps.startDate, { weekday: 'short' });
+ expect(formatDate)
+ .toHaveBeenCalledWith(defaultProps.startDate, { day: 'numeric' });
+ expect(tree.find(`.${classes.dayOfWeek}`).props().children)
+ .toBeTruthy();
+ expect(tree.find(`.${classes.dayOfMonth}`).props().children)
+ .toBeTruthy();
+ });
});
});
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/cell.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/cell.jsx
index 0b899282ef..c0a73ac5d7 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/cell.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/cell.jsx
@@ -3,7 +3,7 @@ import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import TableCell from '@material-ui/core/TableCell';
import { withStyles } from '@material-ui/core/styles';
-import moment from 'moment';
+import { HOUR_MINUTE_OPTIONS } from '@devexpress/dx-scheduler-core';
const styles = theme => ({
cell: {
@@ -29,22 +29,21 @@ const CellBase = ({
className,
startDate,
endDate,
+ formatDate,
...restProps
-}) => {
- const currentTime = moment(endDate);
- return (
-
-
- {currentTime.format('h:mm A')}
-
-
- );
-};
+}) => (
+
+
+ {formatDate(endDate, HOUR_MINUTE_OPTIONS)}
+
+
+);
CellBase.propTypes = {
+ formatDate: PropTypes.func.isRequired,
endDate: PropTypes.instanceOf(Date).isRequired,
startDate: PropTypes.instanceOf(Date),
classes: PropTypes.object.isRequired,
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/cell.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/cell.test.jsx
index ffd1d31123..743ce9c3f7 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/cell.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/cell.test.jsx
@@ -5,6 +5,7 @@ import { Cell } from './cell';
describe('Vertical view TimePanel', () => {
const defaultProps = {
endDate: new Date(2018, 6, 7, 16, 20),
+ formatDate: () => undefined,
};
let classes;
let shallow;
@@ -31,5 +32,17 @@ describe('Vertical view TimePanel', () => {
expect(tree.props().data)
.toMatchObject({ a: 1 });
});
+ it('should call date format function', () => {
+ const formatDate = jest.fn();
+ formatDate.mockImplementation(() => 'time');
+ const tree = shallow((
+ |
+ ));
+
+ expect(formatDate)
+ .toHaveBeenCalledWith(defaultProps.endDate, { hour: 'numeric', minute: 'numeric' });
+ expect(tree.find(`.${classes.text}`).props().children)
+ .toBeTruthy();
+ });
});
});
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/layout.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/layout.jsx
index a40c12db73..6d437ca84d 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/layout.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/layout.jsx
@@ -17,6 +17,7 @@ const LayoutBase = ({
cellsData,
classes,
className,
+ formatDate,
...restProps
}) => (
@@ -30,6 +31,7 @@ const LayoutBase = ({
rowSpan="2"
startDate={days[0].startDate}
endDate={days[0].endDate}
+ formatDate={formatDate}
/>
)}
@@ -43,6 +45,7 @@ LayoutBase.propTypes = {
cellsData: PropTypes.arrayOf(Array).isRequired,
cellComponent: PropTypes.func.isRequired,
rowComponent: PropTypes.func.isRequired,
+ formatDate: PropTypes.func.isRequired,
className: PropTypes.string,
};
LayoutBase.defaultProps = {
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/layout.test.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/layout.test.jsx
index 476fdf77bd..01506fcb14 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/layout.test.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-scale/layout.test.jsx
@@ -18,6 +18,7 @@ describe('Vertical view TimePanel', () => {
],
cellComponent: () => undefined,
rowComponent: () => undefined,
+ formatDate: () => undefined,
};
beforeAll(() => {
classes = getClasses();
diff --git a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-table/layout.jsx b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-table/layout.jsx
index fccfb2e28d..e7ba787682 100644
--- a/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-table/layout.jsx
+++ b/packages/dx-react-scheduler-material-ui/src/templates/views/vertical/time-table/layout.jsx
@@ -18,6 +18,7 @@ const LayoutBase = ({
cellComponent: Cell,
rowComponent: Row,
cellsData,
+ formatDate,
...restProps
}) => (
@@ -48,6 +49,7 @@ LayoutBase.propTypes = {
cellsData: PropTypes.arrayOf(Array).isRequired,
cellComponent: PropTypes.func.isRequired,
rowComponent: PropTypes.func.isRequired,
+ formatDate: PropTypes.func.isRequired,
className: PropTypes.string,
};
LayoutBase.defaultProps = {
diff --git a/packages/dx-react-scheduler/api/dx-react-scheduler.api.ts b/packages/dx-react-scheduler/api/dx-react-scheduler.api.ts
index 7425e95e51..cfd694b2bf 100644
--- a/packages/dx-react-scheduler/api/dx-react-scheduler.api.ts
+++ b/packages/dx-react-scheduler/api/dx-react-scheduler.api.ts
@@ -167,6 +167,7 @@ namespace Appointments {
interface AppointmentContentProps {
children: React.ReactNode;
data: object;
+ formatDate: (date: Date, options: any) => string;
recurringIconComponent: React.ComponentType