Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance/display important dates on search #41301

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e5611f3
Display the right date all the time
millerf Apr 18, 2020
3cee3d4
Small refactor as post cannot be null (props.isRequired)
millerf Apr 18, 2020
d676b2e
clean up - includeNonDraftStatuses was never used across the project
millerf Apr 18, 2020
36be7c5
Fix CamelCase
millerf Apr 18, 2020
5ca266b
More refactor.
millerf Apr 18, 2020
38dc57d
Refactor label, use only one method to display time label
millerf Apr 18, 2020
32b2d1b
Revert "Fix CamelCase"
millerf Apr 20, 2020
1434be6
Minor translation fix
millerf Apr 20, 2020
aca3eb5
Fix date for pendingPost
millerf Apr 20, 2020
3f0bb96
Fix translation for scheduled posts
millerf Apr 21, 2020
2ed0eed
use for scheduled posts
millerf Apr 21, 2020
7be3d67
Small refactor for readability
millerf Apr 21, 2020
31323cb
Added modified date to pending review status
millerf Apr 22, 2020
dc7e183
Remove unnecessary case in a switch
millerf Apr 24, 2020
75cafee
Remove duplicated on
millerf Apr 24, 2020
964df20
pending as an extra sticker
millerf Apr 24, 2020
00c3126
remove 'on' prefix for dates without text label
millerf Apr 25, 2020
a05f2fe
Change to for draft and pending statuses
millerf Apr 27, 2020
75965c2
Remove negated variable for clarity
millerf Apr 27, 2020
20c0305
refactor getLabel to remove onlySticky and onlyPending parameters
millerf Apr 27, 2020
6157493
rename displayedTime vairables to make more sense
millerf Apr 27, 2020
e651d84
minor JsDocs and formatting fixes
millerf Apr 28, 2020
db74c42
minor changes in variable names
millerf Apr 28, 2020
cb7b07d
Pass private as a label
millerf Apr 28, 2020
5defad5
fix translations
millerf Apr 28, 2020
6b0fcda
Add forgotten case for 'private' posts date
millerf Apr 29, 2020
effba2a
Add better comments for translators for dates
millerf Apr 29, 2020
edd82c6
Update client/my-sites/post-relative-time-status/index.jsx
millerf Apr 30, 2020
0380076
Update client/my-sites/post-relative-time-status/index.jsx
millerf Apr 30, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
238 changes: 162 additions & 76 deletions client/my-sites/post-relative-time-status/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import PropTypes from 'prop-types';
import { localize } from 'i18n-calypso';
import React from 'react';
import { includes } from 'lodash';

/**
* Internal dependencies
Expand All @@ -21,121 +20,208 @@ class PostRelativeTime extends React.PureComponent {
static propTypes = {
showPublishedStatus: PropTypes.bool.isRequired,
post: PropTypes.object.isRequired,
includeNonDraftStatuses: PropTypes.bool,
link: PropTypes.string,
target: PropTypes.string,
gridiconSize: PropTypes.number,
};

static defaultProps = {
includeNonDraftStatuses: false,
link: null,
target: null,
};

/**
* Get the date to be displayed depending on the status of the post
*/
getTimestamp() {
switch ( this.props.post.status ) {
case 'new':
return null;

case 'draft':
case 'future':
case 'trash':
case 'pending':
return this.props.post.modified;

default:
return this.props.post.date;
}
}

