From db13b7a3ca3d3099392be557e47f838a7851a69a Mon Sep 17 00:00:00 2001 From: hmhealey Date: Mon, 1 Feb 2016 15:22:44 -0500 Subject: Changed deleted posts to be more general ephemeral posts --- web/react/components/delete_post_modal.jsx | 2 +- web/react/components/post_info.jsx | 25 +++++++- web/react/dispatcher/event_helpers.jsx | 7 +++ web/react/stores/post_store.jsx | 91 ++++++++---------------------- web/react/utils/constants.jsx | 2 + web/sass-files/sass/partials/_post.scss | 9 ++- 6 files changed, 64 insertions(+), 72 deletions(-) (limited to 'web') diff --git a/web/react/components/delete_post_modal.jsx b/web/react/components/delete_post_modal.jsx index 34fd724f5..9d7dcb3e5 100644 --- a/web/react/components/delete_post_modal.jsx +++ b/web/react/components/delete_post_modal.jsx @@ -88,7 +88,7 @@ export default class DeletePostModal extends React.Component { } } - PostStore.removePost(this.state.post.id, this.state.post.channel_id); + PostStore.deletePost(this.state.post); AsyncClient.getPosts(this.state.post.channel_id); }, (err) => { diff --git a/web/react/components/post_info.jsx b/web/react/components/post_info.jsx index ddb393520..02150bd9d 100644 --- a/web/react/components/post_info.jsx +++ b/web/react/components/post_info.jsx @@ -23,13 +23,14 @@ export default class PostInfo extends React.Component { }; this.handlePermalinkCopy = this.handlePermalinkCopy.bind(this); + this.removePost = this.removePost.bind(this); } createDropdown() { var post = this.props.post; var isOwner = UserStore.getCurrentId() === post.user_id; var isAdmin = Utils.isAdmin(UserStore.getCurrentUser().roles); - if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || post.state === Constants.POST_DELETED) { + if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || post.ephemeral) { return ''; } @@ -166,6 +167,25 @@ export default class PostInfo extends React.Component { this.setState({copiedLink: false}); } } + removePost() { + EventHelpers.emitRemovePost(this.props.post); + } + createRemovePostButton(post) { + if (!post.ephemeral) { + return null; + } + + return ( + + {'×'} + + ); + } render() { var post = this.props.post; var comments = ''; @@ -178,7 +198,7 @@ export default class PostInfo extends React.Component { commentCountText = ''; } - if (post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING && post.state !== Constants.POST_DELETED) { + if (post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING && !post.ephemeral) { comments = ( {permalinkOverlay} + {this.createRemovePostButton(post)} ); diff --git a/web/react/dispatcher/event_helpers.jsx b/web/react/dispatcher/event_helpers.jsx index 5eb319320..cb41bd1bb 100644 --- a/web/react/dispatcher/event_helpers.jsx +++ b/web/react/dispatcher/event_helpers.jsx @@ -180,3 +180,10 @@ export function emitPreferenceChangedEvent(preference) { preference }); } + +export function emitRemovePost(post) { + AppDispatcher.handleViewAction({ + type: Constants.ActionTypes.REMOVE_POST, + post + }); +} diff --git a/web/react/stores/post_store.jsx b/web/react/stores/post_store.jsx index 08ffef822..93e565403 100644 --- a/web/react/stores/post_store.jsx +++ b/web/react/stores/post_store.jsx @@ -57,6 +57,7 @@ class PostStoreClass extends EventEmitter { this.clearFocusedPost = this.clearFocusedPost.bind(this); this.clearChannelVisibility = this.clearChannelVisibility.bind(this); + this.deletePost = this.deletePost.bind(this); this.removePost = this.removePost.bind(this); this.getPendingPosts = this.getPendingPosts.bind(this); @@ -65,10 +66,6 @@ class PostStoreClass extends EventEmitter { this.clearPendingPosts = this.clearPendingPosts.bind(this); this.updatePendingPost = this.updatePendingPost.bind(this); - this.storeUnseenDeletedPost = this.storeUnseenDeletedPost.bind(this); - this.getUnseenDeletedPosts = this.getUnseenDeletedPosts.bind(this); - this.clearUnseenDeletedPosts = this.clearUnseenDeletedPosts.bind(this); - // These functions are bad and work should be done to remove this system when the RHS dies this.storeSelectedPost = this.storeSelectedPost.bind(this); this.getSelectedPost = this.getSelectedPost.bind(this); @@ -211,28 +208,6 @@ class PostStoreClass extends EventEmitter { postList.order = this.postsInfo[id].pendingPosts.order.concat(postList.order); } - // Add deleted posts - if (this.postsInfo[id].hasOwnProperty('deletedPosts')) { - Object.assign(postList.posts, this.postsInfo[id].deletedPosts); - - for (const postID in this.postsInfo[id].deletedPosts) { - if (this.postsInfo[id].deletedPosts.hasOwnProperty(postID)) { - postList.order.push(postID); - } - } - - // Merge would be faster - postList.order.sort((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; - }); - } - return postList; } @@ -286,15 +261,6 @@ class PostStoreClass extends EventEmitter { if (combinedPosts.order.indexOf(pid) === -1) { combinedPosts.order.push(pid); } - } else { - if (pid in combinedPosts.posts) { - Reflect.deleteProperty(combinedPosts.posts, pid); - } - - const index = combinedPosts.order.indexOf(pid); - if (index !== -1) { - combinedPosts.order.splice(index, 1); - } } } } @@ -365,6 +331,24 @@ class PostStoreClass extends EventEmitter { this.postsInfo[id].atBottom = atBottom; } + deletePost(post) { + const postList = this.postsInfo[post.channel_id].postList; + + if (isPostListNull(postList)) { + return; + } + + if (post.id in postList.posts) { + // make sure to copy the post so that component state changes work properly + postList.posts[post.id] = Object.assign({}, post, { + message: this.delete_message, // TODO + state: Constants.POST_DELETED, + filenames: [], + ephemeral: true + }); + } + } + removePost(post) { const channelId = post.channel_id; this.makePostsInfo(channelId); @@ -439,37 +423,6 @@ class PostStoreClass extends EventEmitter { this.emitChange(); } - storeUnseenDeletedPost(post) { - let posts = this.getUnseenDeletedPosts(post.channel_id); - - if (!posts) { - posts = {}; - } - - post.message = this.delete_message; - post.state = Constants.POST_DELETED; - post.filenames = []; - - posts[post.id] = post; - - this.makePostsInfo(post.channel_id); - this.postsInfo[post.channel_id].deletedPosts = posts; - } - - getUnseenDeletedPosts(channelId) { - if (this.postsInfo.hasOwnProperty(channelId)) { - return this.postsInfo[channelId].deletedPosts; - } - - return null; - } - - clearUnseenDeletedPosts(channelId) { - if (this.postsInfo.hasOwnProperty(channelId)) { - Reflect.deleteProperty(this.postsInfo[channelId], 'deletedPosts'); - } - } - storeSelectedPost(postList) { this.selectedPost = postList; } @@ -615,7 +568,6 @@ PostStore.dispatchToken = AppDispatcher.register((payload) => { case ActionTypes.CLICK_CHANNEL: PostStore.clearFocusedPost(); PostStore.clearChannelVisibility(action.id, true); - PostStore.clearUnseenDeletedPosts(action.prev); break; case ActionTypes.CREATE_POST: PostStore.storePendingPost(action.post); @@ -623,7 +575,10 @@ PostStore.dispatchToken = AppDispatcher.register((payload) => { PostStore.jumpPostsViewToBottom(); break; case ActionTypes.POST_DELETED: - PostStore.storeUnseenDeletedPost(action.post); + PostStore.deletePost(action.post); + PostStore.emitChange(); + break; + case ActionTypes.REMOVE_POST: PostStore.removePost(action.post); PostStore.emitChange(); break; diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index 11a8da669..7d103a270 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -12,6 +12,7 @@ export default { LEAVE_CHANNEL: null, CREATE_POST: null, POST_DELETED: null, + REMOVE_POST: null, RECIEVED_CHANNELS: null, RECIEVED_CHANNEL: null, @@ -127,6 +128,7 @@ export default { POST_FAILED: 'failed', POST_DELETED: 'deleted', POST_TYPE_JOIN_LEAVE: 'system_join_leave', + POST_TYPE_EPHEMERAL: 'system_ephemeral', SYSTEM_MESSAGE_PREFIX: 'system_', SYSTEM_MESSAGE_PROFILE_NAME: 'System', SYSTEM_MESSAGE_PROFILE_IMAGE: '/static/images/logo_compact.png', diff --git a/web/sass-files/sass/partials/_post.scss b/web/sass-files/sass/partials/_post.scss index 3f80e6664..4a3415bb5 100644 --- a/web/sass-files/sass/partials/_post.scss +++ b/web/sass-files/sass/partials/_post.scss @@ -408,7 +408,7 @@ body.ios { @include legacy-pie-clearfix; &:hover { - .dropdown, .comment-icon__container, .post__reply { + .dropdown, .comment-icon__container, .post__reply, .post__remove { visibility: visible; } .permalink-icon { @@ -646,6 +646,13 @@ body.ios { } } + .post__remove { + display: inline-block; + visibility: hidden; + margin-right: 5px; + top: -1px; + } + .post__body { word-wrap: break-word; padding: 0.2em 0.5em 0em; -- cgit v1.2.3-1-g7c22 From fcb92fa1b53a2b67323a881e7cb03965d3ec24d1 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Tue, 2 Feb 2016 10:52:18 -0500 Subject: Added ephemeral messages sent when a user mentions someone not in the channel --- web/react/stores/socket_store.jsx | 1 + web/react/utils/constants.jsx | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'web') diff --git a/web/react/stores/socket_store.jsx b/web/react/stores/socket_store.jsx index 744c2c8e5..745b94313 100644 --- a/web/react/stores/socket_store.jsx +++ b/web/react/stores/socket_store.jsx @@ -109,6 +109,7 @@ class SocketStoreClass extends EventEmitter { handleMessage(msg) { switch (msg.action) { case SocketEvents.POSTED: + case SocketEvents.EPHEMERAL_MESSAGE: handleNewPostEvent(msg, this.translations); break; diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index 7d103a270..cfb33a79c 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -79,7 +79,8 @@ export default { USER_ADDED: 'user_added', USER_REMOVED: 'user_removed', TYPING: 'typing', - PREFERENCE_CHANGED: 'preference_changed' + PREFERENCE_CHANGED: 'preference_changed', + EPHEMERAL_MESSAGE: 'ephemeral_message' }, //SPECIAL_MENTIONS: ['all', 'channel'], -- cgit v1.2.3-1-g7c22 From fd123a6e4a7cfd19ff7ddc7141bc928c27e0a890 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Tue, 2 Feb 2016 15:34:22 -0500 Subject: Changed PostStore to not clear a deleted post's message --- web/react/components/create_post.jsx | 7 +------ web/react/components/post_body.jsx | 30 ++++++++++++++++++++++-------- web/react/stores/post_store.jsx | 4 ---- web/static/i18n/en.json | 4 ++-- web/static/i18n/es.json | 4 ++-- 5 files changed, 27 insertions(+), 22 deletions(-) (limited to 'web') diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx index ed672cd34..3dfc91970 100644 --- a/web/react/components/create_post.jsx +++ b/web/react/components/create_post.jsx @@ -40,10 +40,6 @@ const holders = defineMessages({ write: { id: 'create_post.write', defaultMessage: 'Write a message...' - }, - deleteMsg: { - id: 'create_post.deleteMsg', - defaultMessage: '(message deleted)' } }); @@ -70,7 +66,6 @@ class CreatePost extends React.Component { this.sendMessage = this.sendMessage.bind(this); PostStore.clearDraftUploads(); - PostStore.deleteMessage(this.props.intl.formatMessage(holders.deleteMsg)); const draft = this.getCurrentDraft(); @@ -511,4 +506,4 @@ CreatePost.propTypes = { intl: intlShape.isRequired }; -export default injectIntl(CreatePost); \ No newline at end of file +export default injectIntl(CreatePost); diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index 16f8528b2..d71ac6ec7 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -44,7 +44,6 @@ class PostBody extends React.Component { this.state = { links: linkData.links, - message: linkData.text, post: this.props.post, hasUserProfiles: profiles && Object.keys(profiles).length > 1 }; @@ -106,7 +105,9 @@ class PostBody extends React.Component { if (this.props.post.filenames.length === 0 && this.state.links && this.state.links.length > 0) { this.embed = this.createEmbed(linkData.links[0]); } - this.setState({links: linkData.links, message: linkData.text}); + this.setState({ + links: linkData.links + }); } createEmbed(link) { @@ -310,6 +311,23 @@ class PostBody extends React.Component { ); } + let message; + if (this.props.post.state === Constants.POST_DELETED) { + message = ( + + ); + } else { + message = ( + + ); + } + return (
{comment} @@ -320,11 +338,7 @@ class PostBody extends React.Component { className={postClass} > {loading} - + {message}
Sending Messages

Type here to write a message and press Enter to post it.

Click the Attachment button to upload an image or a file.

", "delete_channel.channel": "channel", "delete_channel.group": "group", @@ -768,6 +767,7 @@ "members_popover.title": "Members", "post_attachment.collapse": "▲ collapse text", "post_attachment.more": "▼ read more", + "post_body.deleted": "(message deleted)", "post_body.plusOne": " plus 1 other file", "post_body.plusMore": " plus {count} other files", "post_body.commentedOn": "Commented on {name}{apostrophe} message: ", @@ -1220,4 +1220,4 @@ "intro_messages.beginning": "Beginning of {name}", "intro_messages.invite": "Invite others to this {type}", "intro_messages.setHeader": "Set a Header" -} \ No newline at end of file +} diff --git a/web/static/i18n/es.json b/web/static/i18n/es.json index 981e1f06f..98cb2db66 100644 --- a/web/static/i18n/es.json +++ b/web/static/i18n/es.json @@ -589,7 +589,6 @@ "create_comment.file": "Subiendo archivo", "create_comment.files": "Subiendo archivos", "create_post.comment": "Comentario", - "create_post.deleteMsg": "(mensaje eliminado)", "create_post.post": "Mensaje", "create_post.tutorialTip": "

Enviar Mensajes

Escribe aquí para redactar un mensaje y presiona Retorno para enviarlo.

Pincha el botón de Adjuntar para subir una imagen o archivo.

", "create_post.write": "Escribe un mensaje...", @@ -809,6 +808,7 @@ "post_attachment.collapse": "▲ colapsar texto", "post_attachment.more": "▼ leer más", "post_body.commentedOn": "Comentó el mensaje de {name}{apostrophe}: ", + "post_body.deleted": "(mensaje eliminado)", "post_body.plusMore": " más {count} otros archivos", "post_body.plusOne": " más 1 archivo", "post_body.retry": "Reintentar", @@ -1220,4 +1220,4 @@ "view_image_popover.download": "Descargar", "view_image_popover.file": "Archivo {count} de {total}", "view_image_popover.publicLink": "Obtener Enlace Público" -} \ No newline at end of file +} -- cgit v1.2.3-1-g7c22 From 70c3715b963cd8f2a710f8909f23696f9de7fcc7 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Wed, 3 Feb 2016 12:12:10 -0500 Subject: Changed how posts are marked ephemeral --- web/react/components/post_info.jsx | 6 +++--- web/react/stores/post_store.jsx | 3 +-- web/react/utils/constants.jsx | 2 +- web/react/utils/utils.jsx | 4 ++++ 4 files changed, 9 insertions(+), 6 deletions(-) (limited to 'web') diff --git a/web/react/components/post_info.jsx b/web/react/components/post_info.jsx index 02150bd9d..b1bc8ca14 100644 --- a/web/react/components/post_info.jsx +++ b/web/react/components/post_info.jsx @@ -30,7 +30,7 @@ export default class PostInfo extends React.Component { var isOwner = UserStore.getCurrentId() === post.user_id; var isAdmin = Utils.isAdmin(UserStore.getCurrentUser().roles); - if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || post.ephemeral) { + if (post.state === Constants.POST_FAILED || post.state === Constants.POST_LOADING || Utils.isPostEphemeral(post)) { return ''; } @@ -171,7 +171,7 @@ export default class PostInfo extends React.Component { EventHelpers.emitRemovePost(this.props.post); } createRemovePostButton(post) { - if (!post.ephemeral) { + if (!Utils.isPostEphemeral(post)) { return null; } @@ -198,7 +198,7 @@ export default class PostInfo extends React.Component { commentCountText = ''; } - if (post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING && !post.ephemeral) { + if (post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING && !Utils.isPostEphemeral(post)) { comments = (
Date: Wed, 3 Feb 2016 15:21:03 -0500 Subject: Added helper methods to send ephemeral messages to specific users --- web/react/dispatcher/event_helpers.jsx | 18 ++++++++++++++++++ web/react/stores/socket_store.jsx | 3 +-- 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'web') diff --git a/web/react/dispatcher/event_helpers.jsx b/web/react/dispatcher/event_helpers.jsx index cb41bd1bb..c1041e438 100644 --- a/web/react/dispatcher/event_helpers.jsx +++ b/web/react/dispatcher/event_helpers.jsx @@ -9,6 +9,7 @@ import Constants from '../utils/constants.jsx'; const ActionTypes = Constants.ActionTypes; import * as AsyncClient from '../utils/async_client.jsx'; import * as Client from '../utils/client.jsx'; +import * as Utils from '../utils/utils.jsx'; export function emitChannelClickEvent(channel) { AsyncClient.getChannels(true); @@ -187,3 +188,20 @@ export function emitRemovePost(post) { post }); } + +export function sendEphemeralPost(message, channelId) { + const timestamp = Utils.getTimestamp(); + const post = { + id: Utils.generateId(), + user_id: '0', + channel_id: channelId || ChannelStore.getCurrentId(), + message, + type: Constants.POST_TYPE_EPHEMERAL, + create_at: timestamp, + update_at: timestamp, + filenames: [], + props: {} + }; + + emitPostRecievedEvent(post); +} diff --git a/web/react/stores/socket_store.jsx b/web/react/stores/socket_store.jsx index 745b94313..33604f44b 100644 --- a/web/react/stores/socket_store.jsx +++ b/web/react/stores/socket_store.jsx @@ -180,7 +180,6 @@ function handleNewPostEvent(msg, translations) { mentions = JSON.parse(msg.props.mentions); } - const channelType = msgProps.channel_type; const channel = ChannelStore.get(msg.channel_id); const user = UserStore.getCurrentUser(); const member = ChannelStore.getMember(msg.channel_id); @@ -192,7 +191,7 @@ function handleNewPostEvent(msg, translations) { if (notifyLevel === 'none') { return; - } else if (notifyLevel === 'mention' && mentions.indexOf(user.id) === -1 && channelType !== Constants.DM_CHANNEL) { + } else if (notifyLevel === 'mention' && mentions.indexOf(user.id) === -1 && channel.type !== Constants.DM_CHANNEL) { return; } -- cgit v1.2.3-1-g7c22