PLT-5605 Fix logic for indicating start of new messages (#284)

* Fix placement of new messages separator

* Ignore your own posts when determining start of new messages

* Cache lastViewedAt in ChannelPostList until switching channels

* Increase padding around DateHeader & NewMessagesDivider

* Improve styling of new messages divider line

* Use async await for ChannelDrawerList.onSelectChannel

* Convert DateHeader to functional component
This commit is contained in:
Chris Duarte 2017-02-21 18:59:27 -08:00 committed by enahum
parent 9d9fae43d7
commit afe09babfa
8 changed files with 60 additions and 50 deletions

View file

@ -166,13 +166,13 @@ class ChannelDrawerList extends Component {
}
};
onSelectChannel = (channel) => {
onSelectChannel = async (channel) => {
const {
currentChannel,
currentTeam
} = this.props;
this.props.onSelectChannel(channel.id);
await this.props.onSelectChannel(channel.id);
this.props.actions.viewChannel(currentTeam.id, channel.id);
this.props.actions.markChannelAsRead(channel.id, currentChannel.id);
};

View file

@ -1,7 +1,7 @@
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React from 'react';
import React, {PropTypes} from 'react';
import {StyleSheet, View} from 'react-native';
import FormattedDate from 'app/components/formatted_date';
@ -11,16 +11,16 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
return StyleSheet.create({
container: {
alignItems: 'center',
flexDirection: 'row'
flexDirection: 'row',
height: 28
},
dateContainer: {
marginLeft: 15,
marginRight: 15
marginHorizontal: 15
},
line: {
backgroundColor: theme.centerChannelColor,
flex: 1,
height: StyleSheet.hairlineWidth,
backgroundColor: theme.centerChannelColor,
opacity: 0.2
},
date: {
@ -31,31 +31,31 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
});
});
export default class DateHeader extends React.Component {
static propTypes = {
date: React.PropTypes.object.isRequired,
theme: React.PropTypes.object.isRequired,
style: View.propTypes.style
};
function DateHeader(props) {
const style = getStyleSheet(props.theme);
render() {
const style = getStyleSheet(this.props.theme);
return (
<View style={[style.container, this.props.style]}>
<View style={style.line}/>
<View style={style.dateContainer}>
<FormattedDate
style={style.date}
value={this.props.date}
weekday='short'
day='2-digit'
month='short'
year='numeric'
/>
</View>
<View style={style.line}/>
return (
<View style={[style.container, props.style]}>
<View style={style.line}/>
<View style={style.dateContainer}>
<FormattedDate
style={style.date}
value={props.date}
weekday='short'
day='2-digit'
month='short'
year='numeric'
/>
</View>
);
}
<View style={style.line}/>
</View>
);
}
DateHeader.propTypes = {
date: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
style: View.propTypes.style
};
export default DateHeader;

View file

@ -9,16 +9,16 @@ import FormattedText from 'app/components/formatted_text';
const style = StyleSheet.create({
container: {
alignItems: 'center',
flexDirection: 'row'
flexDirection: 'row',
height: 28
},
textContainer: {
marginHorizontal: 15
},
line: {
flex: 1,
height: 1,
backgroundColor: '#ffaf53',
opacity: 0.2
height: StyleSheet.hairlineWidth,
backgroundColor: '#f80'
},
text: {
fontSize: 14,

View file

@ -31,24 +31,25 @@ export default class PostList extends React.Component {
onPostPress: React.PropTypes.func,
renderReplies: React.PropTypes.bool,
indicateNewMessages: React.PropTypes.bool,
currentUserId: React.PropTypes.string,
lastViewedAt: React.PropTypes.number
};
constructor(props) {
super(props);
const {posts, indicateNewMessages, lastViewedAt} = this.props;
const {posts, indicateNewMessages, currentUserId, lastViewedAt} = this.props;
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (a, b) => a !== b
}).cloneWithRows(addDatesToPostList(posts, indicateNewMessages, lastViewedAt))
}).cloneWithRows(addDatesToPostList(posts, indicateNewMessages, currentUserId, lastViewedAt))
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.posts !== this.props.posts) {
const {posts, indicateNewMessages, lastViewedAt} = nextProps;
const {posts, indicateNewMessages, currentUserId, lastViewedAt} = nextProps;
const dataSource = this.state.dataSource.cloneWithRows(
addDatesToPostList(posts, indicateNewMessages, lastViewedAt)
addDatesToPostList(posts, indicateNewMessages, currentUserId, lastViewedAt)
);
this.setState({dataSource});
}

