PLT-6208 Follow policies set in System Console (#456)

This commit is contained in:
enahum 2017-04-05 22:33:03 -03:00 committed by GitHub
parent 70449a4768
commit 007c8bcf35
16 changed files with 235 additions and 145 deletions

View file

@ -9,7 +9,7 @@ import com.learnium.RNDeviceInfo.RNDeviceInfo;
import com.psykar.cookiemanager.CookieManagerPackage;
import com.dieam.reactnativepushnotification.ReactNativePushNotificationPackage;
import com.oblador.vectoricons.VectorIconsPackage;
import com.horcrux.svg.RNSvgPackage;
import com.horcrux.svg.SvgPackage;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
@ -41,7 +41,7 @@ public class MainApplication extends Application implements ReactApplication {
new CookieManagerPackage(),
new ReactNativePushNotificationPackage(),
new VectorIconsPackage(),
new RNSvgPackage(),
new SvgPackage(),
new LinearGradientPackage(),
new PickerPackage(),
new OrientationPackage()

View file

@ -281,7 +281,6 @@ export function showOptionsModal(options) {
export function showMoreChannelsModal() {
return async (dispatch, getState) => {
closeDrawers()(dispatch, getState);
dispatch({
type: NavigationTypes.NAVIGATION_MODAL,
route: Routes.MoreChannels
@ -291,7 +290,6 @@ export function showMoreChannelsModal() {
export function showDirectMessagesModal() {
return async (dispatch, getState) => {
closeDrawers()(dispatch, getState);
dispatch({
type: NavigationTypes.NAVIGATION_MODAL,
route: Routes.MoreDirectMessages

View file

@ -37,6 +37,7 @@ class ChannelDrawerList extends Component {
showDirectMessagesModal: PropTypes.func.isRequired,
showMoreChannelsModal: PropTypes.func.isRequired
}).isRequired,
canCreatePrivateChannels: PropTypes.bool.isRequired,
channels: PropTypes.object.isRequired,
channelMembers: PropTypes.object,
currentTeam: PropTypes.object.isRequired,
@ -186,7 +187,7 @@ class ChannelDrawerList extends Component {
return data;
}
const {theme} = this.props;
const {canCreatePrivateChannels, theme} = this.props;
const styles = getStyleSheet(theme);
const {
@ -208,8 +209,12 @@ class ChannelDrawerList extends Component {
...publicChannels
);
let createPrivateChannel;
if (canCreatePrivateChannels) {
createPrivateChannel = this.createPrivateChannel;
}
data.push(
this.renderTitle(styles, 'sidebar.pg', 'PRIVATE CHANNELS', this.createPrivateChannel, privateChannels.length > 0),
this.renderTitle(styles, 'sidebar.pg', 'PRIVATE CHANNELS', createPrivateChannel, privateChannels.length > 0),
...privateChannels
);

View file

@ -20,10 +20,19 @@ import {
unmarkFavorite
} from 'app/actions/views/channel';
import {Constants} from 'mattermost-redux/constants';
import {getCurrentUserRoles} from 'mattermost-redux/selectors/entities/users';
import {showCreateOption} from 'mattermost-redux/utils/channel_utils';
import {isAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils';
import ChannelDrawerList from './channel_drawer_list';
function mapStateToProps(state, ownProps) {
const {config, license} = state.entities.general;
const roles = getCurrentUserRoles(state);
return {
canCreatePrivateChannels: showCreateOption(config, license, Constants.PRIVATE_CHANNEL, isAdmin(roles), isSystemAdmin(roles)),
...ownProps
};
}

View file

@ -23,7 +23,8 @@ export default class CustomList extends PureComponent {
selectable: PropTypes.bool,
onRowSelect: PropTypes.func,
renderRow: PropTypes.func.isRequired,
createSections: PropTypes.func
createSections: PropTypes.func,
showNoResults: PropTypes.bool
};
static defaultProps = {
@ -37,7 +38,8 @@ export default class CustomList extends PureComponent {
loadingText: null,
onRowSelect: () => true,
createSections: () => true,
showSections: true
showSections: true,
showNoResults: true
};
constructor(props) {
@ -48,7 +50,6 @@ export default class CustomList extends PureComponent {
componentWillReceiveProps(nextProps) {
const {data, showSections, searching} = nextProps;
this.showNoResults = true;
if (searching || searching !== this.props.searching) {
this.setState(this.buildDataSource(nextProps));
@ -161,7 +162,7 @@ export default class CustomList extends PureComponent {
noResults = this.props.data.length === 0;
}
if (this.showNoResults && !this.props.loading && noResults) {
if (this.props.showNoResults && !this.props.loading && noResults) {
return (
<View style={style.noResultContainer}>
<FormattedText

View file

@ -1,4 +1,4 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React, {PropTypes, PureComponent} from 'react';
@ -13,9 +13,6 @@ import {
View
} from 'react-native';
import {injectIntl, intlShape} from 'react-intl';
import {Constants} from 'mattermost-redux/constants';
import {isSystemMessage} from 'mattermost-redux/utils/post_utils';
import {isAdmin} from 'mattermost-redux/utils/user_utils';
import FormattedText from 'app/components/formatted_text';
import FormattedTime from 'app/components/formatted_time';
@ -29,6 +26,11 @@ import ReplyIcon from 'app/components/reply_icon';
import webhookIcon from 'assets/images/icons/webhook.jpg';
import {Constants} from 'mattermost-redux/constants';
import DelayedAction from 'mattermost-redux/utils/delayed_action';
import {canDeletePost, canEditPost, isSystemMessage} from 'mattermost-redux/utils/post_utils';
import {isAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils';
const BOT_NAME = 'BOT';
class Post extends PureComponent {
@ -48,6 +50,7 @@ class Post extends PureComponent {
isLastReply: PropTypes.bool,
commentedOnDisplayName: PropTypes.string,
commentedOnPost: PropTypes.object,
license: PropTypes.object.isRequired,
roles: PropTypes.string,
theme: PropTypes.object.isRequired,
onPress: PropTypes.func,
@ -60,6 +63,33 @@ class Post extends PureComponent {
}).isRequired
};
constructor(props) {
super(props);
const {config, license, currentUserId, roles, post} = props;
this.editDisableAction = new DelayedAction(this.handleEditDisable);
this.state = {
canEdit: canEditPost(config, license, currentUserId, post, this.editDisableAction),
canDelete: canDeletePost(config, license, currentUserId, post, isAdmin(roles), isSystemAdmin(roles))
};
}
componentWillReceiveProps(nextProps) {
const {config, license, currentUserId, roles, post} = nextProps;
this.setState({
canEdit: canEditPost(config, license, currentUserId, post, this.editDisableAction),
canDelete: canDeletePost(config, license, currentUserId, post, isAdmin(roles), isSystemAdmin(roles))
});
}
componentWillUnmount() {
this.editDisableAction.cancel();
}
handleEditDisable = () => {
this.setState({canEdit: false});
};
handlePostDelete = () => {
const {formatMessage} = this.props.intl;
const {currentTeamId, post, actions} = this.props;
@ -74,6 +104,7 @@ class Post extends PureComponent {
text: formatMessage({id: 'post_info.del', defaultMessage: 'Delete'}),
style: 'destructive',
onPress: () => {
this.editDisableAction.cancel();
actions.deletePost(currentTeamId, post);
}
}]
@ -183,7 +214,7 @@ class Post extends PureComponent {
renderMessage = (style, messageStyle, replyBar = false) => {
const {formatMessage} = this.props.intl;
const {currentUserId, isFlagged, post, roles, theme} = this.props;
const {isFlagged, post, theme} = this.props;
const {flagPost, unflagPost} = this.props.actions;
const actions = [];
@ -200,11 +231,11 @@ class Post extends PureComponent {
});
}
if (post.user_id === currentUserId) {
if (this.state.canEdit) {
actions.push({text: formatMessage({id: 'post_info.edit', defaultMessage: 'Edit'}), onPress: () => this.handlePostEdit()});
}
if (post.user_id === currentUserId || isAdmin(roles)) {
if (this.state.canDelete && post.state !== Constants.POST_DELETED) {
actions.push({text: formatMessage({id: 'post_info.del', defaultMessage: 'Delete'}), onPress: () => this.handlePostDelete()});
}

View file

@ -22,16 +22,18 @@ function makeMapStateToProps() {
const commentedOnUser = ownProps.commentedOnPost ? getUser(state, ownProps.commentedOnPost.user_id) : null;
const user = getUser(state, ownProps.post.user_id);
const myPreferences = getMyPreferences(state);
const {config, license} = state.entities.general;
return {
...ownProps,
config: state.entities.general.config,
config,
commentCount: getCommentCountForPost(state, ownProps),
commentedOnDisplayName: displayUsername(commentedOnUser, myPreferences),
currentTeamId: getCurrentTeamId(state),
currentUserId: getCurrentUserId(state),
displayName: displayUsername(user, myPreferences),
isFlagged: isPostFlagged(ownProps.post.id, myPreferences),
license,
roles: getCurrentUserRoles(state),
theme: getTheme(state),
user

View file

@ -20,6 +20,7 @@ import ChannelInfoRow from './channel_info_row';
class ChannelInfo extends PureComponent {
static propTypes = {
intl: intlShape.isRequired,
canDeleteChannel: PropTypes.bool.isRequired,
currentTeamId: PropTypes.string.isRequired,
currentChannel: PropTypes.object.isRequired,
currentChannelCreatorName: PropTypes.string,
@ -152,6 +153,7 @@ class ChannelInfo extends PureComponent {
render() {
const {
canDeleteChannel,
currentChannel,
currentChannelCreatorName,
currentChannelMemberCount,
@ -245,7 +247,7 @@ class ChannelInfo extends PureComponent {
theme={theme}
/>
</View>
{this.renderLeaveOrDeleteChannelRow() &&
{this.renderLeaveOrDeleteChannelRow() && canDeleteChannel &&
<View style={style.footer}>
<ChannelInfoRow
action={() => this.handleDeleteOrLeave('delete')}

View file

@ -22,12 +22,14 @@ import {
getChannelsByCategory,
canManageChannelMembers
} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentUserId, getUser, getStatusForUserId} from 'mattermost-redux/selectors/entities/users';
import {getUserIdFromChannelName} from 'mattermost-redux/utils/channel_utils';
import {getCurrentUserId, getUser, getStatusForUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/entities/users';
import {getUserIdFromChannelName, showDeleteOption} from 'mattermost-redux/utils/channel_utils';
import {isAdmin, isChannelAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils';
import ChannelInfo from './channel_info';
function mapStateToProps(state, ownProps) {
const {config, license} = state.entities.general;
const currentChannel = getCurrentChannel(state);
const currentChannelCreator = getUser(state, currentChannel.creator_id);
const currentChannelCreatorName = currentChannelCreator && currentChannelCreator.username;
@ -37,6 +39,7 @@ function mapStateToProps(state, ownProps) {
const isCurrent = currentChannel.id === state.entities.channels.currentChannelId;
const isFavorite = favoriteChannels.indexOf(currentChannel.id) > -1;
const leaveChannelRequest = state.requests.channels.leaveChannel;
const roles = getCurrentUserRoles(state);
let status;
if (currentChannel.type === Constants.DM_CHANNEL) {
@ -46,6 +49,7 @@ function mapStateToProps(state, ownProps) {
return {
...ownProps,
canDeleteChannel: showDeleteOption(config, license, currentChannel, isAdmin(roles), isSystemAdmin(roles), isChannelAdmin(roles)),
currentTeamId: state.entities.teams.currentTeamId,
currentChannel,
currentChannelCreatorName,

View file

@ -9,10 +9,18 @@ import {
} from 'react-native';
import FormattedText from 'app/components/formatted_text';
import {getTheme} from 'app/selectors/preferences';
import {Constants} from 'mattermost-redux/constants';
import {getCurrentUserRoles} from 'mattermost-redux/selectors/entities/users';
import {showCreateOption} from 'mattermost-redux/utils/channel_utils';
import {isAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils';
function CreateButton(props) {
if (!props.canCreateChannels) {
return null;
}
return (
<View style={{flexDirection: 'column', justifyContent: 'center', alignItems: 'center', flex: 1}}>
<TouchableOpacity
@ -30,6 +38,7 @@ function CreateButton(props) {
}
CreateButton.propTypes = {
canCreateChannels: PropTypes.bool.isRequired,
emitter: PropTypes.func.isRequired,
theme: PropTypes.object
};
@ -39,7 +48,11 @@ CreateButton.defaultProps = {
};
function mapStateToProps(state) {
const {config, license} = state.entities.general;
const roles = getCurrentUserRoles(state);
return {
canCreateChannels: showCreateOption(config, license, Constants.PRIVATE_CHANNEL, isAdmin(roles), isSystemAdmin(roles)),
theme: getTheme(state)
};
}

View file

@ -5,7 +5,7 @@ import {bindActionCreators} from 'redux';
import navigationSceneConnect from '../navigationSceneConnect';
import {goBack, goToCreateChannel} from 'app/actions/navigation';
import {closeDrawers, goBack, goToCreateChannel} from 'app/actions/navigation';
import {getTheme} from 'app/selectors/preferences';
import {getMoreChannels as getMoreChannelsSelector} from 'mattermost-redux/selectors/entities/channels';
import {handleSelectChannel} from 'app/actions/views/channel';
@ -17,11 +17,12 @@ function mapStateToProps(state) {
const {currentUserId} = state.entities.users;
const {currentTeamId} = state.entities.teams;
const {getMoreChannels: requestStatus} = state.requests.channels;
const channels = getMoreChannelsSelector(state);
return {
currentUserId,
currentTeamId,
channels: getMoreChannelsSelector(state),
channels,
theme: getTheme(state),
requestStatus
};
@ -30,6 +31,7 @@ function mapStateToProps(state) {
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
closeDrawers,
goBack,
handleSelectChannel,
goToCreateChannel,

View file

@ -34,6 +34,7 @@ class MoreChannels extends PureComponent {
subscribeToHeaderEvent: React.PropTypes.func.isRequired,
unsubscribeFromHeaderEvent: React.PropTypes.func.isRequired,
actions: PropTypes.shape({
closeDrawers: PropTypes.func.isRequired,
goBack: PropTypes.func.isRequired,
handleSelectChannel: PropTypes.func.isRequired,
goToCreateChannel: PropTypes.func.isRequired,
@ -69,11 +70,12 @@ class MoreChannels extends PureComponent {
this.searchTimeoutId = 0;
this.state = {
channels: [],
channels: props.channels,
page: 0,
adding: false,
next: true,
searching: false
searching: false,
showNoResults: false
};
}
@ -87,12 +89,12 @@ class MoreChannels extends PureComponent {
if (this.state.searching &&
nextProps.requestStatus.status === RequestStatus.SUCCESS) {
const channels = this.filterChannels(nextProps.channels, this.state.term);
this.setState({channels});
this.setState({channels, showNoResults: true});
} else if (requestStatus.status === RequestStatus.STARTED &&
nextProps.requestStatus.status === RequestStatus.SUCCESS) {
const {page} = this.state;
const channels = nextProps.channels.splice(0, (page + 1) * Constants.CHANNELS_CHUNK_SIZE);
this.setState({channels});
this.setState({channels, showNoResults: true});
}
}
@ -101,9 +103,11 @@ class MoreChannels extends PureComponent {
Keyboard.addListener('keyboardDidHide', this.handleAndroidKeyboard);
}
InteractionManager.runAfterInteractions(() => {
// set the timeout to 400 cause is the time that the modal takes to open
// Somehow interactionManager doesn't care
setTimeout(() => {
this.props.actions.getMoreChannels(this.props.currentTeamId, 0);
});
}, 400);
}
componentWillUnmount() {
@ -208,6 +212,7 @@ class MoreChannels extends PureComponent {
id);
await this.props.actions.handleSelectChannel(id);
this.props.actions.closeDrawers();
InteractionManager.runAfterInteractions(() => {
this.props.actions.goBack();
});
@ -218,13 +223,15 @@ class MoreChannels extends PureComponent {
};
render() {
const {formatMessage} = this.props.intl;
const isLoading = this.props.requestStatus.status === RequestStatus.STARTED;
const style = getStyleFromTheme(this.props.theme);
const more = this.state.searching ? () => true : this.loadMoreChannels;
const {intl, requestStatus, theme} = this.props;
const {adding, channels, searching} = this.state;
const {formatMessage} = intl;
const isLoading = requestStatus.status === RequestStatus.STARTED || requestStatus.status === RequestStatus.NOT_STARTED;
const style = getStyleFromTheme(theme);
const more = searching ? () => true : this.loadMoreChannels;
let content;
if (this.state.adding) {
if (adding) {
content = (
<View style={style.container}>
<Loading/>
@ -250,9 +257,9 @@ class MoreChannels extends PureComponent {
/>
</View>
<ChannelList
data={this.state.channels}
theme={this.props.theme}
searching={this.state.searching}
data={channels}
theme={theme}
searching={searching}
onListEndReached={more}
loading={isLoading}
selectable={false}
@ -261,6 +268,7 @@ class MoreChannels extends PureComponent {
renderRow={this.renderChannelRow}
onRowPress={this.onSelectChannel}
loadingText={{id: 'mobile.loading_channels', defaultMessage: 'Loading Channels...'}}
showNoResults={this.state.showNoResults}
/>
</View>
);

View file

@ -5,7 +5,7 @@ import {bindActionCreators} from 'redux';
import navigationSceneConnect from '../navigationSceneConnect';
import {goBack} from 'app/actions/navigation';
import {closeDrawers, goBack} from 'app/actions/navigation';
import {makeDirectChannel} from 'app/actions/views/more_dms';
import {getTheme} from 'app/selectors/preferences';
import {getProfiles, searchProfiles} from 'mattermost-redux/actions/users';
@ -41,6 +41,7 @@ function mapStateToProps(state, ownProps) {
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
closeDrawers,
goBack,
makeDirectChannel,
getProfiles,

View file

@ -31,6 +31,7 @@ class MoreDirectMessages extends PureComponent {
subscribeToHeaderEvent: React.PropTypes.func.isRequired,
unsubscribeFromHeaderEvent: React.PropTypes.func.isRequired,
actions: PropTypes.shape({
closeDrawers: PropTypes.func.isRequired,
goBack: PropTypes.func.isRequired,
makeDirectChannel: PropTypes.func.isRequired,
getProfiles: PropTypes.func.isRequired,
@ -61,11 +62,12 @@ class MoreDirectMessages extends PureComponent {
this.searchTimeoutId = 0;
this.state = {
profiles: [],
profiles: props.profiles,
page: 0,
adding: false,
next: true,
searching: false
searching: false,
showNoResults: false
};
}
@ -79,7 +81,7 @@ class MoreDirectMessages extends PureComponent {
nextProps.requestStatus.status === RequestStatus.SUCCESS) {
const {page} = this.state;
const profiles = nextProps.profiles.splice(0, (page + 1) * Constants.PROFILE_CHUNK_SIZE);
this.setState({profiles});
this.setState({profiles, showNoResults: true});
} else if (this.state.searching &&
nextProps.searchRequest.status === RequestStatus.SUCCESS) {
const results = nextProps.profiles.filter((p) => {
@ -87,7 +89,7 @@ class MoreDirectMessages extends PureComponent {
return p.username.toLowerCase().includes(term) || p.email.toLowerCase().includes(term) ||
p.first_name.toLowerCase().includes(term) || p.last_name.toLowerCase().includes(term);
});
this.setState({profiles: results});
this.setState({profiles: results, showNoResults: true});
}
}
@ -96,9 +98,11 @@ class MoreDirectMessages extends PureComponent {
Keyboard.addListener('keyboardDidHide', this.handleAndroidKeyboard);
}
InteractionManager.runAfterInteractions(() => {
// set the timeout to 400 cause is the time that the modal takes to open
// Somehow interactionManager doesn't care
setTimeout(() => {
this.props.actions.getProfiles(0);
});
}, 400);
}
componentWillUnmount() {
@ -166,20 +170,24 @@ class MoreDirectMessages extends PureComponent {
this.setState({adding: true});
this.searchBar.blur();
await this.props.actions.makeDirectChannel(id);
this.props.actions.closeDrawers();
InteractionManager.runAfterInteractions(() => {
this.props.actions.goBack();
});
};
render() {
const {formatMessage} = this.props.intl;
const isLoading = (this.props.requestStatus.status === RequestStatus.STARTED) ||
(this.props.searchRequest.status === RequestStatus.STARTED);
const style = getStyleFromTheme(this.props.theme);
const {intl, preferences, requestStatus, searchRequest, theme} = this.props;
const {adding, profiles, searching, showNoResults} = this.state;
const {formatMessage} = intl;
const isLoading = (requestStatus.status === RequestStatus.STARTED) || (requestStatus.status === RequestStatus.NOT_STARTED) ||
(searchRequest.status === RequestStatus.STARTED);
const style = getStyleFromTheme(theme);
const more = this.state.searching ? () => true : this.loadMoreProfiles;
let content;
if (this.state.adding) {
if (adding) {
content = (
<View style={style.container}>
<Loading/>
@ -205,11 +213,11 @@ class MoreDirectMessages extends PureComponent {
/>
</View>
<MemberList
data={this.state.profiles}
theme={this.props.theme}
searching={this.state.searching}
data={profiles}
theme={theme}
searching={searching}
onListEndReached={more}
preferences={this.props.preferences}
preferences={preferences}
loading={isLoading}
selectable={false}
listScrollRenderAheadDistance={50}
@ -217,6 +225,7 @@ class MoreDirectMessages extends PureComponent {
renderRow={renderMemberRow}
onRowPress={this.onSelectMember}
loadingText={loadingText}
showNoResults={showNoResults}
/>
</View>
);

View file

@ -15,6 +15,95 @@ import {getFullName} from 'mattermost-redux/utils/user_utils';
import UserProfileRow from './user_profile_row';
export default class UserProfile extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
handleSendMessage: PropTypes.func.isRequired
}).isRequired,
config: PropTypes.object.isRequired,
currentUserId: PropTypes.string.isRequired,
theme: PropTypes.object.isRequired,
user: PropTypes.object.isRequired
};
state = {
isFavorite: false
};
getDisplayName = () => {
const {theme, user} = this.props;
const style = createStyleSheet(theme);
const displayName = getFullName(user);
if (displayName) {
return <Text style={style.displayName}>{displayName}</Text>;
}
return null;
};
buildDisplayBlock = (property) => {
const {theme, user} = this.props;
const style = createStyleSheet(theme);
if (user.hasOwnProperty(property) && user[property].length > 0) {
return (
<View>
<Text style={style.header}>{property.toUpperCase()}</Text>
<Text style={style.text}>{user[property]}</Text>
</View>
);
}
return null;
};
sendMessage = () => {
this.props.actions.handleSendMessage(this.props.user.id);
};
render() {
const {config, currentUserId, theme, user} = this.props;
const style = createStyleSheet(theme);
return (
<View style={style.container}>
<ScrollView
style={style.scrollView}
contentContainerStyle={style.scrollViewContent}
>
<View style={style.top}>
<ProfilePicture
user={user}
size={150}
statusBorderWidth={6}
statusSize={40}
statusIconSize={18}
/>
{this.getDisplayName()}
<Text style={style.username}>{`@${user.username}`}</Text>
</View>
<View style={style.content}>
{this.buildDisplayBlock('username')}
{config.ShowEmailAddress === 'true' && this.buildDisplayBlock('email')}
{this.buildDisplayBlock('position')}
</View>
{currentUserId !== user.id &&
<UserProfileRow
action={this.sendMessage}
defaultMessage='Send Message'
icon='paper-plane-o'
textId='mobile.routes.user_profile.send_message'
theme={theme}
/>
}
</ScrollView>
</View>
);
}
}
const createStyleSheet = makeStyleSheetFromTheme((theme) => {
return StyleSheet.create({
container: {
@ -60,91 +149,3 @@ const createStyleSheet = makeStyleSheetFromTheme((theme) => {
}
});
});
export default class UserProfile extends PureComponent {
static propTypes = {
currentUserId: PropTypes.string.isRequired,
theme: PropTypes.object.isRequired,
user: PropTypes.object.isRequired,
actions: PropTypes.shape({
handleSendMessage: PropTypes.func.isRequired
}).isRequired
};
state = {
isFavorite: false
}
getDisplayName = () => {
const {theme, user} = this.props;
const style = createStyleSheet(theme);
const displayName = getFullName(user);
if (displayName) {
return <Text style={style.displayName}>{displayName}</Text>;
}
return null;
}
buildDisplayBlock = (property) => {
const {theme, user} = this.props;
const style = createStyleSheet(theme);
if (user.hasOwnProperty(property) && user[property].length > 0) {
return (
<View>
<Text style={style.header}>{property.toUpperCase()}</Text>
<Text style={style.text}>{user[property]}</Text>
</View>
);
}
return null;
}
sendMessage = () => {
this.props.actions.handleSendMessage(this.props.user.id);
}
render() {
const {theme, user} = this.props;
const style = createStyleSheet(theme);
return (
<View style={style.container}>
<ScrollView
style={style.scrollView}
contentContainerStyle={style.scrollViewContent}
>
<View style={style.top}>
<ProfilePicture
user={user}
size={150}
statusBorderWidth={6}
statusSize={40}
statusIconSize={18}
/>
{this.getDisplayName()}
<Text style={style.username}>{`@${user.username}`}</Text>
</View>
<View style={style.content}>
{this.buildDisplayBlock('username')}
{this.buildDisplayBlock('email')}
{this.buildDisplayBlock('position')}
</View>
{this.props.currentUserId !== this.props.user.id &&
<UserProfileRow
action={this.sendMessage}
defaultMessage='Send Message'
icon='paper-plane-o'
textId='mobile.routes.user_profile.send_message'
theme={theme}
/>
}
</ScrollView>
</View>
);
}
}

View file

@ -4,15 +4,19 @@
import {bindActionCreators} from 'redux';
import {handleSendMessage} from 'app/actions/views/user_profile';
import navigationSceneConnect from 'app/scenes/navigationSceneConnect';
import {getTheme} from 'app/selectors/preferences';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import UserProfile from './user_profile';
import navigationSceneConnect from '../navigationSceneConnect';
function mapStateToProps(state, ownProps) {
const {config} = state.entities.general;
return {
currentUserId: state.entities.users.currentUserId,
config,
currentUserId: getCurrentUserId(state),
user: state.entities.users.profiles[ownProps.userId],
theme: getTheme(state)
};