Add permalink to timestamp (#5206)

* Add permalink to timestamp

* Add permalink to timestamp

* Add permalink to timestamp

* Add permalink to timestamp

* fix error with duplicated import

* underline permalink on hover
This commit is contained in:
Andrei Stanciu
2017-02-10 16:56:48 +02:00
committed by Corey Hulen
parent 1359f7f391
commit 1bbed1cb2b
8 changed files with 191 additions and 27 deletions

View File

@@ -376,6 +376,7 @@ export default class PostInfo extends React.Component {
sameUser={this.props.sameUser}
compactDisplay={this.props.compactDisplay}
useMilitaryTime={this.props.useMilitaryTime}
postId={post.id}
/>
{flagTrigger}
</li>

View File

@@ -6,26 +6,40 @@ import React from 'react';
import Constants from 'utils/constants.jsx';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import {getDateForUnixTicks} from 'utils/utils.jsx';
import {getDateForUnixTicks, isMobile, updateWindowDimensions} from 'utils/utils.jsx';
import {Link} from 'react-router/es6';
import TeamStore from 'stores/team_store.jsx';
export default class PostTime extends React.Component {
constructor(props) {
super(props);
this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
this.state = {
currentTeamDisplayName: TeamStore.getCurrent().name,
width: '',
height: ''
};
}
componentDidMount() {
this.intervalId = setInterval(() => {
this.forceUpdate();
}, Constants.TIME_SINCE_UPDATE_INTERVAL);
window.addEventListener('resize', () => {
updateWindowDimensions(this);
});
}
componentWillUnmount() {
clearInterval(this.intervalId);
window.removeEventListener('resize', () => {
updateWindowDimensions(this);
});
}
render() {
renderTimeTag() {
return (
<time
className='post__time'
@@ -35,6 +49,20 @@ export default class PostTime extends React.Component {
</time>
);
}
render() {
return isMobile() ?
this.renderTimeTag() :
(
<Link
to={`/${this.state.currentTeamDisplayName}/pl/${this.props.postId}`}
target='_blank'
className='post__permalink'
>
{this.renderTimeTag()}
</Link>
);
}
}
PostTime.defaultProps = {
@@ -46,5 +74,6 @@ PostTime.propTypes = {
eventTime: React.PropTypes.number.isRequired,
sameUser: React.PropTypes.bool,
compactDisplay: React.PropTypes.bool,
useMilitaryTime: React.PropTypes.bool.isRequired
useMilitaryTime: React.PropTypes.bool.isRequired,
postId: React.PropTypes.string
};

View File

@@ -12,6 +12,8 @@ import RhsDropdown from 'components/rhs_dropdown.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import {flagPost, unflagPost} from 'actions/post_actions.jsx';
import TeamStore from 'stores/team_store.jsx';
import * as Utils from 'utils/utils.jsx';
import * as PostUtils from 'utils/post_utils.jsx';
@@ -24,6 +26,7 @@ import {FormattedMessage} from 'react-intl';
import loadingGif from 'images/load.gif';
import React from 'react';
import {Link} from 'react-router/es6';
export default class RhsComment extends React.Component {
constructor(props) {
@@ -38,7 +41,23 @@ export default class RhsComment extends React.Component {
this.canDelete = false;
this.editDisableAction = new DelayedAction(this.handleEditDisable);
this.state = {};
this.state = {
currentTeamDisplayName: TeamStore.getCurrent().name,
width: '',
height: ''
};
}
componentDidMount() {
window.addEventListener('resize', () => {
Utils.updateWindowDimensions(this);
});
}
componentWillUnmount() {
window.removeEventListener('resize', () => {
Utils.updateWindowDimensions(this);
});
}
handlePermalink(e) {
@@ -235,6 +254,31 @@ export default class RhsComment extends React.Component {
);
}
timeTag(post, timeOptions) {
return (
<time
className='post__time'
dateTime={Utils.getDateForUnixTicks(post.create_at).toISOString()}
>
{Utils.getDateForUnixTicks(post.create_at).toLocaleString('en', timeOptions)}
</time>
);
}
renderTimeTag(post, timeOptions) {
return Utils.isMobile() ?
this.timeTag(post, timeOptions) :
(
<Link
to={`/${this.state.currentTeamDisplayName}/pl/${post.id}`}
target='_blank'
className='post__permalink'
>
{this.timeTag(post, timeOptions)}
</Link>
);
}
render() {
const post = this.props.post;
const flagIcon = Constants.FLAG_ICON_SVG;
@@ -479,12 +523,7 @@ export default class RhsComment extends React.Component {
</li>
{botIndicator}
<li className='col'>
<time
className='post__time'
dateTime={Utils.getDateForUnixTicks(post.create_at).toISOString()}
>
{Utils.getDateForUnixTicks(post.create_at).toLocaleString('en', timeOptions)}
</time>
{this.renderTimeTag(post, timeOptions)}
{flagTrigger}
</li>
{options}

View File

@@ -11,6 +11,7 @@ import RhsDropdown from 'components/rhs_dropdown.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import UserStore from 'stores/user_store.jsx';
import TeamStore from 'stores/team_store.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
import {flagPost, unflagPost} from 'actions/post_actions.jsx';
@@ -25,6 +26,7 @@ import {Tooltip, OverlayTrigger} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl';
import React from 'react';
import {Link} from 'react-router/es6';
export default class RhsRootPost extends React.Component {
constructor(props) {
@@ -38,7 +40,23 @@ export default class RhsRootPost extends React.Component {
this.canDelete = false;
this.editDisableAction = new DelayedAction(this.handleEditDisable);
this.state = {};
this.state = {
currentTeamDisplayName: TeamStore.getCurrent().name,
width: '',
height: ''
};
}
componentDidMount() {
window.addEventListener('resize', () => {
Utils.updateWindowDimensions(this);
});
}
componentWillUnmount() {
window.removeEventListener('resize', () => {
Utils.updateWindowDimensions(this);
});
}
handlePermalink(e) {
@@ -100,6 +118,31 @@ export default class RhsRootPost extends React.Component {
unflagPost(this.props.post.id);
}
timeTag(post, timeOptions) {
return (
<time
className='post__time'
dateTime={Utils.getDateForUnixTicks(post.create_at).toISOString()}
>
{Utils.getDateForUnixTicks(post.create_at).toLocaleString('en', timeOptions)}
</time>
);
}
renderTimeTag(post, timeOptions) {
return Utils.isMobile() ?
this.timeTag(post, timeOptions) :
(
<Link
to={`/${this.state.currentTeamDisplayName}/pl/${post.id}`}
target='_blank'
className='post__permalink'
>
{this.timeTag(post, timeOptions)}
</Link>
);
}
render() {
const post = this.props.post;
const user = this.props.user;
@@ -426,12 +469,7 @@ export default class RhsRootPost extends React.Component {
<li className='col__name'>{userProfile}</li>
{botIndicator}
<li className='col'>
<time
className='post__time'
dateTime={Utils.getDateForUnixTicks(post.create_at).toISOString()}
>
{Utils.getDateForUnixTicks(post.create_at).toLocaleString('en', timeOptions)}
</time>
{this.renderTimeTag(post, timeOptions)}
<OverlayTrigger
key={'rootpostflagtooltipkey' + flagVisible}
delayShow={Constants.OVERLAY_TIME_DELAY}

View File

@@ -22,7 +22,7 @@ const ActionTypes = Constants.ActionTypes;
import React from 'react';
import {FormattedMessage, FormattedDate} from 'react-intl';
import {browserHistory} from 'react-router/es6';
import {browserHistory, Link} from 'react-router/es6';
export default class SearchResultsItem extends React.Component {
constructor(props) {
@@ -32,6 +32,24 @@ export default class SearchResultsItem extends React.Component {
this.shrinkSidebar = this.shrinkSidebar.bind(this);
this.unflagPost = this.unflagPost.bind(this);
this.flagPost = this.flagPost.bind(this);
this.state = {
currentTeamDisplayName: TeamStore.getCurrent().name,
width: '',
height: ''
};
}
componentDidMount() {
window.addEventListener('resize', () => {
Utils.updateWindowDimensions(this);
});
}
componentWillUnmount() {
window.removeEventListener('resize', () => {
Utils.updateWindowDimensions(this);
});
}
hideSidebar() {
@@ -59,6 +77,33 @@ export default class SearchResultsItem extends React.Component {
unflagPost(this.props.post.id);
}
timeTag(post) {
return (
<time className='search-item-time'>
<FormattedDate
value={post.create_at}
hour12={!this.props.useMilitaryTime}
hour='2-digit'
minute='2-digit'
/>
</time>
);
}
renderTimeTag(post) {
return Utils.isMobile() ?
this.timeTag(post) :
(
<Link
to={`/${this.state.currentTeamDisplayName}/pl/${post.id}`}
target='_blank'
className='post__permalink'
>
{this.timeTag(post)}
</Link>
);
}
render() {
let channelName = null;
const channel = this.props.channel;
@@ -276,14 +321,7 @@ export default class SearchResultsItem extends React.Component {
</strong></li>
{botIndicator}
<li className='col'>
<time className='search-item-time'>
<FormattedDate
value={post.create_at}
hour12={!this.props.useMilitaryTime}
hour='2-digit'
minute='2-digit'
/>
</time>
{this.renderTimeTag(post)}
{flagContent}
</li>
{rhsControls}

View File

@@ -1199,6 +1199,19 @@
font-size: .9em;
}
.post__permalink {
color: #333;
&:hover, &:focus {
color: #333;
}
&:focus {
text-decoration: none;
}
&:hover {
text-decoration: underline;
}
}
.post-loading-gif {
height: 10px;
margin-top: 6px;

View File

@@ -366,7 +366,9 @@
text-rendering: auto;
top: -2px;
width: 51px;
&:hover {
text-decoration: underline;
}
}
}
}

View File

@@ -1287,3 +1287,7 @@ export function isEmptyObject(object) {
return false;
}
export function updateWindowDimensions(component) {
component.setState({width: window.innerWidth, height: window.innerHeight});
}