MM-18466 Change recent date separators to yesterday/today (#3245)
* MM-18466 Change recent date separators to yesterday/today * Add i18n strings
This commit is contained in:
parent
ed29e2fbee
commit
6fc8569266
5 changed files with 198 additions and 8 deletions
|
|
@ -31,8 +31,7 @@ exports[`DateHeader component should match snapshot when timezone is set 1`] = `
|
|||
}
|
||||
}
|
||||
>
|
||||
<FormattedDate
|
||||
format="ddd, MMM DD, YYYY"
|
||||
<RecentDate
|
||||
style={
|
||||
Object {
|
||||
"color": "#3d3c40",
|
||||
|
|
@ -88,8 +87,7 @@ exports[`DateHeader component should match snapshot with suffix 1`] = `
|
|||
}
|
||||
}
|
||||
>
|
||||
<FormattedDate
|
||||
format="ddd, MMM DD, YYYY"
|
||||
<RecentDate
|
||||
style={
|
||||
Object {
|
||||
"color": "#3d3c40",
|
||||
|
|
@ -145,8 +143,7 @@ exports[`DateHeader component should match snapshot without suffix 1`] = `
|
|||
}
|
||||
}
|
||||
>
|
||||
<FormattedDate
|
||||
format="ddd, MMM DD, YYYY"
|
||||
<RecentDate
|
||||
style={
|
||||
Object {
|
||||
"color": "#3d3c40",
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
ViewPropTypes,
|
||||
} from 'react-native';
|
||||
|
||||
import FormattedDate from 'app/components/formatted_date';
|
||||
import RecentDate from 'app/components/recent_date';
|
||||
import {makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
// DateHeader accepts as a timestamp for rendering as part of a post list.
|
||||
|
|
@ -28,7 +28,7 @@ export default class DateHeader extends PureComponent {
|
|||
<View style={[style.container, this.props.style]}>
|
||||
<View style={style.line}/>
|
||||
<View style={style.dateContainer}>
|
||||
<FormattedDate
|
||||
<RecentDate
|
||||
style={style.date}
|
||||
timeZone={timeZone}
|
||||
value={date}
|
||||
|
|
|
|||
68
app/components/recent_date.js
Normal file
68
app/components/recent_date.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
import FormattedDate from 'app/components/formatted_date';
|
||||
|
||||
export default class RecentDate extends React.PureComponent {
|
||||
static propTypes = {
|
||||
value: PropTypes.oneOfType([
|
||||
PropTypes.number,
|
||||
PropTypes.instanceOf(Date),
|
||||
]).isRequired,
|
||||
}
|
||||
|
||||
render() {
|
||||
const {value, ...otherProps} = this.props;
|
||||
const date = new Date(value);
|
||||
|
||||
if (isToday(date)) {
|
||||
return (
|
||||
<FormattedText
|
||||
{...otherProps}
|
||||
id='date_separator.today'
|
||||
defaultMessage='Today'
|
||||
/>
|
||||
);
|
||||
} else if (isYesterday(date)) {
|
||||
return (
|
||||
<FormattedText
|
||||
{...otherProps}
|
||||
id='date_separator.yesterday'
|
||||
defaultMessage='Yesterday'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FormattedDate
|
||||
{...otherProps}
|
||||
value={value}
|
||||
weekday='short'
|
||||
month='short'
|
||||
day='2-digit'
|
||||
year='numeric'
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function isSameDay(a, b) {
|
||||
return a.getDate() === b.getDate() && a.getMonth() === b.getMonth() && a.getFullYear() === b.getFullYear();
|
||||
}
|
||||
|
||||
export function isToday(date) {
|
||||
const now = new Date();
|
||||
|
||||
return isSameDay(date, now);
|
||||
}
|
||||
|
||||
export function isYesterday(date) {
|
||||
const yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
|
||||
return isSameDay(date, yesterday);
|
||||
}
|
||||
123
app/components/recent_date.test.js
Normal file
123
app/components/recent_date.test.js
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import FormattedDate from 'app/components/formatted_date';
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
|
||||
import {shallowWithIntl} from 'test/intl-test-helper.js';
|
||||
|
||||
import RecentDate, {
|
||||
isToday,
|
||||
isYesterday,
|
||||
} from './recent_date';
|
||||
|
||||
describe('RecentDate', () => {
|
||||
test('should render "Today" today', () => {
|
||||
const today = new Date();
|
||||
|
||||
const props = {
|
||||
value: today,
|
||||
};
|
||||
|
||||
const wrapper = shallowWithIntl(<RecentDate {...props}/>);
|
||||
|
||||
expect(wrapper.find(FormattedText).exists()).toBe(true);
|
||||
expect(wrapper.find(FormattedText).prop('id')).toBe('date_separator.today');
|
||||
});
|
||||
|
||||
test('should render "Yesterday" yesterday', () => {
|
||||
const yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
|
||||
const props = {
|
||||
value: yesterday,
|
||||
};
|
||||
|
||||
const wrapper = shallowWithIntl(<RecentDate {...props}/>);
|
||||
|
||||
expect(wrapper.find(FormattedText).exists()).toBe(true);
|
||||
expect(wrapper.find(FormattedText).prop('id')).toBe('date_separator.yesterday');
|
||||
});
|
||||
|
||||
test('should render date two days ago', () => {
|
||||
const twoDaysAgo = new Date();
|
||||
twoDaysAgo.setDate(twoDaysAgo.getDate() - 2);
|
||||
|
||||
const props = {
|
||||
value: twoDaysAgo,
|
||||
};
|
||||
|
||||
const wrapper = shallowWithIntl(<RecentDate {...props}/>);
|
||||
|
||||
expect(wrapper.find(FormattedDate).exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isToday and isYesterday', () => {
|
||||
test('tomorrow at 12am', () => {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() + 1);
|
||||
date.setHours(0);
|
||||
date.setMinutes(0);
|
||||
|
||||
expect(isToday(date)).toBe(false);
|
||||
expect(isYesterday(date)).toBe(false);
|
||||
});
|
||||
|
||||
test('now', () => {
|
||||
const date = new Date();
|
||||
|
||||
expect(isToday(date)).toBe(true);
|
||||
expect(isYesterday(date)).toBe(false);
|
||||
});
|
||||
|
||||
test('today at 12am', () => {
|
||||
const date = new Date();
|
||||
date.setHours(0);
|
||||
date.setMinutes(0);
|
||||
|
||||
expect(isToday(date)).toBe(true);
|
||||
expect(isYesterday(date)).toBe(false);
|
||||
});
|
||||
|
||||
test('today at 11:59pm', () => {
|
||||
const date = new Date();
|
||||
date.setHours(23);
|
||||
date.setMinutes(59);
|
||||
|
||||
expect(isToday(date)).toBe(true);
|
||||
expect(isYesterday(date)).toBe(false);
|
||||
});
|
||||
|
||||
test('yesterday at 11:59pm', () => {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() - 1);
|
||||
date.setHours(23);
|
||||
date.setMinutes(59);
|
||||
|
||||
expect(isToday(date)).toBe(false);
|
||||
expect(isYesterday(date)).toBe(true);
|
||||
});
|
||||
|
||||
test('yesterday at 12am', () => {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() - 1);
|
||||
date.setHours(0);
|
||||
date.setMinutes(0);
|
||||
|
||||
expect(isToday(date)).toBe(false);
|
||||
expect(isYesterday(date)).toBe(true);
|
||||
});
|
||||
|
||||
test('two days ago at 11:59pm', () => {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() - 2);
|
||||
date.setHours(23);
|
||||
date.setMinutes(59);
|
||||
|
||||
expect(isToday(date)).toBe(false);
|
||||
expect(isYesterday(date)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
@ -74,6 +74,8 @@
|
|||
"create_comment.addComment": "Add a comment...",
|
||||
"create_post.deactivated": "You are viewing an archived channel with a deactivated user.",
|
||||
"create_post.write": "Write to {channelDisplayName}",
|
||||
"date_separator.today": "Today",
|
||||
"date_separator.yesterday": "Yesterday",
|
||||
"edit_post.editPost": "Edit the post...",
|
||||
"edit_post.save": "Save",
|
||||
"file_attachment.download": "Download",
|
||||
|
|
|
|||
Loading…
Reference in a new issue