summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/react/.eslintrc287
-rw-r--r--web/react/components/login.jsx2
-rw-r--r--web/react/components/post.jsx3
-rw-r--r--web/react/components/post_info.jsx171
-rw-r--r--web/react/components/post_list.jsx45
-rw-r--r--web/react/package.json27
-rw-r--r--web/react/stores/post_store.jsx22
-rw-r--r--web/react/utils/constants.jsx5
8 files changed, 356 insertions, 206 deletions
diff --git a/web/react/.eslintrc b/web/react/.eslintrc
index d8b36f6ca..cdf96905b 100644
--- a/web/react/.eslintrc
+++ b/web/react/.eslintrc
@@ -1,139 +1,160 @@
{
- "ecmaFeatures": {
- "jsx": true,
- "blockBindings": true,
- "modules": true
- },
- "plugins": [
- "react"
- ],
- "env": {
- "browser": true,
- "node": true,
- "jquery": true,
- "es6": true
- },
- "globals": {
- "React": false
- },
- "rules": {
- "comma-dangle": [2, "never"],
- "no-cond-assign": [2, "except-parens"],
- "no-console": 1,
- "no-constant-condition": 1,
- "no-debugger": 1,
- "no-dupe-args": 2,
- "no-dupe-keys": 2,
- "no-duplicate-case": 2,
- "no-empty": 1,
- "no-ex-assign": 1,
- "no-extra-semi": 2,
- "no-func-assign": 1,
- "no-inner-declarations": 0,
- "no-invalid-regexp": 2,
- "no-irregular-whitespace": 2,
- "no-unreachable": 2,
- "valid-typeof": 2,
- "no-unexpected-multiline": 2,
+ "extends": "eslint:recommended",
+ "ecmaFeatures": {
+ "jsx": true,
+ "blockBindings": true,
+ "modules": true,
+ "classes": true
+ },
+ "plugins": [
+ "react"
+ ],
+ "env": {
+ "browser": true,
+ "node": true,
+ "jquery": true,
+ "es6": true
+ },
+ "globals": {
+ "React": false
+ },
+ "rules": {
+ "comma-dangle": [2, "never"],
+ "no-cond-assign": [2, "except-parens"],
+ "no-console": 1,
+ "no-constant-condition": 1,
+ "no-debugger": 1,
+ "no-dupe-args": 2,
+ "no-dupe-keys": 2,
+ "no-duplicate-case": 2,
+ "no-empty": 1,
+ "no-ex-assign": 1,
+ "no-extra-semi": 2,
+ "no-func-assign": 1,
+ "no-inner-declarations": 0,
+ "no-invalid-regexp": 2,
+ "no-irregular-whitespace": 2,
+ "no-unreachable": 2,
+ "valid-typeof": 2,
+ "no-unexpected-multiline": 2,
- "block-scoped-var": 1,
- "complexity": [1, 8],
- "consistent-return": 2,
- "curly": [2, "all"],
- "dot-notation": 2,
- "dot-location": [2, "object"],
- "eqeqeq": [2, "smart"],
- "guard-for-in": 1,
- "no-alert": 1,
- "no-caller": 2,
- "no-div-regex": 1,
- "no-else-return": 1,
- "no-eval": 2,
- "no-extend-native": 2,
- "no-floating-decimal": 2,
- "no-labels": 2,
- "no-lone-blocks": 1,
- "no-multi-spaces": [2, { "exceptions": { "Property": false } }],
- "no-multi-str": 0,
- "no-param-reassign": 2,
- "no-process-env": 2,
- "no-redeclare": 2,
- "no-return-assign": [2, "always"],
- "no-script-url": 2,
- "no-self-compare": 2,
- "no-sequences": 2,
- "no-throw-literal": 2,
- "no-unused-expressions": 2,
- "no-void": 2,
- "no-warning-comments": 0,
- "no-with": 2,
- "radix": 2,
- "vars-on-top": 0,
- "wrap-iife": [2, "outside"],
- "yoda": [2, "never", {"exceptRange": false, "onlyEquality": false}],
+ "block-scoped-var": 1,
+ "complexity": [1, 8],
+ "consistent-return": 2,
+ "curly": [2, "all"],
+ "dot-notation": 2,
+ "dot-location": [2, "object"],
+ "eqeqeq": [2, "smart"],
+ "guard-for-in": 1,
+ "no-alert": 1,
+ "no-array-constructor": 2,
+ "no-caller": 2,
+ "no-div-regex": 1,
+ "no-else-return": 1,
+ "no-eval": 2,
+ "no-extend-native": 2,
+ "no-extra-bind": 2,
+ "no-floating-decimal": 2,
+ "no-implied-eval": 2,
+ "no-iterator": 2,
+ "no-labels": 2,
+ "no-lone-blocks": 1,
+ "no-loop-func": 2,
+ "no-multi-spaces": [2, { "exceptions": { "Property": false } }],
+ "no-multi-str": 0,
+ "no-native-reassign": 2,
+ "no-new": 2,
+ "no-new-func": 2,
+ "no-new-object": 2,
+ "no-new-wrappers": 2,
+ "no-octal-escape": 2,
+ "no-param-reassign": 2,
+ "no-process-env": 2,
+ "no-process-exit": 2,
+ "no-proto": 2,
+ "no-redeclare": 2,
+ "no-return-assign": [2, "always"],
+ "no-script-url": 2,
+ "no-self-compare": 2,
+ "no-sequences": 2,
+ "no-throw-literal": 2,
+ "no-unused-expressions": 2,
+ "no-undef-init": 2,
+ "no-void": 2,
+ "no-warning-comments": 0,
+ "no-with": 2,
+ "radix": 2,
+ "vars-on-top": 0,
+ "wrap-iife": [2, "outside"],
+ "yoda": [2, "never", {"exceptRange": false, "onlyEquality": false}],
- "no-undefined": 2,
- "no-shadow": [2, {"hoist": "functions"}],
- "no-unused-vars": [2, {"vars": "all", "args": "all"}],
- "no-use-before-define": [2, "nofunc"],
+ "no-undefined": 2,
+ "no-shadow": [2, {"hoist": "functions"}],
+ "no-shadow-restricted-names": 2,
+ "no-unused-vars": [2, {"vars": "all", "args": "after-used"}],
+ "no-use-before-define": [2, "nofunc"],
- // Style
- "array-bracket-spacing": [2, "never"],
- "brace-style": [2, "1tbs", { "allowSingleLine": false }],
- "camelcase": [2, {"properties": "always"}],
- "comma-spacing": [2, {"before": false, "after": true}],
- "comma-style": [2, "last"],
- "computed-property-spacing": [2, "never"],
- "consistent-this": [2, "self"],
- "func-names": 2,
- "func-style": [2, "declaration"],
- "indent": [2, 4, {"indentSwitchCase": false}],
- "key-spacing": [2, {"beforeColon": false, "afterColon": true}],
- "lines-around-comment": [2, { "beforeBlockComment": true, "beforeLineComment": true, "allowBlockStart": true, "allowBlockEnd": true }],
- "linebreak-style": 2,
- "new-cap": 2,
- "new-parens": 2,
- "no-lonely-if": 2,
- "no-mixed-spaces-and-tabs": 2,
- "no-multiple-empty-lines": [2, {"max": 1}],
- "no-spaced-func": 2,
- "no-ternary": 2,
- "no-trailing-spaces": [2, { "skipBlankLines": false }],
- "no-underscore-dangle": 2,
- "no-unneeded-ternary": 2,
- "object-curly-spacing": [2, "never"],
- "one-var": [2, "never"],
- "operator-linebreak": [2, "after"],
- "padded-blocks": [2, "never"],
- "quote-props": [2, "as-needed"],
- "quotes": [2, "single", "avoid-escape"],
- "semi-spacing": [2, {"before": false, "after": true}],
- "semi": [2, "always"],
- "space-after-keywords": [2, "always"],
- "space-before-blocks": [2, "always"],
- "space-before-function-paren": [2, "never"],
- "space-in-parens": [2, "never"],
- "space-infix-ops": 2,
- "space-return-throw-case": 2,
- "space-unary-ops": [2, { "words": true, "nonwords": false }],
- "wrap-regex": 2,
+ // Style
+ "array-bracket-spacing": [2, "never"],
+ "brace-style": [2, "1tbs", { "allowSingleLine": false }],
+ "camelcase": [2, {"properties": "always"}],
+ "comma-spacing": [2, {"before": false, "after": true}],
+ "comma-style": [2, "last"],
+ "computed-property-spacing": [2, "never"],
+ "consistent-this": [2, "self"],
+ "func-names": 2,
+ "func-style": [2, "declaration"],
+ "indent": [2, 4, {"SwitchCase": 0}],
+ "key-spacing": [2, {"beforeColon": false, "afterColon": true}],
+ "lines-around-comment": [2, { "beforeBlockComment": true, "beforeLineComment": true, "allowBlockStart": true, "allowBlockEnd": true }],
+ "linebreak-style": 2,
+ "new-cap": 2,
+ "new-parens": 2,
+ "no-lonely-if": 2,
+ "no-mixed-spaces-and-tabs": 2,
+ "no-multiple-empty-lines": [2, {"max": 1}],
+ "no-spaced-func": 2,
+ "no-ternary": 2,
+ "no-trailing-spaces": [2, { "skipBlankLines": false }],
+ "no-underscore-dangle": 2,
+ "no-unneeded-ternary": 2,
+ "object-curly-spacing": [2, "never"],
+ "one-var": [2, "never"],
+ "operator-linebreak": [2, "after"],
+ "padded-blocks": [2, "never"],
+ "quote-props": [2, "as-needed"],
+ "quotes": [2, "single", "avoid-escape"],
+ "semi-spacing": [2, {"before": false, "after": true}],
+ "semi": [2, "always"],
+ "space-after-keywords": [2, "always"],
+ "space-before-blocks": [2, "always"],
+ "space-before-function-paren": [2, "never"],
+ "space-in-parens": [2, "never"],
+ "space-infix-ops": 2,
+ "space-return-throw-case": 2,
+ "space-unary-ops": [2, { "words": true, "nonwords": false }],
+ "wrap-regex": 2,
- // React Specific
- "react/display-name": [2, { "acceptTranspilerName": true }],
- "react/jsx-boolean-value": [2, "always"],
- "react/jsx-curly-spacing": [2, "never"],
- "react/jsx-no-duplicate-props": [2, { "ignoreCase": false }],
- "react/jsx-no-undef": 2,
- "react/jsx-quotes": [2, "single", "avoid-escape"],
- "react/jsx-uses-react": 2,
- "react/jsx-uses-vars": 2,
- "react/no-danger": 0,
- "react/no-did-mount-set-state": 2,
- "react/no-did-update-set-state": 2,
- "react/no-multi-comp": 2,
- "react/no-unknown-property": 2,
- "react/prop-types": 2,
- "react/sort-comp": 0,
- "react/wrap-multilines": 2
- }
+ // React Specific
+ "react/display-name": [2, { "acceptTranspilerName": true }],
+ "react/jsx-boolean-value": [2, "always"],
+ "react/jsx-curly-spacing": [2, "never"],
+ "react/jsx-max-props-per-line": [2, { "maximum": 1 }],
+ // SOON "react/jsx-indent-props": [2, 4],
+ "react/jsx-no-duplicate-props": [2, { "ignoreCase": false }],
+ "react/jsx-no-literals": 0,
+ "react/jsx-no-undef": 2,
+ "react/jsx-quotes": [2, "single", "avoid-escape"],
+ "react/jsx-uses-react": 2,
+ "react/jsx-uses-vars": 2,
+ "react/no-danger": 0,
+ "react/no-did-mount-set-state": 2,
+ "react/no-did-update-set-state": 2,
+ "react/no-multi-comp": 2,
+ "react/no-unknown-property": 2,
+ "react/prop-types": 2,
+ "react/sort-comp": 0,
+ "react/self-closing-comp": 2,
+ "react/wrap-multilines": 2
+ }
}
diff --git a/web/react/components/login.jsx b/web/react/components/login.jsx
index f9eacf094..b61ea931e 100644
--- a/web/react/components/login.jsx
+++ b/web/react/components/login.jsx
@@ -56,7 +56,7 @@ module.exports = React.createClass({
},
function loginFailed(err) {
if (err.message === 'Login failed because email address has not been verified') {
- window.location.href = '/verify_email?name=' + encodeURIComponent(name) + '&email=' + encodeURIComponent(email);
+ window.location.href = '/verify_email?teamname=' + encodeURIComponent(name) + '&email=' + encodeURIComponent(email);
return;
}
state.serverError = err.message;
diff --git a/web/react/components/post.jsx b/web/react/components/post.jsx
index b798dc7ca..7bc6a8c01 100644
--- a/web/react/components/post.jsx
+++ b/web/react/components/post.jsx
@@ -3,7 +3,6 @@
var PostHeader = require('./post_header.jsx');
var PostBody = require('./post_body.jsx');
-var PostInfo = require('./post_info.jsx');
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var Constants = require('../utils/constants.jsx');
var UserStore = require('../stores/user_store.jsx');
@@ -13,6 +12,8 @@ var client = require('../utils/client.jsx');
var AsyncClient = require('../utils/async_client.jsx');
var ActionTypes = Constants.ActionTypes;
+var PostInfo = require('./post_info.jsx');
+
module.exports = React.createClass({
displayName: "Post",
handleCommentClick: function(e) {
diff --git a/web/react/components/post_info.jsx b/web/react/components/post_info.jsx
index f6ab0ed8a..c96a04c7c 100644
--- a/web/react/components/post_info.jsx
+++ b/web/react/components/post_info.jsx
@@ -6,68 +6,145 @@ var utils = require('../utils/utils.jsx');
var Constants = require('../utils/constants.jsx');
-module.exports = React.createClass({
- getInitialState: function() {
- return { };
- },
- render: function() {
+export default class PostInfo extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {};
+ }
+ shouldShowComment(state, type, isOwner) {
+ if (state === Constants.POST_FAILED || state === Constants.POST_LOADING) {
+ return false;
+ }
+ return isOwner || (this.props.allowReply === 'true' && type !== 'Comment');
+ }
+ createDropdown() {
var post = this.props.post;
var isOwner = UserStore.getCurrentId() === post.user_id;
var isAdmin = UserStore.getCurrentUser().roles.indexOf('admin') > -1;
+ if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || post.state === Constants.POST_DELETED) {
+ return '';
+ }
+
var type = 'Post';
if (post.root_id && post.root_id.length > 0) {
type = 'Comment';
}
- var comments = '';
- var lastCommentClass = ' comment-icon__container__hide';
- if (this.props.isLastComment) {
- lastCommentClass = ' comment-icon__container__show';
+ if (!this.shouldShowComment(post.state, type, isOwner)) {
+ return '';
}
- if (this.props.commentCount >= 1 && post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING) {
- comments = <a href='#' className={'comment-icon__container theme' + lastCommentClass} onClick={this.props.handleCommentClick}><span className='comment-icon' dangerouslySetInnerHTML={{__html: Constants.COMMENT_ICON}} />{this.props.commentCount}</a>;
+ var dropdownContents = [];
+ var dataComments = 0;
+ if (type === 'Post') {
+ dataComments = this.props.commentCount;
}
- var showDropdown = isOwner || (this.props.allowReply === 'true' && type !== 'Comment');
- if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING) {
- showDropdown = false;
+ if (isOwner) {
+ dropdownContents.push(
+ <li role='presentation'>
+ <a
+ href='#'
+ role='menuitem'
+ data-toggle='modal'
+ data-target='#edit_post'
+ data-title={type}
+ data-message={post.message}
+ data-postid={post.id}
+ data-channelid={post.channel_id}
+ data-comments={dataComments}
+ >
+ Edit
+ </a>
+ </li>
+ );
}
- var dropdownContents = [];
- var dropdown;
- if (showDropdown) {
- var dataComments = 0;
- if (type === 'Post') {
- dataComments = this.props.commentCount;
- }
-
- if (isOwner) {
- dropdownContents.push(<li role='presentation'><a href='#' role='menuitem' data-toggle='modal' data-target='#edit_post' data-title={type} data-message={post.message} data-postid={post.id} data-channelid={post.channel_id} data-comments={dataComments}>Edit</a></li>);
- }
+ if (isOwner || isAdmin) {
+ dropdownContents.push(
+ <li role='presentation'>
+ <a
+ href='#'
+ role='menuitem'
+ data-toggle='modal'
+ data-target='#delete_post'
+ data-title={type}
+ data-postid={post.id}
+ data-channelid={post.channel_id}
+ data-comments={dataComments}
+ >
+ Delete
+ </a>
+ </li>
+ );
+ }
- if (isOwner || isAdmin) {
- dropdownContents.push(<li role='presentation'><a href='#' role='menuitem' data-toggle='modal' data-target='#delete_post' data-title={type} data-postid={post.id} data-channelid={post.channel_id} data-comments={dataComments}>Delete</a></li>);
- }
+ if (this.props.allowReply === 'true') {
+ dropdownContents.push(
+ <li role='presentation'>
+ <a
+ className='reply-link theme'
+ href='#'
+ onClick={this.props.handleCommentClick}
+ >
+ Reply
+ </a>
+ </li>
+ );
+ }
- if (this.props.allowReply === 'true') {
- dropdownContents.push(<li role='presentation'><a className='reply-link theme' href='#' onClick={this.props.handleCommentClick}>Reply</a></li>);
- }
+ return (
+ <div>
+ <a
+ href='#'
+ className='dropdown-toggle theme'
+ type='button'
+ data-toggle='dropdown'
+ aria-expanded='false'
+ />
+ <ul
+ className='dropdown-menu'
+ role='menu'
+ >
+ {dropdownContents}
+ </ul>
+ </div>
+ );
+ }
+ render() {
+ var post = this.props.post;
+ var comments = '';
+ var lastCommentClass = ' comment-icon__container__hide';
+ if (this.props.isLastComment) {
+ lastCommentClass = ' comment-icon__container__show';
+ }
- dropdown = (
- <div>
- <a href='#' className='dropdown-toggle theme' type='button' data-toggle='dropdown' aria-expanded='false' />
- <ul className='dropdown-menu' role='menu'>
- {dropdownContents}
- </ul>
- </div>
+ if (this.props.commentCount >= 1 && post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING) {
+ comments = (
+ <a
+ href='#'
+ className={'comment-icon__container theme' + lastCommentClass}
+ onClick={this.props.handleCommentClick}
+ >
+ <span
+ className='comment-icon'
+ dangerouslySetInnerHTML={{__html: Constants.COMMENT_ICON}}
+ />
+ {this.props.commentCount}
+ </a>
);
}
+ var dropdown = this.createDropdown();
+
return (
<ul className='post-header post-info'>
- <li className='post-header-col'><time className='post-profile-time'>{utils.displayDateTime(post.create_at)}</time></li>
+ <li className='post-header-col'>
+ <time className='post-profile-time'>
+ {utils.displayDateTime(post.create_at)}
+ </time>
+ </li>
<li className='post-header-col post-header__reply'>
<div className='dropdown'>
{dropdown}
@@ -77,4 +154,18 @@ module.exports = React.createClass({
</ul>
);
}
-});
+}
+
+PostInfo.defaultProps = {
+ post: null,
+ commentCount: 0,
+ isLastComment: false,
+ allowReply: false
+};
+PostInfo.propTypes = {
+ post: React.PropTypes.object,
+ commentCount: React.PropTypes.number,
+ isLastComment: React.PropTypes.bool,
+ allowReply: React.PropTypes.string,
+ handleCommentClick: React.PropTypes.func
+};
diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx
index bebd6847f..5fbee99f6 100644
--- a/web/react/components/post_list.jsx
+++ b/web/react/components/post_list.jsx
@@ -23,12 +23,31 @@ function getStateFromStores() {
}
var postList = PostStore.getCurrentPosts();
+ var deletedPosts = PostStore.getUnseenDeletedPosts(channel.id);
+
+ if (deletedPosts && Object.keys(deletedPosts).length > 0) {
+ for (var pid in deletedPosts) {
+ postList.posts[pid] = deletedPosts[pid];
+ postList.order.unshift(pid);
+ }
+
+ postList.order.sort(function postSort(a, b) {
+ if (postList.posts[a].create_at > postList.posts[b].create_at) {
+ return -1;
+ }
+ if (postList.posts[a].create_at < postList.posts[b].create_at) {
+ return 1;
+ }
+ return 0;
+ });
+ }
+
var pendingPostList = PostStore.getPendingPosts(channel.id);
if (pendingPostList) {
postList.order = pendingPostList.order.concat(postList.order);
- for (var pid in pendingPostList.posts) {
- postList.posts[pid] = pendingPostList.posts[pid];
+ for (var ppid in pendingPostList.posts) {
+ postList.posts[ppid] = pendingPostList.posts[ppid];
}
}
@@ -88,7 +107,6 @@ module.exports = React.createClass({
$('.modal-body').css('max-height', $(window).height() * 0.7);
});
- // Timeout exists for the DOM to fully render before making changes
var self = this;
$(window).resize(function resize() {
$(postHolder).perfectScrollbar('update');
@@ -185,6 +203,7 @@ module.exports = React.createClass({
}
}
if (this.state.channel.id !== newState.channel.id) {
+ PostStore.clearUnseenDeletedPosts(this.state.channel.id);
this.scrolledToNew = false;
}
this.setState(newState);
@@ -220,23 +239,19 @@ module.exports = React.createClass({
activeRootPostId = activeRoot.id;
}
- if (this.state.channel.id === msg.channel_id) {
- postList = this.state.postList;
- if (!(msg.props.post_id in this.state.postList.posts)) {
- return;
- }
+ post = JSON.parse(msg.props.post);
+ postList = this.state.postList;
+
+ PostStore.storeUnseenDeletedPost(post);
- delete postList.posts[msg.props.post_id];
- var index = postList.order.indexOf(msg.props.post_id);
+ if (postList.posts[post.id]) {
+ delete postList.posts[post.id];
+ var index = postList.order.indexOf(post.id);
if (index > -1) {
postList.order.splice(index, 1);
}
- this.setState({postList: postList});
-
PostStore.storePosts(msg.channel_id, postList);
- } else {
- AsyncClient.getPosts(true, msg.channel_id);
}
if (activeRootPostId === msg.props.post_id && UserStore.getCurrentId() !== msg.user_id) {
@@ -318,7 +333,7 @@ module.exports = React.createClass({
var lastViewed = Number.MAX_VALUE;
if (ChannelStore.getCurrentMember() != null) {
- lastViewed = ChannelStore.getCurrentMember().lastViewed_at;
+ lastViewed = ChannelStore.getCurrentMember().last_viewed_at;
}
if (this.state.postList != null) {
diff --git a/web/react/package.json b/web/react/package.json
index 2bba29e2b..c930c4db6 100644
--- a/web/react/package.json
+++ b/web/react/package.json
@@ -3,22 +3,21 @@
"version": "0.0.1",
"private": true,
"dependencies": {
- "flux": "^2.0.0",
- "keymirror": "~0.1.0",
- "object-assign": "^1.0.0",
- "react": "^0.12.0",
- "autolinker": "^0.15.2",
+ "autolinker": "^0.18.1",
+ "flux": "^2.1.1",
+ "keymirror": "^0.1.1",
+ "object-assign": "^3.0.0",
+ "react": "^0.13.3",
"react-zeroclipboard-mixin": "^0.1.0"
},
"devDependencies": {
- "browserify": "^6.2.0",
- "envify": "^3.0.0",
- "jest-cli": "~0.1.17",
- "reactify": "^0.15.2",
- "uglify-js": "~2.4.15",
- "watchify": "^2.1.1",
- "eslint": "^0.24.1",
- "eslint-plugin-react": "^3.0.0"
+ "browserify": "^11.0.1",
+ "envify": "^3.4.0",
+ "babelify": "^6.1.3",
+ "uglify-js": "^2.4.24",
+ "watchify": "^3.3.1",
+ "eslint": "^1.1.0",
+ "eslint-plugin-react": "^3.2.3"
},
"scripts": {
"start": "watchify --extension=jsx -o ../static/js/bundle.js -v -d ./**/*.jsx",
@@ -28,7 +27,7 @@
},
"browserify": {
"transform": [
- "reactify",
+ ["babelify", {"blacklist": ["strict"]}],
"envify"
]
},
diff --git a/web/react/stores/post_store.jsx b/web/react/stores/post_store.jsx
index 3e4fde30a..2fffb17d0 100644
--- a/web/react/stores/post_store.jsx
+++ b/web/react/stores/post_store.jsx
@@ -172,6 +172,28 @@ var PostStore = assign({}, EventEmitter.prototype, {
getPendingPosts: function(channelId) {
return BrowserStore.getItem('pending_posts_' + channelId);
},
+ storeUnseenDeletedPost: function(post) {
+ var posts = this.getUnseenDeletedPosts(post.channel_id);
+
+ if (!posts) {
+ posts = {};
+ }
+
+ post.message = '(message deleted)';
+ post.state = Constants.POST_DELETED;
+
+ posts[post.id] = post;
+ this.storeUnseenDeletedPosts(post.channel_id, posts);
+ },
+ storeUnseenDeletedPosts: function(channelId, posts) {
+ BrowserStore.setItem('deleted_posts_' + channelId, posts);
+ },
+ getUnseenDeletedPosts: function(channelId) {
+ return BrowserStore.getItem('deleted_posts_' + channelId);
+ },
+ clearUnseenDeletedPosts: function(channelId) {
+ BrowserStore.setItem('deleted_posts_' + channelId, {});
+ },
removePendingPost: function(channelId, pendingPostId) {
this._removePendingPost(channelId, pendingPostId);
this.emitChange();
diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx
index 41b02c8d6..8239a4a69 100644
--- a/web/react/utils/constants.jsx
+++ b/web/react/utils/constants.jsx
@@ -63,8 +63,9 @@ module.exports = {
GOOGLE_SERVICE: 'google',
POST_CHUNK_SIZE: 60,
MAX_POST_CHUNKS: 3,
- POST_LOADING: "loading",
- POST_FAILED: "failed",
+ POST_LOADING: 'loading',
+ POST_FAILED: 'failed',
+ POST_DELETED: 'deleted',
RESERVED_TEAM_NAMES: [
"www",
"web",