From ed68f2e9015f3ac94ef1d5f7bf2941611625c60d Mon Sep 17 00:00:00 2001
From: Christopher Speller <crspeller@gmail.com>
Date: Thu, 29 Oct 2015 17:45:33 -0400
Subject: Refactoring center channel

---
 web/react/components/posts_view.jsx | 249 ++++++++++++++++++++++++++++++++++++
 1 file changed, 249 insertions(+)
 create mode 100644 web/react/components/posts_view.jsx

(limited to 'web/react/components/posts_view.jsx')

diff --git a/web/react/components/posts_view.jsx b/web/react/components/posts_view.jsx
new file mode 100644
index 000000000..d9a95af8b
--- /dev/null
+++ b/web/react/components/posts_view.jsx
@@ -0,0 +1,249 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+const UserStore = require('../stores/user_store.jsx');
+const Utils = require('../utils/utils.jsx');
+const Post = require('./post.jsx');
+
+export default class PostsView extends React.Component {
+    constructor(props) {
+        super(props);
+
+        this.handleScroll = this.handleScroll.bind(this);
+        this.loadMorePostsTop = this.loadMorePostsTop.bind(this);
+        this.postsRerendered = this.postsRerendered.bind(this);
+        this.createPosts = this.createPosts.bind(this);
+        this.scrollToBottom = this.scrollToBottom.bind(this);
+        this.handleResize = this.handleResize.bind(this);
+    }
+    static get SCROLL_TYPE_FREE() {
+        return 1;
+    }
+    static get SCROLL_TYPE_BOTTOM() {
+        return 2;
+    }
+    handleScroll() {
+        const atBottom = ((this.refs.postlist.scrollHeight - this.refs.postlist.scrollTop) === this.refs.postlist.clientHeight);
+        this.props.postListScrolled(atBottom);
+    }
+    loadMorePostsTop() {
+        this.props.loadMorePostsTopClicked();
+    }
+    postsRerendered() {
+    }
+    createPosts(posts, order) {
+        const postCtls = [];
+        let previousPostDay = new Date(0);
+        const userId = UserStore.getCurrentId();
+
+        let renderedLastViewed = false;
+
+        let numToDisplay = this.props.numPostsToDisplay;
+        if (order.length - 1 < numToDisplay) {
+            numToDisplay = order.length - 1;
+        }
+
+        for (let i = numToDisplay; i >= 0; i--) {
+            const post = posts[order[i]];
+            const parentPost = posts[post.parent_id];
+            const prevPost = posts[order[i + 1]];
+
+            let sameUser = false;
+            let sameRoot = false;
+            let hideProfilePic = false;
+
+            if (prevPost) {
+                sameUser = prevPost.user_id === post.user_id && post.create_at - prevPost.create_at <= 1000 * 60 * 5;
+
+                sameRoot = Utils.isComment(post) && (prevPost.id === post.root_id || prevPost.root_id === post.root_id);
+
+                // hide the profile pic if:
+                //     the previous post was made by the same user as the current post,
+                //     the previous post is not a comment,
+                //     the current post is not a comment,
+                //     the current post is not from a webhook
+                //     and the previous post is not from a webhook
+                if ((prevPost.user_id === post.user_id) &&
+                        !Utils.isComment(prevPost) &&
+                        !Utils.isComment(post) &&
+                        (!post.props || !post.props.from_webhook) &&
+                        (!prevPost.props || !prevPost.props.from_webhook)) {
+                    hideProfilePic = true;
+                }
+            }
+
+            // check if it's the last comment in a consecutive string of comments on the same post
+            // it is the last comment if it is last post in the channel or the next post has a different root post
+            var isLastComment = Utils.isComment(post) && (i === 0 || posts[order[i - 1]].root_id !== post.root_id);
+
+            var postCtl = (
+                <Post
+                    key={post.id + 'postKey'}
+                    ref={post.id}
+                    sameUser={sameUser}
+                    sameRoot={sameRoot}
+                    post={post}
+                    parentPost={parentPost}
+                    posts={posts}
+                    hideProfilePic={hideProfilePic}
+                    isLastComment={isLastComment}
+                    resize={this.postsRerendered}
+                />
+            );
+
+            const currentPostDay = Utils.getDateForUnixTicks(post.create_at);
+            if (currentPostDay.toDateString() !== previousPostDay.toDateString()) {
+                postCtls.push(
+                    <div
+                        key={currentPostDay.toDateString()}
+                        className='date-separator'
+                    >
+                        <hr className='separator__hr' />
+                        <div className='separator__text'>{currentPostDay.toDateString()}</div>
+                    </div>
+                );
+            }
+
+            if (post.user_id !== userId &&
+                    this.props.messageSeparatorTime !== 0 &&
+                    post.create_at > this.props.messageSeparatorTime &&
+                    !renderedLastViewed) {
+                renderedLastViewed = true;
+
+                // Temporary fix to solve ie11 rendering issue
+                let newSeparatorId = '';
+                if (!Utils.isBrowserIE()) {
+                    newSeparatorId = 'new_message_' + post.id;
+                }
+                postCtls.push(
+                    <div
+                        id={newSeparatorId}
+                        key='unviewed'
+                        className='new-separator'
+                    >
+                        <hr
+                            className='separator__hr'
+                        />
+                        <div className='separator__text'>{'New Messages'}</div>
+                    </div>
+                );
+            }
+            postCtls.push(postCtl);
+            previousPostDay = currentPostDay;
+        }
+
+        return postCtls;
+    }
+    scrollToBottom() {
+        if (this.props.scrollType === PostsView.SCROLL_TYPE_BOTTOM) {
+            window.requestAnimationFrame(() => {
+                this.refs.postlist.scrollTop = this.refs.postlist.scrollHeight;
+            });
+        }
+    }
+    handleResize() {
+        this.scrollToBottom();
+    }
+    componentDidMount() {
+        this.scrollToBottom();
+        window.addEventListener('resize', this.handleResize);
+    }
+    componentWillUnmount() {
+        window.removeEventListener('resize', this.handleResize);
+    }
+    componentDidUpdate() {
+        this.scrollToBottom();
+    }
+    shouldComponentUpdate(nextProps) {
+        if (this.props.isActive !== nextProps.isActive) {
+            return true;
+        }
+        if (this.props.postList !== nextProps.postList) {
+            return true;
+        }
+        if (this.props.scrollPost !== nextProps.scrollPost) {
+            return true;
+        }
+        if (this.props.scrollType !== nextProps.scrollType && nextProps.scrollType !== PostsView.SCROLL_TYPE_FREE) {
+            return true;
+        }
+        if (this.props.numPostsToDisplay !== nextProps.numPostsToDisplay) {
+            return true;
+        }
+        if (this.props.messageSeparatorTime !== nextProps.messageSeparatorTime) {
+            return true;
+        }
+        if (!Utils.areStatesEqual(this.props.postList, nextProps.postList)) {
+            return true;
+        }
+
+        return false;
+    }
+    render() {
+        let posts = [];
+        let order = [];
+        let moreMessages;
+        let postElements;
+        let activeClass = 'inactive';
+        if (this.props.postList != null) {
+            posts = this.props.postList.posts;
+            order = this.props.postList.order;
+
+            // Create intro message or top loadmore link
+            if (order.length >= this.props.numPostsToDisplay) {
+                moreMessages = (
+                    <a
+                        ref='loadmore'
+                        className='more-messages-text theme'
+                        href='#'
+                        onClick={this.loadMorePostsTop}
+                        >
+                        {'Load more messages'}
+                    </a>
+                );
+            } else {
+                moreMessages = this.props.introText;
+            }
+
+            // Create post elements
+            postElements = this.createPosts(posts, order);
+
+            // Show ourselves if we are marked active
+            if (this.props.isActive) {
+                activeClass = '';
+            }
+        }
+
+        return (
+            <div
+                ref='postlist'
+                className={'post-list-holder-by-time ' + activeClass}
+                onScroll={this.handleScroll}
+            >
+                <div className='post-list__table'>
+                    <div
+                        ref='postlistcontent'
+                        className='post-list__content'
+                    >
+                        {moreMessages}
+                        {postElements}
+                    </div>
+                </div>
+            </div>
+        );
+    }
+}
+PostsView.defaultProps = {
+};
+
+PostsView.propTypes = {
+    isActive: React.PropTypes.bool,
+    postList: React.PropTypes.object.isRequired,
+    scrollPost: React.PropTypes.string,
+    scrollType: React.PropTypes.number,
+    postListScrolled: React.PropTypes.func.isRequired,
+    loadMorePostsTopClicked: React.PropTypes.func.isRequired,
+    numPostsToDisplay: React.PropTypes.number,
+    introText: React.PropTypes.element,
+    messageSeparatorTime: React.PropTypes.number
+};
-- 
cgit v1.2.3-1-g7c22

