ICU-584 Add support for own DM (#1357)
* add support for own DM * update per comment
This commit is contained in:
parent
b14a197983
commit
542f0998b1
8 changed files with 182 additions and 59 deletions
|
|
@ -25,6 +25,7 @@ export default class ChannelItem extends PureComponent {
|
|||
currentChannelId: PropTypes.string.isRequired,
|
||||
displayName: PropTypes.string.isRequired,
|
||||
fake: PropTypes.bool,
|
||||
isMyUser: PropTypes.bool,
|
||||
isUnread: PropTypes.bool,
|
||||
mentions: PropTypes.number.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
|
|
@ -74,6 +75,7 @@ export default class ChannelItem extends PureComponent {
|
|||
channelId,
|
||||
currentChannelId,
|
||||
displayName,
|
||||
isMyUser,
|
||||
isUnread,
|
||||
mentions,
|
||||
status,
|
||||
|
|
@ -81,6 +83,16 @@ export default class ChannelItem extends PureComponent {
|
|||
type
|
||||
} = this.props;
|
||||
|
||||
const {intl} = this.context;
|
||||
|
||||
let channelDisplayName = displayName;
|
||||
if (isMyUser) {
|
||||
channelDisplayName = intl.formatMessage({
|
||||
id: 'channel_header.directchannel.you',
|
||||
defaultMessage: '{displayName} (you)'
|
||||
}, {displayname: displayName});
|
||||
}
|
||||
|
||||
const style = getStyleSheet(theme);
|
||||
const isActive = channelId === currentChannelId;
|
||||
|
||||
|
|
@ -142,7 +154,7 @@ export default class ChannelItem extends PureComponent {
|
|||
ellipsizeMode='tail'
|
||||
numberOfLines={1}
|
||||
>
|
||||
{displayName}
|
||||
{channelDisplayName}
|
||||
</Text>
|
||||
{badge}
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {General} from 'mattermost-redux/constants';
|
||||
import {getCurrentChannelId, makeGetChannel, getMyChannelMember} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
import ChannelItem from './channel_item';
|
||||
|
||||
|
|
@ -18,10 +20,17 @@ function makeMapStateToProps() {
|
|||
member = getMyChannelMember(state, ownProps.channelId);
|
||||
}
|
||||
|
||||
const currentUserId = getCurrentUserId(state);
|
||||
let isMyUser = false;
|
||||
if (channel.type === General.DM_CHANNEL && channel.teammate_id) {
|
||||
isMyUser = channel.teammate_id === currentUserId;
|
||||
}
|
||||
|
||||
return {
|
||||
currentChannelId: getCurrentChannelId(state),
|
||||
displayName: channel.display_name,
|
||||
fake: channel.fake,
|
||||
isMyUser,
|
||||
mentions: member ? member.mention_count : 0,
|
||||
status: channel.status,
|
||||
theme: getTheme(state),
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ function makeMapStateToProps() {
|
|||
return '';
|
||||
}
|
||||
|
||||
return channel.name.split('__').find((m) => m !== currentUserId);
|
||||
return channel.name.split('__').find((m) => m !== currentUserId) || currentUserId;
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@
|
|||
import {connect} from 'react-redux';
|
||||
|
||||
import {getTeammateNameDisplaySetting, getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {getUser} from 'mattermost-redux/selectors/entities/users';
|
||||
import {getCurrentUserId, getUser} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
import UserListRow from './user_list_row';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
isMyUser: getCurrentUserId(state) === ownProps.id,
|
||||
theme: getTheme(state),
|
||||
user: getUser(state, ownProps.id),
|
||||
teammateNameDisplay: getTeammateNameDisplaySetting(state)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {intlShape} from 'react-intl';
|
||||
import {
|
||||
Text,
|
||||
View
|
||||
|
|
@ -17,36 +18,63 @@ import {displayUsername} from 'mattermost-redux/utils/user_utils';
|
|||
export default class UserListRow extends React.PureComponent {
|
||||
static propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
isMyUser: PropTypes.bool.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
user: PropTypes.object.isRequired,
|
||||
teammateNameDisplay: PropTypes.string.isRequired,
|
||||
...CustomListRow.propTypes
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape
|
||||
};
|
||||
|
||||
onPress = () => {
|
||||
this.props.onPress(this.props.id);
|
||||
if (this.props.onPress) {
|
||||
this.props.onPress(this.props.id);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const style = getStyleFromTheme(this.props.theme);
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {
|
||||
enabled,
|
||||
isMyUser,
|
||||
selectable,
|
||||
selected,
|
||||
teammateNameDisplay,
|
||||
theme,
|
||||
user
|
||||
} = this.props;
|
||||
|
||||
const {id, username} = user;
|
||||
const style = getStyleFromTheme(theme);
|
||||
|
||||
let usernameDisplay = `(@${username})`;
|
||||
if (isMyUser) {
|
||||
usernameDisplay = formatMessage({
|
||||
id: 'mobile.more_dms.you',
|
||||
defaultMessage: '(@{username} - you)'
|
||||
}, {username});
|
||||
}
|
||||
|
||||
return (
|
||||
<CustomListRow
|
||||
id={this.props.id}
|
||||
theme={this.props.theme}
|
||||
onPress={this.props.onPress ? this.onPress : null}
|
||||
enabled={this.props.enabled}
|
||||
selectable={this.props.selectable}
|
||||
selected={this.props.selected}
|
||||
id={id}
|
||||
theme={theme}
|
||||
onPress={this.onPress}
|
||||
enabled={enabled}
|
||||
selectable={selectable}
|
||||
selected={selected}
|
||||
>
|
||||
<ProfilePicture
|
||||
userId={this.props.user.id}
|
||||
userId={id}
|
||||
size={32}
|
||||
/>
|
||||
<View style={style.textContainer}>
|
||||
<View>
|
||||
<Text style={style.displayName}>
|
||||
{displayUsername(this.props.user, this.props.teammateNameDisplay)}
|
||||
{displayUsername(user, teammateNameDisplay)}
|
||||
</Text>
|
||||
</View>
|
||||
<View>
|
||||
|
|
@ -55,7 +83,7 @@ export default class UserListRow extends React.PureComponent {
|
|||
ellipsizeMode='tail'
|
||||
numberOfLines={1}
|
||||
>
|
||||
{`(@${this.props.user.username})`}
|
||||
{usernameDisplay}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -17,10 +17,8 @@ import {getCurrentUserId, getProfilesInCurrentTeam, getUsers} from 'mattermost-r
|
|||
|
||||
import MoreDirectMessages from './more_dms';
|
||||
|
||||
function sortAndRemoveCurrentUser(profiles, currentUserId) {
|
||||
const users = {...profiles};
|
||||
Reflect.deleteProperty(users, currentUserId);
|
||||
return Object.values(users).sort((a, b) => {
|
||||
function sortCurrentUsers(profiles) {
|
||||
return Object.values(profiles).sort((a, b) => {
|
||||
const nameA = a.username;
|
||||
const nameB = b.username;
|
||||
|
||||
|
|
@ -30,14 +28,12 @@ function sortAndRemoveCurrentUser(profiles, currentUserId) {
|
|||
|
||||
const getUsersInCurrentTeamForMoreDirectMessages = createSelector(
|
||||
getProfilesInCurrentTeam,
|
||||
getCurrentUserId,
|
||||
sortAndRemoveCurrentUser
|
||||
sortCurrentUsers
|
||||
);
|
||||
|
||||
const getUsersForMoreDirectMessages = createSelector(
|
||||
getUsers,
|
||||
getCurrentUserId,
|
||||
sortAndRemoveCurrentUser
|
||||
sortCurrentUsers
|
||||
);
|
||||
|
||||
function mapStateToProps(state) {
|
||||
|
|
|
|||
|
|
@ -91,12 +91,16 @@ class MoreDirectMessages extends PureComponent {
|
|||
const {getRequest} = this.props;
|
||||
if (getRequest.status === RequestStatus.STARTED &&
|
||||
nextProps.getRequest.status === RequestStatus.SUCCESS) {
|
||||
const {page} = this.state;
|
||||
const profiles = nextProps.profiles.slice(0, (page + 1) * General.PROFILE_CHUNK_SIZE);
|
||||
const profiles = this.sliceProfiles(nextProps.profiles);
|
||||
this.setState({profiles, showNoResults: true});
|
||||
} else if (this.state.searching &&
|
||||
nextProps.searchRequest.status === RequestStatus.SUCCESS) {
|
||||
const results = filterProfilesMatchingTerm(nextProps.profiles, this.state.term);
|
||||
let results = filterProfilesMatchingTerm(nextProps.profiles, this.state.term);
|
||||
|
||||
if (this.state.selectedCount > 0) {
|
||||
results = this.removeCurrentUserFromProfiles(results);
|
||||
}
|
||||
|
||||
this.setState({profiles: results, showNoResults: true});
|
||||
}
|
||||
}
|
||||
|
|
@ -112,6 +116,16 @@ class MoreDirectMessages extends PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
removeCurrentUserFromProfiles(profiles = []) {
|
||||
return profiles.filter((profile) => {
|
||||
return profile.id !== this.props.currentUserId;
|
||||
});
|
||||
}
|
||||
|
||||
sliceProfiles(profiles = []) {
|
||||
return profiles.slice(0, (this.state.page + 1) * General.PROFILE_CHUNK_SIZE);
|
||||
}
|
||||
|
||||
isStartEnabled = (state) => {
|
||||
if (state.loadingChannel) {
|
||||
return false;
|
||||
|
|
@ -163,11 +177,20 @@ class MoreDirectMessages extends PureComponent {
|
|||
};
|
||||
|
||||
cancelSearch = () => {
|
||||
const {profiles} = this.props;
|
||||
|
||||
let newProfiles;
|
||||
if (this.state.selectedCount > 0) {
|
||||
newProfiles = this.removeCurrentUserFromProfiles(profiles);
|
||||
} else {
|
||||
newProfiles = this.sliceProfiles(profiles);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
searching: false,
|
||||
term: '',
|
||||
page: 0,
|
||||
profiles: this.props.profiles
|
||||
profiles: newProfiles
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -208,42 +231,81 @@ class MoreDirectMessages extends PureComponent {
|
|||
};
|
||||
|
||||
handleSelectUser = (id) => {
|
||||
this.setState((prevState) => {
|
||||
const wasSelected = prevState.selectedIds[id];
|
||||
const {currentUserId} = this.props;
|
||||
|
||||
// Prevent selecting too many users
|
||||
if (!wasSelected && Object.keys(prevState.selectedIds).length >= General.MAX_USERS_IN_GM - 1) {
|
||||
return {};
|
||||
}
|
||||
if (id === currentUserId) {
|
||||
const selectedId = {};
|
||||
selectedId[currentUserId] = true;
|
||||
|
||||
const selectedIds = {...prevState.selectedIds};
|
||||
this.startConversation(selectedId);
|
||||
} else {
|
||||
this.setState((prevState) => {
|
||||
const {
|
||||
profiles,
|
||||
selectedCount,
|
||||
selectedIds
|
||||
} = prevState;
|
||||
|
||||
if (wasSelected) {
|
||||
Reflect.deleteProperty(selectedIds, id);
|
||||
} else {
|
||||
selectedIds[id] = true;
|
||||
}
|
||||
const wasSelected = selectedIds[id];
|
||||
|
||||
return {
|
||||
selectedIds,
|
||||
selectedCount: Object.keys(selectedIds).length
|
||||
};
|
||||
});
|
||||
// Prevent selecting too many users
|
||||
if (!wasSelected && Object.keys(selectedIds).length >= General.MAX_USERS_IN_GM - 1) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const newSelectedIds = Object.assign({}, selectedIds);
|
||||
|
||||
let newProfiles = profiles;
|
||||
if (wasSelected) {
|
||||
Reflect.deleteProperty(newSelectedIds, id);
|
||||
if (selectedCount === 1) {
|
||||
newProfiles = this.sliceProfiles(this.props.profiles);
|
||||
}
|
||||
} else {
|
||||
newSelectedIds[id] = true;
|
||||
newProfiles = this.removeCurrentUserFromProfiles(profiles);
|
||||
}
|
||||
|
||||
return {
|
||||
profiles: newProfiles,
|
||||
selectedIds: newSelectedIds,
|
||||
selectedCount: Object.keys(newSelectedIds).length
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleRemoveUser = (id) => {
|
||||
this.setState((prevState) => {
|
||||
const selectedIds = {...prevState.selectedIds};
|
||||
Reflect.deleteProperty(selectedIds, id);
|
||||
const {
|
||||
profiles,
|
||||
selectedCount,
|
||||
selectedIds
|
||||
} = prevState;
|
||||
|
||||
const newSelectedIds = Object.assign({}, selectedIds);
|
||||
|
||||
Reflect.deleteProperty(newSelectedIds, id);
|
||||
|
||||
let newProfiles = profiles;
|
||||
if (selectedCount === 1) {
|
||||
newProfiles = this.sliceProfiles(this.props.profiles);
|
||||
}
|
||||
|
||||
return {
|
||||
selectedIds,
|
||||
selectedCount: Object.keys(selectedIds).length
|
||||
profiles: newProfiles,
|
||||
selectedIds: newSelectedIds,
|
||||
selectedCount: Object.keys(newSelectedIds).length
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
startConversation = async () => {
|
||||
startConversation = async (selectedId) => {
|
||||
const {
|
||||
currentDisplayName,
|
||||
actions
|
||||
} = this.props;
|
||||
|
||||
if (this.state.loadingChannel) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -253,9 +315,9 @@ class MoreDirectMessages extends PureComponent {
|
|||
});
|
||||
|
||||
// Save the current channel display name in case it fails
|
||||
const currentChannelDisplayName = this.props.currentDisplayName;
|
||||
const currentChannelDisplayName = currentDisplayName;
|
||||
|
||||
const selectedIds = Object.keys(this.state.selectedIds);
|
||||
const selectedIds = selectedId ? Object.keys(selectedId) : Object.keys(this.state.selectedIds);
|
||||
let success;
|
||||
if (selectedIds.length === 0) {
|
||||
success = false;
|
||||
|
|
@ -275,19 +337,27 @@ class MoreDirectMessages extends PureComponent {
|
|||
loadingChannel: false
|
||||
});
|
||||
|
||||
this.props.actions.setChannelDisplayName(currentChannelDisplayName);
|
||||
actions.setChannelDisplayName(currentChannelDisplayName);
|
||||
}
|
||||
};
|
||||
|
||||
makeGroupChannel = async (ids) => {
|
||||
const result = await this.props.actions.makeGroupChannel(ids);
|
||||
const {
|
||||
actions,
|
||||
allProfiles,
|
||||
currentUserId,
|
||||
intl,
|
||||
teammateNameDisplay
|
||||
} = this.props;
|
||||
|
||||
const displayName = getGroupDisplayNameFromUserIds(ids, this.props.allProfiles, this.props.currentUserId, this.props.teammateNameDisplay);
|
||||
this.props.actions.setChannelDisplayName(displayName);
|
||||
const result = await actions.makeGroupChannel(ids);
|
||||
|
||||
const displayName = getGroupDisplayNameFromUserIds(ids, allProfiles, currentUserId, teammateNameDisplay);
|
||||
actions.setChannelDisplayName(displayName);
|
||||
|
||||
if (result.error) {
|
||||
alertErrorWithFallback(
|
||||
this.props.intl,
|
||||
intl,
|
||||
result.error,
|
||||
{
|
||||
id: 'mobile.open_gm.error',
|
||||
|
|
@ -300,16 +370,22 @@ class MoreDirectMessages extends PureComponent {
|
|||
};
|
||||
|
||||
makeDirectChannel = async (id) => {
|
||||
const {
|
||||
actions,
|
||||
intl,
|
||||
teammateNameDisplay
|
||||
} = this.props;
|
||||
|
||||
const user = this.state.profiles[id];
|
||||
|
||||
const displayName = displayUsername(user, this.props.teammateNameDisplay);
|
||||
this.props.actions.setChannelDisplayName(displayName);
|
||||
const displayName = displayUsername(user, teammateNameDisplay);
|
||||
actions.setChannelDisplayName(displayName);
|
||||
|
||||
const result = await this.props.actions.makeDirectChannel(id);
|
||||
const result = await actions.makeDirectChannel(id);
|
||||
|
||||
if (result.error) {
|
||||
alertErrorWithFallback(
|
||||
this.props.intl,
|
||||
intl,
|
||||
result.error,
|
||||
{
|
||||
id: 'mobile.open_dm.error',
|
||||
|
|
|
|||
|
|
@ -2036,6 +2036,7 @@
|
|||
"mobile.markdown.link.copy_url": "Copy URL",
|
||||
"mobile.mention.copy_mention": "Copy Mention",
|
||||
"mobile.more_dms.start": "Start",
|
||||
"mobile.more_dms.you": "(@{username} - you)",
|
||||
"mobile.more_dms.title": "New Conversation",
|
||||
"mobile.notice_mobile_link": "mobile apps",
|
||||
"mobile.notice_platform_link": "platform",
|
||||
|
|
|
|||
Loading…
Reference in a new issue