From 669f0ea1cd1eff3dc26f96c8c0836a9198ac55f1 Mon Sep 17 00:00:00 2001 From: Saturnino Abril Date: Thu, 16 Aug 2018 21:57:23 +0800 Subject: [PATCH] use profile image from local after editing a profile image (#1990) --- app/actions/views/edit_profile.js | 14 ++++++ app/components/profile_picture/index.js | 14 +++++- .../profile_picture/profile_picture.js | 49 ++++++++++++------- app/constants/view.js | 2 + app/reducers/views/index.js | 2 + app/reducers/views/user.js | 20 ++++++++ app/screens/edit_profile/edit_profile.js | 5 +- app/screens/edit_profile/index.js | 3 +- app/selectors/views.js | 4 ++ 9 files changed, 93 insertions(+), 20 deletions(-) create mode 100644 app/reducers/views/user.js diff --git a/app/actions/views/edit_profile.js b/app/actions/views/edit_profile.js index 844abae30..fc5868cb1 100644 --- a/app/actions/views/edit_profile.js +++ b/app/actions/views/edit_profile.js @@ -3,6 +3,8 @@ import {updateMe} from 'mattermost-redux/actions/users'; +import {ViewTypes} from 'app/constants'; + export function updateUser(user, success, error) { return async (dispatch, getState) => { const result = await updateMe(user)(dispatch, getState); @@ -15,3 +17,15 @@ export function updateUser(user, success, error) { return result; }; } + +export function setProfileImageUri(imageUri = '') { + return { + type: ViewTypes.SET_PROFILE_IMAGE_URI, + imageUri, + }; +} + +export default { + updateUser, + setProfileImageUri, +}; diff --git a/app/components/profile_picture/index.js b/app/components/profile_picture/index.js index 9c76e0c0c..3a77ef609 100644 --- a/app/components/profile_picture/index.js +++ b/app/components/profile_picture/index.js @@ -6,7 +6,10 @@ import {connect} from 'react-redux'; import {getTheme} from 'mattermost-redux/selectors/entities/preferences'; import {getStatusesByIdsBatchedDebounced} from 'mattermost-redux/actions/users'; -import {getStatusForUserId, getUser} from 'mattermost-redux/selectors/entities/users'; +import {getCurrentUserId, getStatusForUserId, getUser} from 'mattermost-redux/selectors/entities/users'; + +import {setProfileImageUri} from 'app/actions/views/edit_profile'; +import {getProfileImageUri} from 'app/selectors/views'; import ProfilePicture from './profile_picture'; @@ -17,8 +20,16 @@ function mapStateToProps(state, ownProps) { status = getStatusForUserId(state, ownProps.userId); } + const isCurrentUser = getCurrentUserId(state) === ownProps.userId; + let profileImageUri = ''; + if (isCurrentUser) { + profileImageUri = getProfileImageUri(state); + } + return { + isCurrentUser, theme: getTheme(state), + profileImageUri, status, user, }; @@ -27,6 +38,7 @@ function mapStateToProps(state, ownProps) { function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ + setProfileImageUri, getStatusForId: getStatusesByIdsBatchedDebounced, }, dispatch), }; diff --git a/app/components/profile_picture/profile_picture.js b/app/components/profile_picture/profile_picture.js index 567f72a98..164f19177 100644 --- a/app/components/profile_picture/profile_picture.js +++ b/app/components/profile_picture/profile_picture.js @@ -22,6 +22,7 @@ const STATUS_BUFFER = Platform.select({ export default class ProfilePicture extends PureComponent { static propTypes = { + isCurrentUser: PropTypes.bool.isRequired, size: PropTypes.number, statusSize: PropTypes.number, user: PropTypes.object, @@ -29,9 +30,11 @@ export default class ProfilePicture extends PureComponent { status: PropTypes.string, edit: PropTypes.bool, imageUri: PropTypes.string, + profileImageUri: PropTypes.string, theme: PropTypes.object.isRequired, actions: PropTypes.shape({ getStatusForId: PropTypes.func.isRequired, + setProfileImageUri: PropTypes.func.isRequired, }), }; @@ -47,12 +50,14 @@ export default class ProfilePicture extends PureComponent { }; componentWillMount() { - const {edit, imageUri, user} = this.props; + const {edit, imageUri, profileImageUri, user} = this.props; - if (edit && imageUri) { + if (profileImageUri) { + this.setImageURL(profileImageUri); + } else if (edit && imageUri) { this.setImageURL(imageUri); } else if (user) { - ImageCacheManager.cache('', Client4.getProfilePictureUrl(user.id, user.last_picture_update), this.setImageURL); + ImageCacheManager.cache('', Client4.getProfilePictureUrl(user.id, user.last_picture_update), this.setImageURL).then(this.clearProfileImageUri).catch(emptyFunction); } } @@ -66,22 +71,21 @@ export default class ProfilePicture extends PureComponent { componentWillReceiveProps(nextProps) { if (this.mounted) { + if (nextProps.edit && nextProps.imageUri && nextProps.imageUri !== this.props.imageUri) { + this.setImageURL(nextProps.imageUri); + return; + } + + if (nextProps.profileImageUri !== '' && nextProps.profileImageUri !== this.props.profileImageUri) { + this.setImageURL(nextProps.profileImageUri); + } + const url = this.props.user ? Client4.getProfilePictureUrl(this.props.user.id, this.props.user.last_picture_update) : null; const nextUrl = nextProps.user ? Client4.getProfilePictureUrl(nextProps.user.id, nextProps.user.last_picture_update) : null; - if (url !== nextUrl) { - this.setState({ - pictureUrl: null, - }); - - if (nextUrl) { - // empty function is so that promise unhandled is not triggered in dev mode - ImageCacheManager.cache('', nextUrl, this.setImageURL).then(emptyFunction).catch(emptyFunction); - } - } - - if (nextProps.edit && nextProps.imageUri !== this.props.imageUri) { - this.setImageURL(nextProps.imageUri); + if (nextUrl && url !== nextUrl) { + // empty function is so that promise unhandled is not triggered in dev mode + ImageCacheManager.cache('', nextUrl, this.setImageURL).then(this.clearProfileImageUri).catch(emptyFunction); } } } @@ -96,6 +100,12 @@ export default class ProfilePicture extends PureComponent { } }; + clearProfileImageUri = () => { + if (this.props.isCurrentUser && this.props.profileImageUri !== '') { + this.props.actions.setProfileImageUri(''); + } + } + render() { const {edit, showStatus, theme} = this.props; const {pictureUrl} = this.state; @@ -139,13 +149,18 @@ export default class ProfilePicture extends PureComponent { }; } + const otherImageProps = {}; + if (!this.props.edit) { + otherImageProps.defaultSource = placeholder; + } + return ( {(showStatus || edit) && diff --git a/app/constants/view.js b/app/constants/view.js index 6fb81576e..01f9b4aed 100644 --- a/app/constants/view.js +++ b/app/constants/view.js @@ -69,6 +69,8 @@ const ViewTypes = keyMirror({ LAUNCH_CHANNEL: null, SET_DEEP_LINK_URL: null, + + SET_PROFILE_IMAGE_URI: null, }); export default { diff --git a/app/reducers/views/index.js b/app/reducers/views/index.js index 3a92db4e2..49185854b 100644 --- a/app/reducers/views/index.js +++ b/app/reducers/views/index.js @@ -15,6 +15,7 @@ import search from './search'; import selectServer from './select_server'; import team from './team'; import thread from './thread'; +import user from './user'; import emoji from './emoji'; export default combineReducers({ @@ -30,5 +31,6 @@ export default combineReducers({ selectServer, team, thread, + user, emoji, }); diff --git a/app/reducers/views/user.js b/app/reducers/views/user.js new file mode 100644 index 000000000..9fc492f33 --- /dev/null +++ b/app/reducers/views/user.js @@ -0,0 +1,20 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {combineReducers} from 'redux'; + +import {ViewTypes} from 'app/constants'; + +function profileImageUri(state = '', action) { + switch (action.type) { + case ViewTypes.SET_PROFILE_IMAGE_URI: { + return action.imageUri; + } + default: + return state; + } +} + +export default combineReducers({ + profileImageUri, +}); diff --git a/app/screens/edit_profile/edit_profile.js b/app/screens/edit_profile/edit_profile.js index c4ceddc0d..b0cd2f412 100644 --- a/app/screens/edit_profile/edit_profile.js +++ b/app/screens/edit_profile/edit_profile.js @@ -53,6 +53,7 @@ const holders = { export default class EditProfile extends PureComponent { static propTypes = { actions: PropTypes.shape({ + setProfileImageUri: PropTypes.func.isRequired, updateUser: PropTypes.func.isRequired, }).isRequired, config: PropTypes.object.isRequired, @@ -166,13 +167,15 @@ export default class EditProfile extends PureComponent { position, email, }; + const {actions} = this.props; if (profileImage) { + actions.setProfileImageUri(profileImage.uri); this.uploadProfileImage().catch(this.handleUploadError); } if (this.canUpdate()) { - const {error} = await this.props.actions.updateUser(user); + const {error} = await actions.updateUser(user); if (error) { this.handleRequestError(error); return; diff --git a/app/screens/edit_profile/index.js b/app/screens/edit_profile/index.js index 776430678..6986c7d4c 100644 --- a/app/screens/edit_profile/index.js +++ b/app/screens/edit_profile/index.js @@ -7,7 +7,7 @@ import {bindActionCreators} from 'redux'; import {getConfig} from 'mattermost-redux/selectors/entities/general'; import {getTheme} from 'mattermost-redux/selectors/entities/preferences'; -import {updateUser} from 'app/actions/views/edit_profile'; +import {setProfileImageUri, updateUser} from 'app/actions/views/edit_profile'; import EditProfile from './edit_profile'; @@ -21,6 +21,7 @@ function mapStateToProps(state) { function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ + setProfileImageUri, updateUser, }, dispatch), }; diff --git a/app/selectors/views.js b/app/selectors/views.js index 5afa005ce..b6d0c63d0 100644 --- a/app/selectors/views.js +++ b/app/selectors/views.js @@ -33,3 +33,7 @@ export const getThreadDraft = createSelector( return drafts[rootId] || emptyDraft; } ); + +export function getProfileImageUri(state) { + return state.views.user.profileImageUri; +}