mattermost-mobile/app/components/post_list/post_list.js
Harrison Healey 0e4f9d5825 Changed to pass IDs to PostList instead of posts (#1036)
* Moved PostList to take a list of postIds instead of posts

* Removed usage of selectors that return posts from ChannelPostList and Thread

* Fixed search and switched to use getPostIdsAroundPost selector

* Removed use of selectors that returned posts from emoji reactions

* Updated makePreparePostIdsForPostList to be better memoized

* Fixed filter of join/leave messages

* Added unit tests for makePrepaprePostIdsForPostList

* Check if post edit/delete should be enabled more often

* Updated mattermost-redux version in yarn.lock
2017-10-20 18:58:44 -03:00

192 lines
5.6 KiB
JavaScript

// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
StyleSheet,
View
} from 'react-native';
import ChannelIntro from 'app/components/channel_intro';
import FlatList from 'app/components/inverted_flat_list';
import Post from 'app/components/post';
import {DATE_LINE, START_OF_NEW_MESSAGES} from 'app/selectors/post_list';
import DateHeader from './date_header';
import LoadMorePosts from './load_more_posts';
import NewMessagesDivider from './new_messages_divider';
export default class PostList extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
refreshChannelWithRetry: PropTypes.func.isRequired
}).isRequired,
channelId: PropTypes.string,
currentUserId: PropTypes.string,
highlightPostId: PropTypes.string,
indicateNewMessages: PropTypes.bool,
isSearchResult: PropTypes.bool,
lastViewedAt: PropTypes.number, // Used by container // eslint-disable-line no-unused-prop-types
loadMore: PropTypes.func,
navigator: PropTypes.object,
onPostPress: PropTypes.func,
onRefresh: PropTypes.func,
postIds: PropTypes.array.isRequired,
renderReplies: PropTypes.bool,
showLoadMore: PropTypes.bool,
shouldRenderReplyButton: PropTypes.bool,
theme: PropTypes.object.isRequired
};
static defaultProps = {
loadMore: () => true
};
componentDidUpdate(prevProps) {
if (prevProps.channelId !== this.props.channelId && this.refs.list) {
// When switching channels make sure we start from the bottom
this.refs.list.scrollToOffset({y: 0, animated: false});
}
}
getItem = (data, index) => data[index];
getItemCount = (data) => data.length;
keyExtractor = (item) => {
// All keys are strings (either post IDs or special keys)
return item;
};
onRefresh = () => {
const {
actions,
channelId,
onRefresh
} = this.props;
if (channelId) {
actions.refreshChannelWithRetry(channelId);
}
if (onRefresh) {
onRefresh();
}
};
renderItem = ({item, index}) => {
if (item === START_OF_NEW_MESSAGES) {
return (
<NewMessagesDivider
theme={this.props.theme}
/>
);
} else if (item.indexOf(DATE_LINE) === 0) {
const date = item.substring(DATE_LINE.length);
return this.renderDateHeader(new Date(date));
}
const postId = item;
// Remember that the list is rendered with item 0 at the bottom so the "previous" post
// comes after this one in the list
const previousPostId = index < this.props.postIds.length - 1 ? this.props.postIds[index + 1] : null;
const nextPostId = index > 0 ? this.props.postIds[index - 1] : null;
return this.renderPost(postId, previousPostId, nextPostId);
};
renderDateHeader = (date) => {
return (
<DateHeader
theme={this.props.theme}
date={date}
/>
);
};
renderPost = (postId, previousPostId, nextPostId) => {
const {
highlightPostId,
isSearchResult,
navigator,
onPostPress,
renderReplies,
shouldRenderReplyButton
} = this.props;
return (
<Post
postId={postId}
previousPostId={previousPostId}
nextPostId={nextPostId}
highlight={highlightPostId && highlightPostId === postId}
renderReplies={renderReplies}
isSearchResult={isSearchResult}
shouldRenderReplyButton={shouldRenderReplyButton}
onPress={onPostPress}
navigator={navigator}
/>
);
};
renderFooter = () => {
if (this.props.showLoadMore) {
return <LoadMorePosts theme={this.props.theme}/>;
} else if (this.props.channelId) {
// FIXME: Only show the channel intro when we are at the very start of the channel
return (
<View>
<ChannelIntro navigator={this.props.navigator}/>
</View>
);
}
return null;
};
render() {
const {
channelId,
highlightPostId,
loadMore,
postIds,
theme
} = this.props;
const refreshControl = {
refreshing: false
};
if (channelId) {
refreshControl.onRefresh = this.onRefresh;
}
return (
<FlatList
ref='list'
data={postIds}
extraData={highlightPostId}
initialNumToRender={15}
inverted={true}
keyExtractor={this.keyExtractor}
ListFooterComponent={this.renderFooter}
onEndReached={loadMore}
onEndReachedThreshold={0}
{...refreshControl}
renderItem={this.renderItem}
theme={theme}
getItem={this.getItem}
getItemCount={this.getItemCount}
contentContainerStyle={styles.postListContent}
/>
);
}
}
const styles = StyleSheet.create({
postListContent: {
paddingTop: 5
}
});