Refactor Jump to Conversation (#726)
* Refactor Jump to Conversation Fixed channel loader not showing when switching channels Refactored jump to conversation * Review feedback
This commit is contained in:
parent
c017afb392
commit
b03189defb
7 changed files with 160 additions and 81 deletions
|
|
@ -144,7 +144,7 @@ export default class ChannelDrawer extends PureComponent {
|
|||
this.setState({openDrawer: true});
|
||||
};
|
||||
|
||||
selectChannel = (id) => {
|
||||
selectChannel = (channel) => {
|
||||
const {
|
||||
actions,
|
||||
currentChannel
|
||||
|
|
@ -154,15 +154,17 @@ export default class ChannelDrawer extends PureComponent {
|
|||
handleSelectChannel,
|
||||
markChannelAsRead,
|
||||
setChannelLoading,
|
||||
setChannelDisplayName,
|
||||
viewChannel
|
||||
} = actions;
|
||||
|
||||
markChannelAsRead(id, currentChannel.id);
|
||||
setChannelLoading();
|
||||
viewChannel(id, currentChannel.id);
|
||||
markChannelAsRead(channel.id, currentChannel.id);
|
||||
viewChannel(channel.id, currentChannel.id);
|
||||
setChannelDisplayName(channel.display_name);
|
||||
this.closeChannelDrawer();
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
handleSelectChannel(id);
|
||||
handleSelectChannel(channel.id);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ class FilteredList extends Component {
|
|||
PropTypes.object,
|
||||
PropTypes.array
|
||||
),
|
||||
searchOrder: PropTypes.array.isRequired,
|
||||
pastDirectMessages: PropTypes.array,
|
||||
statuses: PropTypes.object,
|
||||
styles: PropTypes.object.isRequired,
|
||||
term: PropTypes.string,
|
||||
|
|
@ -50,7 +52,8 @@ class FilteredList extends Component {
|
|||
|
||||
static defaultProps = {
|
||||
currentTeam: {},
|
||||
currentChannel: {}
|
||||
currentChannel: {},
|
||||
pastDirectMessages: []
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
|
@ -116,72 +119,92 @@ class FilteredList extends Component {
|
|||
});
|
||||
};
|
||||
|
||||
buildChannelsForSearch = (props, term) => {
|
||||
const data = [];
|
||||
const {groupChannels, otherChannels, styles} = props;
|
||||
const {
|
||||
unreadChannels,
|
||||
favoriteChannels,
|
||||
publicChannels,
|
||||
privateChannels
|
||||
} = props.channels;
|
||||
getSectionBuilders = () => ({
|
||||
unreads: {
|
||||
builder: this.buildUnreadChannelsForSearch,
|
||||
id: 'mobile.channel_list.unreads',
|
||||
defaultMessage: 'UNREADS'
|
||||
},
|
||||
channels: {
|
||||
builder: this.buildChannelsForSearch,
|
||||
id: 'sidebar.channels',
|
||||
defaultMessage: 'CHANNELS'
|
||||
},
|
||||
dms: {
|
||||
builder: this.buildCurrentDMSForSearch,
|
||||
id: 'sidebar.direct',
|
||||
defaultMessage: 'DIRECT MESSAGES'
|
||||
},
|
||||
members: {
|
||||
builder: this.buildMembersForSearch,
|
||||
id: 'mobile.channel_list.members',
|
||||
defaultMessage: 'MEMBERS'
|
||||
},
|
||||
nonmembers: {
|
||||
builder: this.buildOtherMembersForSearch,
|
||||
id: 'mobile.channel_list.not_member',
|
||||
defaultMessage: 'NOT A MEMBER'
|
||||
}
|
||||
});
|
||||
|
||||
buildUnreadChannelsForSearch = (props, term) => {
|
||||
const {unreadChannels} = props.channels;
|
||||
|
||||
return this.filterChannels(unreadChannels, term);
|
||||
}
|
||||
|
||||
buildCurrentDMSForSearch = (props, term) => {
|
||||
const {channels, teammateNameDisplay, profiles, statuses, pastDirectMessages} = props;
|
||||
const {favoriteChannels} = channels;
|
||||
|
||||
const favoriteDms = favoriteChannels.filter((c) => {
|
||||
return c.type === General.DM_CHANNEL;
|
||||
});
|
||||
|
||||
const directChannelUsers = [];
|
||||
const groupChannels = [];
|
||||
|
||||
channels.directAndGroupChannels.forEach((c) => {
|
||||
if (c.type === General.DM_CHANNEL) {
|
||||
directChannelUsers.push(profiles[c.teammate_id]);
|
||||
} else {
|
||||
groupChannels.push(c);
|
||||
}
|
||||
});
|
||||
|
||||
const pastDirectMessageUsers = pastDirectMessages.map((p) => profiles[p]).filter((p) => typeof p !== 'undefined');
|
||||
|
||||
const dms = [...directChannelUsers, ...pastDirectMessageUsers].map((u) => {
|
||||
const displayName = displayUsername(u, teammateNameDisplay);
|
||||
|
||||
const notMemberOf = otherChannels.map((o) => {
|
||||
return {
|
||||
...o,
|
||||
id: u.id,
|
||||
status: statuses[u.id],
|
||||
display_name: displayName,
|
||||
username: u.username,
|
||||
email: u.email,
|
||||
name: displayName,
|
||||
type: General.DM_CHANNEL,
|
||||
fake: true
|
||||
};
|
||||
});
|
||||
|
||||
const favorites = favoriteChannels.filter((c) => {
|
||||
return c.type !== General.DM_CHANNEL && c.type !== General.GM_CHANNEL;
|
||||
return this.filterChannels([...favoriteDms, ...dms, ...groupChannels], term).sort(sortChannelsByDisplayName.bind(null, props.intl.locale));
|
||||
}
|
||||
|
||||
buildMembersForSearch = (props, term) => {
|
||||
const {channels, currentUserId, teammateNameDisplay, profiles, statuses, pastDirectMessages} = props;
|
||||
const {favoriteChannels, unreadChannels} = channels;
|
||||
|
||||
const favoriteAndUnreadDms = [...favoriteChannels, ...unreadChannels].filter((c) => {
|
||||
return c.type === General.DM_CHANNEL;
|
||||
});
|
||||
|
||||
const unreads = this.filterChannels(unreadChannels, term);
|
||||
const channels = this.filterChannels([...favorites, ...publicChannels, ...privateChannels], term).
|
||||
sort(sortChannelsByDisplayName.bind(null, props.intl.locale));
|
||||
const directAndGroupChannelMembers = [...channels.directAndGroupChannels, ...favoriteAndUnreadDms].filter((c) => c.type === General.DM_CHANNEL).map((c) => c.teammate_id);
|
||||
|
||||
const others = this.filterChannels(notMemberOf, term);
|
||||
const groups = this.filterChannels(groupChannels, term);
|
||||
const fakeDms = this.filterChannels(this.buildFakeDms(props), term);
|
||||
const directMessages = [...groups, ...fakeDms].sort(sortChannelsByDisplayName.bind(null, props.intl.locale));
|
||||
const userNotInDirectOrGroupChannels = Object.values(profiles).filter((u) => directAndGroupChannelMembers.indexOf(u.id) === -1 && pastDirectMessages.indexOf(u.id) === -1 && u.id !== currentUserId);
|
||||
|
||||
if (unreads.length) {
|
||||
data.push(
|
||||
this.renderTitle(styles, 'mobile.channel_list.unreads', 'UNREADS', null, false, true),
|
||||
...unreads
|
||||
);
|
||||
}
|
||||
|
||||
if (channels.length) {
|
||||
data.push(
|
||||
this.renderTitle(styles, 'sidebar.channels', 'CHANNELS', null, unreads.length > 0, true),
|
||||
...channels
|
||||
);
|
||||
}
|
||||
|
||||
if (others.length) {
|
||||
data.push(
|
||||
this.renderTitle(styles, 'mobile.channel_list.not_member', 'NOT A MEMBER', null, channels.length > 0, true),
|
||||
...others
|
||||
);
|
||||
}
|
||||
|
||||
if (directMessages.length) {
|
||||
data.push(
|
||||
this.renderTitle(styles, 'sidebar.direct', 'DIRECT MESSAGES', null, others.length > 0, true),
|
||||
...directMessages
|
||||
);
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
buildFakeDms = (props) => {
|
||||
const {currentUserId, teammateNameDisplay, profiles, statuses} = props;
|
||||
const users = Object.values(profiles).filter((p) => p.id !== currentUserId);
|
||||
|
||||
return users.map((u) => {
|
||||
const members = userNotInDirectOrGroupChannels.map((u) => {
|
||||
const displayName = displayUsername(u, teammateNameDisplay);
|
||||
|
||||
return {
|
||||
|
|
@ -193,6 +216,61 @@ class FilteredList extends Component {
|
|||
fake: true
|
||||
};
|
||||
});
|
||||
|
||||
const fakeDms = this.filterChannels([...members], term);
|
||||
|
||||
return [...fakeDms].sort(sortChannelsByDisplayName.bind(null, props.intl.locale));
|
||||
}
|
||||
|
||||
buildChannelsForSearch = (props, term) => {
|
||||
const {
|
||||
favoriteChannels,
|
||||
publicChannels,
|
||||
privateChannels
|
||||
} = props.channels;
|
||||
|
||||
const favorites = favoriteChannels.filter((c) => {
|
||||
return c.type !== General.DM_CHANNEL && c.type !== General.GM_CHANNEL;
|
||||
});
|
||||
|
||||
return this.filterChannels([...favorites, ...publicChannels, ...privateChannels], term).
|
||||
sort(sortChannelsByDisplayName.bind(null, props.intl.locale));
|
||||
}
|
||||
|
||||
buildOtherMembersForSearch = (props, term) => {
|
||||
const {otherChannels} = props;
|
||||
|
||||
const notMemberOf = otherChannels.map((o) => {
|
||||
return {
|
||||
...o,
|
||||
fake: true
|
||||
};
|
||||
});
|
||||
|
||||
return this.filterChannels(notMemberOf, term);
|
||||
}
|
||||
|
||||
buildSectionsForSearch = (props, term) => {
|
||||
const items = [];
|
||||
const {searchOrder, styles} = props;
|
||||
const sectionBuilders = this.getSectionBuilders();
|
||||
|
||||
let previousDataLength = 0;
|
||||
for (const section of searchOrder) {
|
||||
if (sectionBuilders.hasOwnProperty(section)) {
|
||||
const sectionBuilder = sectionBuilders[section];
|
||||
const {builder, defaultMessage, id} = sectionBuilder;
|
||||
const data = builder(props, term);
|
||||
|
||||
if (data.length) {
|
||||
const title = this.renderTitle(styles, id, defaultMessage, null, previousDataLength > 0, true);
|
||||
items.push(title, ...data);
|
||||
previousDataLength = data.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
buildData = (props, term) => {
|
||||
|
|
@ -200,7 +278,7 @@ class FilteredList extends Component {
|
|||
return null;
|
||||
}
|
||||
|
||||
return this.buildChannelsForSearch(props, term);
|
||||
return this.buildSectionsForSearch(props, term);
|
||||
};
|
||||
|
||||
renderSectionAction = (styles, action) => {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
import {createSelector} from 'reselect';
|
||||
|
||||
import {searchChannels} from 'mattermost-redux/actions/channels';
|
||||
import {searchProfiles} from 'mattermost-redux/actions/users';
|
||||
|
|
@ -11,10 +12,19 @@ import {General} from 'mattermost-redux/constants';
|
|||
import {getGroupChannels, getOtherChannels} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getConfig} from 'mattermost-redux/selectors/entities/general';
|
||||
import {getProfilesInCurrentTeam, getUsers, getUserStatuses} from 'mattermost-redux/selectors/entities/users';
|
||||
import {getTeammateNameDisplaySetting} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {getDirectShowPreferences, getTeammateNameDisplaySetting} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import Config from 'assets/config';
|
||||
|
||||
import FilteredList from './filtered_list';
|
||||
|
||||
const DEFAULT_SEARCH_ORDER = ['unreads', 'dms', 'channels', 'members', 'nonmembers'];
|
||||
|
||||
const pastDirectMessages = createSelector(
|
||||
getDirectShowPreferences,
|
||||
(directChannelsFromPreferences) => directChannelsFromPreferences.filter((d) => d.value === 'false').map((d) => d.name)
|
||||
);
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
const {currentUserId} = state.entities.users;
|
||||
|
||||
|
|
@ -25,6 +35,8 @@ function mapStateToProps(state, ownProps) {
|
|||
profiles = getProfilesInCurrentTeam(state);
|
||||
}
|
||||
|
||||
const searchOrder = Config.DrawerSearchOrder ? Config.DrawerSearchOrder : DEFAULT_SEARCH_ORDER;
|
||||
|
||||
return {
|
||||
currentUserId,
|
||||
otherChannels: getOtherChannels(state),
|
||||
|
|
@ -32,6 +44,8 @@ function mapStateToProps(state, ownProps) {
|
|||
profiles,
|
||||
teammateNameDisplay: getTeammateNameDisplaySetting(state),
|
||||
statuses: getUserStatuses(state),
|
||||
searchOrder,
|
||||
pastDirectMessages: pastDirectMessages(state),
|
||||
...ownProps
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class ChannelsList extends Component {
|
|||
if (channel.fake) {
|
||||
this.props.onJoinChannel(channel);
|
||||
} else {
|
||||
this.props.onSelectChannel(channel.id);
|
||||
this.props.onSelectChannel(channel);
|
||||
}
|
||||
|
||||
this.refs.search_bar.cancel();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {General} from 'mattermost-redux/constants';
|
||||
|
|
@ -9,8 +8,6 @@ import {getCurrentUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/
|
|||
import {showCreateOption} from 'mattermost-redux/utils/channel_utils';
|
||||
import {isAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils';
|
||||
|
||||
import {setChannelDisplayName} from 'app/actions/views/channel';
|
||||
|
||||
import List from './list';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
|
|
@ -23,12 +20,4 @@ function mapStateToProps(state, ownProps) {
|
|||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
setChannelDisplayName
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(List);
|
||||
export default connect(mapStateToProps, null)(List);
|
||||
|
|
|
|||
|
|
@ -24,9 +24,6 @@ import UnreadIndicator from 'app/components/channel_drawer/channels_list/unread_
|
|||
|
||||
class List extends Component {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
setChannelDisplayName: PropTypes.func.isRequired
|
||||
}).isRequired,
|
||||
canCreatePrivateChannels: PropTypes.bool.isRequired,
|
||||
channels: PropTypes.object.isRequired,
|
||||
channelMembers: PropTypes.object,
|
||||
|
|
@ -95,7 +92,6 @@ class List extends Component {
|
|||
};
|
||||
|
||||
onSelectChannel = (channel) => {
|
||||
this.props.actions.setChannelDisplayName(channel.display_name);
|
||||
this.props.onSelectChannel(channel);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ function makeMapStateToProps() {
|
|||
const posts = getPostsInChannel(state, channelId) || [];
|
||||
|
||||
return {
|
||||
channelIsLoading: (getPosts.status === RequestStatus.STARTED),
|
||||
channelIsLoading: getPosts.status === RequestStatus.STARTED || state.views.channel.loading,
|
||||
channelIsRefreshing: refreshing,
|
||||
currentChannelId: getCurrentChannelId(state),
|
||||
posts,
|
||||
|
|
|
|||
Loading…
Reference in a new issue