ICU-584 Add support for own DM (#1357)

* add support for own DM

* update per comment
This commit is contained in:
Saturnino Abril 2018-01-18 01:52:28 +08:00 committed by enahum
parent b14a197983
commit 542f0998b1
8 changed files with 182 additions and 59 deletions

View file

@ -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>

View file

@ -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),

View file

@ -24,7 +24,7 @@ function makeMapStateToProps() {
return '';
}
return channel.name.split('__').find((m) => m !== currentUserId);
return channel.name.split('__').find((m) => m !== currentUserId) || currentUserId;
}
);

View file

@ -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)

View file

@ -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>

View file

@ -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) {

View file

@ -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',

View file

@ -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",