From afe09babfacdd78403c5852d9dd792416d2c2e3e Mon Sep 17 00:00:00 2001 From: Chris Duarte Date: Tue, 21 Feb 2017 18:59:27 -0800 Subject: [PATCH] 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 --- .../channel_drawer_list.js | 4 +- app/components/post_list/date_header.js | 60 +++++++++---------- .../post_list/new_messages_divider.js | 8 +-- app/components/post_list/post_list.js | 9 +-- .../channel_post_list/channel_post_list.js | 8 ++- .../channel_post_list_container.js | 3 +- app/scenes/channel_drawer/channel_drawer.js | 2 +- service/utils/post_utils.js | 16 ++--- 8 files changed, 60 insertions(+), 50 deletions(-) diff --git a/app/components/channel_drawer_list/channel_drawer_list.js b/app/components/channel_drawer_list/channel_drawer_list.js index 73dcfccf9..f652371b6 100644 --- a/app/components/channel_drawer_list/channel_drawer_list.js +++ b/app/components/channel_drawer_list/channel_drawer_list.js @@ -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); }; diff --git a/app/components/post_list/date_header.js b/app/components/post_list/date_header.js index 99203ca07..47e43c369 100644 --- a/app/components/post_list/date_header.js +++ b/app/components/post_list/date_header.js @@ -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 ( - - - - - - + return ( + + + + - ); - } + + + ); } + +DateHeader.propTypes = { + date: PropTypes.object.isRequired, + theme: PropTypes.object.isRequired, + style: View.propTypes.style +}; + +export default DateHeader; diff --git a/app/components/post_list/new_messages_divider.js b/app/components/post_list/new_messages_divider.js index e2ca9436a..e7f1e2f8b 100644 --- a/app/components/post_list/new_messages_divider.js +++ b/app/components/post_list/new_messages_divider.js @@ -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, diff --git a/app/components/post_list/post_list.js b/app/components/post_list/post_list.js index 966976eea..e69068f77 100644 --- a/app/components/post_list/post_list.js +++ b/app/components/post_list/post_list.js @@ -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}); } diff --git a/app/scenes/channel/channel_post_list/channel_post_list.js b/app/scenes/channel/channel_post_list/channel_post_list.js index 3bc5c4841..917e9eac7 100644 --- a/app/scenes/channel/channel_post_list/channel_post_list.js +++ b/app/scenes/channel/channel_post_list/channel_post_list.js @@ -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} /> ); } diff --git a/app/scenes/channel/channel_post_list/channel_post_list_container.js b/app/scenes/channel/channel_post_list/channel_post_list_container.js index cd483b8db..ae2ef1c37 100644 --- a/app/scenes/channel/channel_post_list/channel_post_list_container.js +++ b/app/scenes/channel/channel_post_list/channel_post_list_container.js @@ -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) }; } diff --git a/app/scenes/channel_drawer/channel_drawer.js b/app/scenes/channel_drawer/channel_drawer.js index 902f64fd2..e293abe00 100644 --- a/app/scenes/channel_drawer/channel_drawer.js +++ b/app/scenes/channel_drawer/channel_drawer.js @@ -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() { diff --git a/service/utils/post_utils.js b/service/utils/post_utils.js index c3d84a288..9c1cb7f00 100644 --- a/service/utils/post_utils.js +++ b/service/utils/post_utils.js @@ -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