use profile image from local after editing a profile image (#1990)

This commit is contained in:
Saturnino Abril 2018-08-16 21:57:23 +08:00 committed by Harrison Healey
parent b59092e1e8
commit 669f0ea1cd
9 changed files with 93 additions and 20 deletions

View file

@ -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,
};

View file

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

View file

@ -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 (
<View style={{width: this.props.size + STATUS_BUFFER, height: this.props.size + STATUS_BUFFER}}>
<Image
key={pictureUrl}
style={{width: this.props.size, height: this.props.size, borderRadius: this.props.size / 2}}
source={source}
defaultSource={placeholder}
{...otherImageProps}
/>
{(showStatus || edit) &&
<View style={[style.statusWrapper, statusStyle, {borderRadius: this.props.statusSize / 2}]}>

View file

@ -69,6 +69,8 @@ const ViewTypes = keyMirror({
LAUNCH_CHANNEL: null,
SET_DEEP_LINK_URL: null,
SET_PROFILE_IMAGE_URI: null,
});
export default {

View file

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

View file

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

View file

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

View file

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

View file

@ -33,3 +33,7 @@ export const getThreadDraft = createSelector(
return drafts[rootId] || emptyDraft;
}
);
export function getProfileImageUri(state) {
return state.views.user.profileImageUri;
}