diff options
author | Joram Wilander <jwawilander@gmail.com> | 2017-03-02 17:48:56 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-02 17:48:56 -0500 |
commit | 3a91d4e5e419a43ff19a0736ce697f8d611d36e3 (patch) | |
tree | e57ad85d49f8768a575f27c89d338a4ccaeda521 /webapp/actions | |
parent | 8c5cee9521656bcffb371aad9dae4bea8fc70e29 (diff) | |
download | chat-3a91d4e5e419a43ff19a0736ce697f8d611d36e3.tar.gz chat-3a91d4e5e419a43ff19a0736ce697f8d611d36e3.tar.bz2 chat-3a91d4e5e419a43ff19a0736ce697f8d611d36e3.zip |
PLT-3077 Add group messaging (#5489)
* Implement server changes for group messaging
* Majority of client-side implementation
* Some server updates
* Added new React multiselect component
* Fix style issues
* Add custom renderer for options
* Fix model test
* Update ENTER functionality for multiselect control
* Remove buttons from multiselect UI control
* Updating group messaging UI (#5524)
* Move filter controls up a component level
* Scroll with arrow keys
* Updating mobile layout for multiselect (#5534)
* Fix race condition when backspacing quickly
* Hidden or new GMs show up for regular messages
* Add overriding of number remaining text
* Add UI filtering for team if config setting set
* Add icon to channel switcher and class prop to status icon
* Minor updates per feedback
* Improving group messaging UI (#5563)
* UX changes per feedback
* Update email for group messages
* UI fixes for group messaging (#5587)
* Fix missing localization string
* Add maximum users message when adding members to GM
* Fix input clearing on Android
* Updating group messaging UI (#5603)
* Updating UI for group messaging (#5604)
Diffstat (limited to 'webapp/actions')
-rw-r--r-- | webapp/actions/channel_actions.jsx | 63 | ||||
-rw-r--r-- | webapp/actions/global_actions.jsx | 4 | ||||
-rw-r--r-- | webapp/actions/post_actions.jsx | 10 | ||||
-rw-r--r-- | webapp/actions/user_actions.jsx | 193 | ||||
-rw-r--r-- | webapp/actions/websocket_actions.jsx | 4 |
5 files changed, 200 insertions, 74 deletions
diff --git a/webapp/actions/channel_actions.jsx b/webapp/actions/channel_actions.jsx index 582de54cc..df7bacac6 100644 --- a/webapp/actions/channel_actions.jsx +++ b/webapp/actions/channel_actions.jsx @@ -9,7 +9,7 @@ import ChannelStore from 'stores/channel_store.jsx'; import * as ChannelUtils from 'utils/channel_utils.jsx'; import PreferenceStore from 'stores/preference_store.jsx'; -import {loadProfilesAndTeamMembersForDMSidebar} from 'actions/user_actions.jsx'; +import {loadProfilesForSidebar} from 'actions/user_actions.jsx'; import {trackEvent} from 'actions/diagnostics_actions.jsx'; import Client from 'client/web_client.jsx'; @@ -22,8 +22,12 @@ import {browserHistory} from 'react-router/es6'; export function goToChannel(channel) { if (channel.fake) { + const user = UserStore.getProfileByUsername(channel.display_name); + if (!user) { + return; + } openDirectChannelToUser( - UserStore.getProfileByUsername(channel.display_name), + user.id, () => { browserHistory.push(TeamStore.getCurrentTeamRelativeUrl() + '/channels/' + channel.name); }, @@ -167,18 +171,18 @@ export function makeUserChannelMember(channelId, userId, success, error) { ); } -export function openDirectChannelToUser(user, success, error) { - const channelName = Utils.getDirectChannelName(UserStore.getCurrentId(), user.id); +export function openDirectChannelToUser(userId, success, error) { + const channelName = Utils.getDirectChannelName(UserStore.getCurrentId(), userId); const channel = ChannelStore.getByName(channelName); if (channel) { trackEvent('api', 'api_channels_join_direct'); - PreferenceStore.setPreference(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, user.id, 'true'); - loadProfilesAndTeamMembersForDMSidebar(); + PreferenceStore.setPreference(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, userId, 'true'); + loadProfilesForSidebar(); AsyncClient.savePreference( Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, - user.id, + userId, 'true' ); @@ -190,7 +194,7 @@ export function openDirectChannelToUser(user, success, error) { } Client.createDirectChannel( - user.id, + userId, (data) => { Client.getChannel( data.id, @@ -201,12 +205,12 @@ export function openDirectChannelToUser(user, success, error) { member: data2.member }); - PreferenceStore.setPreference(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, user.id, 'true'); - loadProfilesAndTeamMembersForDMSidebar(); + PreferenceStore.setPreference(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, userId, 'true'); + loadProfilesForSidebar(); AsyncClient.savePreference( Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, - user.id, + userId, 'true' ); @@ -225,6 +229,43 @@ export function openDirectChannelToUser(user, success, error) { ); } +export function openGroupChannelToUsers(userIds, success, error) { + Client.createGroupChannel( + userIds, + (data) => { + Client.getChannelMember( + data.id, + UserStore.getCurrentId(), + (data2) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_CHANNEL, + channel: data, + member: data2 + }); + + PreferenceStore.setPreference(Preferences.CATEGORY_GROUP_CHANNEL_SHOW, data.id, 'true'); + loadProfilesForSidebar(); + + AsyncClient.savePreference( + Preferences.CATEGORY_GROUP_CHANNEL_SHOW, + data.id, + 'true' + ); + + if (success) { + success(data); + } + } + ); + }, + () => { + if (error) { + error(); + } + } + ); +} + export function markFavorite(channelId) { trackEvent('api', 'api_channels_favorited'); AsyncClient.savePreference(Preferences.CATEGORY_FAVORITE_CHANNEL, channelId, 'true'); diff --git a/webapp/actions/global_actions.jsx b/webapp/actions/global_actions.jsx index 37020f500..90805d057 100644 --- a/webapp/actions/global_actions.jsx +++ b/webapp/actions/global_actions.jsx @@ -13,7 +13,7 @@ import PreferenceStore from 'stores/preference_store.jsx'; import SearchStore from 'stores/search_store.jsx'; import {handleNewPost, loadPosts, loadPostsBefore, loadPostsAfter} from 'actions/post_actions.jsx'; -import {loadProfilesAndTeamMembersForDMSidebar} from 'actions/user_actions.jsx'; +import {loadProfilesForSidebar} from 'actions/user_actions.jsx'; import {loadChannelsForCurrentUser} from 'actions/channel_actions.jsx'; import {stopPeriodicStatusUpdates} from 'actions/status_actions.jsx'; import * as WebsocketActions from 'actions/websocket_actions.jsx'; @@ -387,7 +387,7 @@ export function emitPreferenceChangedEvent(preference) { }); if (preference.category === Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW) { - loadProfilesAndTeamMembersForDMSidebar(); + loadProfilesForSidebar(); } } diff --git a/webapp/actions/post_actions.jsx b/webapp/actions/post_actions.jsx index ad05a69db..cbcddfc7c 100644 --- a/webapp/actions/post_actions.jsx +++ b/webapp/actions/post_actions.jsx @@ -8,7 +8,7 @@ import PostStore from 'stores/post_store.jsx'; import UserStore from 'stores/user_store.jsx'; import {loadStatusesForChannel} from 'actions/status_actions.jsx'; -import {loadNewDMIfNeeded} from 'actions/user_actions.jsx'; +import {loadNewDMIfNeeded, loadNewGMIfNeeded} from 'actions/user_actions.jsx'; import {trackEvent} from 'actions/diagnostics_actions.jsx'; import Client from 'client/web_client.jsx'; @@ -24,8 +24,12 @@ export function handleNewPost(post, msg) { websocketMessageProps = msg.data; } - if (msg && msg.data && msg.data.channel_type === Constants.DM_CHANNEL) { - loadNewDMIfNeeded(post.user_id); + if (msg && msg.data) { + if (msg.data.channel_type === Constants.DM_CHANNEL) { + loadNewDMIfNeeded(post.user_id); + } else if (msg.data.channel_type === Constants.GM_CHANNEL) { + loadNewGMIfNeeded(post.channel_id, post.user_id); + } } if (post.root_id && PostStore.getPost(post.channel_id, post.root_id) == null) { diff --git a/webapp/actions/user_actions.jsx b/webapp/actions/user_actions.jsx index cf5241511..0f6ac3e9f 100644 --- a/webapp/actions/user_actions.jsx +++ b/webapp/actions/user_actions.jsx @@ -225,63 +225,150 @@ function populateDMChannelsWithProfiles(userIds) { } } +function populateChannelWithProfiles(channelId, userIds) { + for (let i = 0; i < userIds.length; i++) { + UserStore.saveUserIdInChannel(channelId, userIds[i]); + } + UserStore.emitInChannelChange(); +} + export function loadNewDMIfNeeded(userId) { if (userId === UserStore.getCurrentId()) { return; } - const pref = PreferenceStore.get(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, userId, 'false'); - if (pref === 'false') { + const pref = PreferenceStore.getBool(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, userId, false); + if (pref === false) { PreferenceStore.setPreference(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, userId, 'true'); AsyncClient.savePreference(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, userId, 'true'); - loadProfilesAndTeamMembersForDMSidebar(); + loadProfilesForDM(); } } -export function loadProfilesAndTeamMembersForDMSidebar() { - const dmPrefs = PreferenceStore.getCategory(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW); - const teamId = TeamStore.getCurrentId(); - const profilesToLoad = []; - const membersToLoad = []; +export function loadNewGMIfNeeded(channelId, userId) { + if (userId === UserStore.getCurrentId()) { + return; + } - for (const [key, value] of dmPrefs) { - if (value === 'true') { - if (!UserStore.hasProfile(key)) { - profilesToLoad.push(key); - } - membersToLoad.push(key); + function checkPreference() { + const pref = PreferenceStore.getBool(Preferences.CATEGORY_GROUP_CHANNEL_SHOW, channelId, false); + if (pref === false) { + PreferenceStore.setPreference(Preferences.CATEGORY_GROUP_CHANNEL_SHOW, channelId, 'true'); + AsyncClient.savePreference(Preferences.CATEGORY_GROUP_CHANNEL_SHOW, channelId, 'true'); + loadProfilesForGM(); } } - const channelMembers = ChannelStore.getMyMembers(); + const channel = ChannelStore.get(channelId); + if (channel) { + checkPreference(); + } else { + Client.getChannel( + channelId, + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_CHANNEL, + channel: data.channel, + member: data.member + }); + + checkPreference(); + }, + (err) => { + AsyncClient.dispatchError(err, 'getChannel'); + } + ); + } +} + +export function loadProfilesForSidebar() { + loadProfilesForDM(); + loadProfilesForGM(); +} + +export function loadProfilesForGM() { const channels = ChannelStore.getChannels(); const newPreferences = []; + for (let i = 0; i < channels.length; i++) { const channel = channels[i]; - if (channel.type !== Constants.DM_CHANNEL) { + if (channel.type !== Constants.GM_CHANNEL) { continue; } - const member = channelMembers[channel.id]; - if (!member) { + if (UserStore.getProfileListInChannel(channel.id).length >= Constants.MIN_USERS_IN_GM) { continue; } - const teammateId = channel.name.replace(member.user_id, '').replace('__', ''); + const isVisible = PreferenceStore.getBool(Preferences.CATEGORY_GROUP_CHANNEL_SHOW, channel.id); + + if (!isVisible) { + const member = ChannelStore.getMyMember(channel.id); + if (!member || (member.mention_count === 0 && member.msg_count < member.total_msg_count)) { + continue; + } + + newPreferences.push({ + user_id: UserStore.getCurrentId(), + category: Preferences.CATEGORY_GROUP_CHANNEL_SHOW, + name: channel.id, + value: 'true' + }); + } + + Client.getProfilesInChannel( + channel.id, + 0, + Constants.MAX_USERS_IN_GM, + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_PROFILES, + profiles: data + }); + + populateChannelWithProfiles(channel.id, Object.keys(data)); + } + ); + } + + if (newPreferences.length > 0) { + AsyncClient.savePreferences(newPreferences); + } +} + +export function loadProfilesForDM() { + const channels = ChannelStore.getChannels(); + const newPreferences = []; + const profilesToLoad = []; + const profileIds = []; + + for (let i = 0; i < channels.length; i++) { + const channel = channels[i]; + if (channel.type !== Constants.DM_CHANNEL) { + continue; + } + + const teammateId = channel.name.replace(UserStore.getCurrentId(), '').replace('__', ''); + const isVisible = PreferenceStore.getBool(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, teammateId); + + if (!isVisible) { + const member = ChannelStore.getMyMember(channel.id); + if (!member || member.mention_count === 0) { + continue; + } - if (member.mention_count > 0 && membersToLoad.indexOf(teammateId) === -1) { - membersToLoad.push(teammateId); newPreferences.push({ user_id: UserStore.getCurrentId(), category: Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, name: teammateId, value: 'true' }); + } - if (!UserStore.hasProfile(teammateId)) { - profilesToLoad.push(teammateId); - } + if (!UserStore.hasProfile(teammateId)) { + profilesToLoad.push(teammateId); } + profileIds.push(teammateId); } if (newPreferences.length > 0) { @@ -298,44 +385,14 @@ export function loadProfilesAndTeamMembersForDMSidebar() { }); // Use membersToLoad so we get all the DM profiles even if they were already loaded - populateDMChannelsWithProfiles(membersToLoad); + populateDMChannelsWithProfiles(profileIds); }, (err) => { AsyncClient.dispatchError(err, 'getProfilesByIds'); } ); } else { - populateDMChannelsWithProfiles(membersToLoad); - } - - if (membersToLoad.length > 0) { - Client.getTeamMembersByIds( - teamId, - membersToLoad, - (data) => { - const memberMap = {}; - for (let i = 0; i < data.length; i++) { - memberMap[data[i].user_id] = data[i]; - } - - const nonMembersMap = {}; - for (let i = 0; i < membersToLoad.length; i++) { - if (!memberMap[membersToLoad[i]]) { - nonMembersMap[membersToLoad[i]] = true; - } - } - - AppDispatcher.handleServerAction({ - type: ActionTypes.RECEIVED_MEMBERS_IN_TEAM, - team_id: teamId, - team_members: memberMap, - non_team_members: nonMembersMap - }); - }, - (err) => { - AsyncClient.dispatchError(err, 'getTeamMembersByIds'); - } - ); + populateDMChannelsWithProfiles(profileIds); } } @@ -801,3 +858,27 @@ export function uploadProfileImage(userPicture, success, error) { } ); } + +export function loadProfiles(offset = UserStore.getPagingOffset(), limit = Constants.PROFILE_CHUNK_SIZE, success, error) { + Client.getProfiles( + offset, + limit, + (data) => { + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_PROFILES, + profiles: data + }); + + if (success) { + success(data); + } + }, + (err) => { + AsyncClient.dispatchError(err, 'getProfiles'); + + if (error) { + error(err); + } + } + ); +} diff --git a/webapp/actions/websocket_actions.jsx b/webapp/actions/websocket_actions.jsx index c181a5e3a..b442b9083 100644 --- a/webapp/actions/websocket_actions.jsx +++ b/webapp/actions/websocket_actions.jsx @@ -22,7 +22,7 @@ import {getSiteURL} from 'utils/url.jsx'; import * as GlobalActions from 'actions/global_actions.jsx'; import {handleNewPost, loadPosts, loadProfilesForPosts} from 'actions/post_actions.jsx'; -import {loadProfilesAndTeamMembersForDMSidebar} from 'actions/user_actions.jsx'; +import {loadProfilesForSidebar} from 'actions/user_actions.jsx'; import {loadChannelsForCurrentUser} from 'actions/channel_actions.jsx'; import * as StatusActions from 'actions/status_actions.jsx'; @@ -244,7 +244,7 @@ function handleUpdateTeamEvent(msg) { function handleDirectAddedEvent(msg) { AsyncClient.getChannel(msg.broadcast.channel_id); PreferenceStore.setPreference(Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, msg.data.teammate_id, 'true'); - loadProfilesAndTeamMembersForDMSidebar(); + loadProfilesForSidebar(); } function handleUserAddedEvent(msg) { |