View file

@ -16,12 +16,17 @@ export default class ChannelPostList extends PureComponent {
posts: PropTypes.array.isRequired
};
state = {
lastViewedAt: this.props.myMember.last_viewed_at
};
componentDidMount() {
this.props.actions.loadPostsIfNecessary(this.props.channel);
}
componentWillReceiveProps(nextProps) {
if (this.props.channel.id !== nextProps.channel.id) {
this.setState({lastViewedAt: nextProps.myMember.last_viewed_at});
this.props.actions.loadPostsIfNecessary(nextProps.channel);
}
}
@ -41,7 +46,8 @@ export default class ChannelPostList extends PureComponent {
onPostPress={this.goToThread}
renderReplies={true}
indicateNewMessages={true}
lastViewedAt={this.props.myMember.last_viewed_at}
currentUserId={this.props.myMember.user_id}
lastViewedAt={this.state.lastViewedAt}
/>
);
}

View file

@ -9,6 +9,7 @@ import {goToThread} from 'app/actions/navigation';
import {loadPostsIfNecessary} from 'app/actions/views/channel';
import {getAllPosts, getPostsInCurrentChannel} from 'service/selectors/entities/posts';
import {getCurrentChannelMembership} from 'service/selectors/entities/channels';
import ChannelPostList from './channel_post_list';
@ -65,7 +66,7 @@ const getPostsInCurrentChannelWithReplyProps = createSelector(
function mapStateToProps(state, ownProps) {
return {
...ownProps,
myMember: state.entities.channels.myMembers[ownProps.channel.id],
myMember: getCurrentChannelMembership(state),
posts: getPostsInCurrentChannelWithReplyProps(state)
};
}

View file

@ -24,7 +24,7 @@ export default class ChannelDrawer extends React.PureComponent {
}
selectChannel = (id) => {
this.props.actions.handleSelectChannel(id);
return this.props.actions.handleSelectChannel(id);
};
render() {

View file

@ -7,13 +7,21 @@ export function isSystemMessage(post) {
return post.type && post.type.startsWith(Constants.SYSTEM_MESSAGE_PREFIX);
}
export function addDatesToPostList(posts, indicateNewMessages, lastViewedAt) {
export function addDatesToPostList(posts, indicateNewMessages, currentUserId, lastViewedAt) {
const out = [];
let lastDate = null;
let subsequentPostIsUnread = false;
let subsequentPostUserId;
let postIsUnread;
for (const post of posts) {
postIsUnread = post.create_at > lastViewedAt;
if (indicateNewMessages && subsequentPostIsUnread && !postIsUnread && subsequentPostUserId !== currentUserId) {
out.push(Constants.START_OF_NEW_MESSAGES);
}
subsequentPostIsUnread = postIsUnread;
subsequentPostUserId = post.user_id;
const postDate = new Date(post.create_at);
// Push on a date header if the last post was on a different day than the current one
@ -23,12 +31,6 @@ export function addDatesToPostList(posts, indicateNewMessages, lastViewedAt) {
lastDate = postDate;
out.push(post);
postIsUnread = post.create_at > lastViewedAt;
if (indicateNewMessages && subsequentPostIsUnread && !postIsUnread) {
out.push(Constants.START_OF_NEW_MESSAGES);
}
subsequentPostIsUnread = postIsUnread;
}
// Push on the date header for the oldest post