getDisplayedTimeFromPost( post ) {
getDisplayedTimeForLabel() {
const moment = this.props.moment;

const now = moment();
const timestamp = moment( this.getTimestamp() );

if ( ! post ) {
// Placeholder text: "a few seconds ago" in English locale
return now.fromNow();
}
const isScheduledPost = this.props.post.status === 'future';

const { status, modified, date } = post;
const time = moment( includes( [ 'draft', 'pending', 'future' ], status ) ? modified : date );
if ( now.diff( time, 'days' ) >= 7 ) {
// Like "Mar 15, 2013 6:23 PM" in English locale
return time.format( 'lll' );
let displayedTime;
if ( isScheduledPost ) {
displayedTime = timestamp.calendar( null, {
nextDay: this.props.translate( '[tomorrow at] LT', {
mmtr marked this conversation as resolved.
Show resolved Hide resolved
comment: 'LT refers to time (eg. 18:00)',
} ),
sameElse: this.props.translate( 'll [at] LT', {
comment:
'll refers to date (eg. 21 Apr) for when the post will be published & LT refers to time (eg. 18:00) - "at" is translated',
} ),
} );
} else {
if ( Math.abs( now.diff( this.getTimestamp(), 'days' ) ) < 7 ) {
return timestamp.fromNow();
}

const sameElse = this.props.translate( 'll [at] LT', {
comment:
'll refers to date (eg. 21 Apr) & LT refers to time (eg. 18:00) - "at" is translated',
} );

displayedTime = timestamp.calendar( null, {
sameElse,
} );
}

// Like "3 days ago" in English locale
return time.fromNow();
// If the content is scheduled to be release within a year, do not display the year at the end
return timestamp.diff( now, 'years' ) > 0
? displayedTime
: displayedTime.replace( timestamp.format( 'Y' ), '' );
}

getTimeText() {
const time = this.getTimestamp();
if ( ! time ) {
return null;
}

return (
<span className="post-relative-time-status__time">
<Gridicon icon="time" size={ this.props.gridiconSize || 18 } />
<time className="post-relative-time-status__time-text" dateTime={ time }>
{ this.getDisplayedTimeFromPost( this.props.post ) }
</time>
{ time && (
<>
<Gridicon icon="time" size={ this.props.gridiconSize || 18 } />
<time className="post-relative-time-status__time-text" dateTime={ time }>
{ this.getDisplayedTimeForLabel() }
</time>
</>
) }
</span>
);
}

getStatusText() {
const status = this.props.post.status;
let statusClassName = 'post-relative-time-status__status';
let statusIcon = 'aside';
let statusText;

if ( this.props.post.sticky ) {
statusText = this.props.translate( 'sticky' );
statusClassName += ' is-sticky';
statusIcon = 'bookmark-outline';
} else if ( status === 'pending' ) {
statusText = this.props.translate( 'pending review' );
statusClassName += ' is-pending';
} else if ( status === 'future' ) {
const moment = this.props.moment;
const now = moment();
const scheduledDate = moment( this.props.post.date );
// If the content is scheduled to be release within a year, do not display the year at the end
const scheduledTime = scheduledDate.calendar( null, {
sameElse: this.props.translate( 'll [at] LT', {
const args = {
displayedTime: this.getDisplayedTimeForLabel(),
};
const moment = this.props.moment;
const now = moment();
const displayOn = Math.abs( now.diff( this.getTimestamp(), 'days' ) ) >= 7;

switch ( status ) {
case 'trash':
if ( displayOn ) {
return this.props.translate( 'trashed on %(displayedTime)s', {
comment:
'%(displayedTime)s is the absolute date (ie. Apr 21, at 10:07 PM) when a post or page was trashed',
args,
} );
}
return this.props.translate( 'trashed %(displayedTime)s', {
comment:
'll refers to date (eg. 21 Apr) & LT refers to time (eg. 18:00) - "at" is translated',
} ),
} );
'%(displayedTime)s is the relative date (ie. 3 days ago) when a post or page was trashed',
args,
} );

const displayScheduleTime =
scheduledDate.diff( now, 'years' ) > 0
? scheduledTime
: scheduledTime.replace( scheduledDate.format( 'Y' ), '' );
case 'future':
return this.props.translate( 'scheduled for %(displayedTime)s', {
comment:
'%(displayedTime)s is when a scheduled post or page is set to be published. It can be either "tomorrow at 16H", or an absoltute date (ie. Apr 21, at 10:07 PM)',
args,
} );

statusText = this.props.translate( 'scheduled for %(displayScheduleTime)s', {
comment: '%(displayScheduleTime)s is when a scheduled post is set to be published',
args: {
displayScheduleTime,
},
} );
statusClassName += ' is-scheduled';
statusIcon = 'calendar';
} else if ( status === 'trash' ) {
statusText = this.props.translate( 'trashed' );
statusClassName += ' is-trash';
case 'draft':
case 'pending':
if ( displayOn ) {
return this.props.translate( 'draft last modified on %(displayedTime)s', {
comment:
'%(displayedTime)s is the absolute date (ie. Apr 21, at 10:07 PM) when a draft post or page was last modified',
args,
} );
}

return this.props.translate( 'draft last modified %(displayedTime)s', {
comment:
'%(displayedTime)s is the relative date (ie. 3 days ago) when a draft post or page was last modified',
args,
} );

case 'private':
case 'publish':
if ( displayOn ) {
return this.props.translate( 'published on %(displayedTime)s', {
comment:
'%(displayedTime)s is the absolute date (ie. Apr 21, at 10:07 PM ) when a post or page was published',
args,
} );
}

return this.props.translate( 'published %(displayedTime)s', {
comment:
'%(displayedTime)s is the relative date (ie. 3 days ago) when a post or page was published',
args,
} );
}
}

/**
* Get status label
*/
getStatus() {
const status = this.props.post.status;
let extraStatusClassName;
let statusIcon;
let statusText = this.getStatusText();

if ( status === 'trash' ) {
extraStatusClassName = 'is-trash';
statusIcon = 'trash';
} else if ( this.props.includeBasicStatus ) {
if ( status === 'draft' ) {
statusText = this.props.translate( 'draft' );
} else if ( status === 'publish' ) {
statusText = this.props.translate( 'published' );
} else if ( status === 'new' ) {
statusText = this.props.translate( 'Publish immediately' );
}
} else if ( status === 'future' ) {
extraStatusClassName = 'is-scheduled';
statusIcon = 'calendar';
} else if ( status === 'new' ) {
mmtr marked this conversation as resolved.
Show resolved Hide resolved
statusText = this.props.translate( 'Publish immediately' );
}

return this.getLabel( statusText, extraStatusClassName, statusIcon );
}

/**
* Get "private" label
*/
getPrivateLabel() {
return this.getLabel( this.props.translate( 'private' ), 'is-private' );
}

/**
* Get "sticky" label
*/
getStickyLabel() {
return this.getLabel( this.props.translate( 'sticky' ), 'is-sticky', 'bookmark-outline' );
}

/**
* Get "Pending" label
*/
getPendingLabel() {
return this.getLabel( this.props.translate( 'pending review' ), 'is-pending' );
mmtr marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Get Label for the status
*
* @param {string} statusText text status
* @param {string} extraStatusClassName extra CSS class to be added to the label
* @param {string} [statusIcon="aside"] icon for the label
*/
getLabel( statusText, extraStatusClassName, statusIcon = 'aside' ) {
if ( statusText ) {
const statusClassName = 'post-relative-time-status__status ' + extraStatusClassName;

return (
<span className={ statusClassName }>
<Gridicon icon={ statusIcon } size={ this.props.gridiconSize || 18 } />
Expand All @@ -146,16 +232,14 @@ class PostRelativeTime extends React.PureComponent {
}

render() {
const { post, showPublishedStatus } = this.props;
const { showPublishedStatus, post } = this.props;
const timeText = this.getTimeText();
const statusText = this.getStatusText();
const relativeTimeClass = timeText ? 'post-relative-time-status' : null;
const time = this.getTimestamp();

let innerText = (
<span>
{ timeText }
{ ( post.status === 'future' || showPublishedStatus ) && statusText }
{ showPublishedStatus ? this.getStatus() : timeText }
{ post.status === 'pending' && this.getPendingLabel() }
{ post.status === 'private' && this.getPrivateLabel() }
{ post.sticky && this.getStickyLabel() }
</span>
);

Expand All @@ -174,6 +258,8 @@ class PostRelativeTime extends React.PureComponent {
);
}

const relativeTimeClass = timeText ? 'post-relative-time-status' : null;
const time = this.getTimestamp();
return (
<div className={ relativeTimeClass } title={ time }>
{ innerText }
Expand Down
3 changes: 3 additions & 0 deletions client/my-sites/post-relative-time-status/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
.is-trash {
color: var( --color-error );
}
.is-private {
color: var( --color-primary-dark );
}
}

a.post-relative-time-status__link {
Expand Down