MM-12354 Remove Profile Image (#2428)
* save progress * Add option to remove profile picture * missed when rebasing * rename extraOptions to removeProfileImage * clean up removeProfileImage action * placeholder after removing profile picture, unit tests
This commit is contained in:
parent
f84b56e987
commit
15b44e9d71
12 changed files with 509 additions and 38 deletions
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {updateMe} from 'mattermost-redux/actions/users';
|
||||
import {updateMe, setDefaultProfileImage} from 'mattermost-redux/actions/users';
|
||||
|
||||
import {ViewTypes} from 'app/constants';
|
||||
|
||||
|
|
@ -25,7 +25,15 @@ export function setProfileImageUri(imageUri = '') {
|
|||
};
|
||||
}
|
||||
|
||||
export function removeProfileImage(user) {
|
||||
return async (dispatch) => {
|
||||
const result = await dispatch(setDefaultProfileImage(user));
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
updateUser,
|
||||
setProfileImageUri,
|
||||
removeProfileImage,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`profile_picture_button should match snapshot 1`] = `
|
||||
<AttachmentButton
|
||||
blurTextBox={[MockFunction]}
|
||||
browseFileTypes="public.item"
|
||||
canBrowseFiles={true}
|
||||
canBrowsePhotoLibrary={true}
|
||||
canBrowseVideoLibrary={true}
|
||||
canTakePhoto={true}
|
||||
canTakeVideo={true}
|
||||
extraOptions={
|
||||
Array [
|
||||
null,
|
||||
]
|
||||
}
|
||||
maxFileCount={5}
|
||||
maxFileSize={20971520}
|
||||
navigator={
|
||||
Object {
|
||||
"dismissModal": [MockFunction],
|
||||
"push": [MockFunction],
|
||||
"setButtons": [MockFunction],
|
||||
"setOnNavigatorEvent": [MockFunction],
|
||||
}
|
||||
}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
uploadFiles={[MockFunction]}
|
||||
/>
|
||||
`;
|
||||
|
|
@ -42,6 +42,7 @@ export default class AttachmentButton extends PureComponent {
|
|||
theme: PropTypes.object.isRequired,
|
||||
uploadFiles: PropTypes.func.isRequired,
|
||||
wrapper: PropTypes.bool,
|
||||
extraOptions: PropTypes.arrayOf(PropTypes.object),
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -52,6 +53,7 @@ export default class AttachmentButton extends PureComponent {
|
|||
canTakePhoto: true,
|
||||
canTakeVideo: true,
|
||||
maxFileCount: 5,
|
||||
extraOptions: null,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
|
|
@ -351,6 +353,7 @@ export default class AttachmentButton extends PureComponent {
|
|||
fileCount,
|
||||
maxFileCount,
|
||||
onShowFileMaxWarning,
|
||||
extraOptions,
|
||||
} = this.props;
|
||||
|
||||
if (fileCount === maxFileCount) {
|
||||
|
|
@ -416,6 +419,14 @@ export default class AttachmentButton extends PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
if (extraOptions) {
|
||||
extraOptions.forEach((option) => {
|
||||
if (option !== null) {
|
||||
items.push(option);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.props.navigator.showModal({
|
||||
screen: 'OptionsModal',
|
||||
title: '',
|
||||
|
|
@ -479,4 +490,3 @@ const style = StyleSheet.create({
|
|||
justifyContent: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export default class ProfilePicture extends PureComponent {
|
|||
edit: PropTypes.bool,
|
||||
imageUri: PropTypes.string,
|
||||
profileImageUri: PropTypes.string,
|
||||
profileImageRemove: PropTypes.bool,
|
||||
theme: PropTypes.object.isRequired,
|
||||
actions: PropTypes.shape({
|
||||
getStatusForId: PropTypes.func.isRequired,
|
||||
|
|
@ -47,6 +48,7 @@ export default class ProfilePicture extends PureComponent {
|
|||
|
||||
state = {
|
||||
pictureUrl: null,
|
||||
otherImageProps: {},
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
|
|
@ -97,15 +99,34 @@ export default class ProfilePicture extends PureComponent {
|
|||
}
|
||||
};
|
||||
|
||||
showDefaultImage = () => {
|
||||
if (this.mounted) {
|
||||
this.setState({otherImageProps: {defaultSource: placeholder}});
|
||||
}
|
||||
};
|
||||
|
||||
clearProfileImageUri = () => {
|
||||
if (this.props.isCurrentUser && this.props.profileImageUri !== '') {
|
||||
this.props.actions.setProfileImageUri('');
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (!this.props.edit) {
|
||||
if (this.state.otherImageProps !== prevState.otherImageProps) {
|
||||
this.showDefaultImage();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.props.profileImageRemove !== prevProps.profileImageRemove) {
|
||||
this.setImageURL(null);
|
||||
this.showDefaultImage();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {edit, showStatus, theme} = this.props;
|
||||
const {pictureUrl} = this.state;
|
||||
const {pictureUrl, otherImageProps} = this.state;
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
let statusIcon;
|
||||
|
|
@ -146,11 +167,6 @@ 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
|
||||
|
|
|
|||
76
app/components/profile_picture_button.js
Normal file
76
app/components/profile_picture_button.js
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
|
||||
import {t} from 'app/utils/i18n';
|
||||
|
||||
import AttachmentButton from 'app/components/attachment_button';
|
||||
|
||||
export default class ProfilePictureButton extends PureComponent {
|
||||
static propTypes = {
|
||||
currentUser: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
removeProfileImage: PropTypes.func,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
extraOptions: [this.getRemoveProfileImageOption()],
|
||||
};
|
||||
}
|
||||
|
||||
getRemoveProfileImageOption = () => {
|
||||
let action = null;
|
||||
const {removeProfileImage} = this.props;
|
||||
const {id, last_picture_update: lastPictureUpdate} = this.props.currentUser;
|
||||
|
||||
const profileImageUrl = Client4.getProfilePictureUrl(id, lastPictureUpdate);
|
||||
|
||||
if (removeProfileImage !== null) {
|
||||
action = removeProfileImage;
|
||||
}
|
||||
|
||||
// Check if image url includes query string for timestamp.
|
||||
// If so, it means the image has been updated from the default
|
||||
// i.e. '.../image?_=1544159746868'
|
||||
if (profileImageUrl.includes('?')) {
|
||||
return {
|
||||
action,
|
||||
text: {
|
||||
id: t('mobile.edit_profile.remove_profile_photo'),
|
||||
defaultMessage: 'Remove Photo',
|
||||
},
|
||||
textStyle: {
|
||||
color: '#CC3239',
|
||||
},
|
||||
icon: 'trash',
|
||||
iconStyle: {
|
||||
color: '#CC3239',
|
||||
},
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {children, ...props} = this.props;
|
||||
const {extraOptions} = this.state;
|
||||
|
||||
// Avoid passing unneeded props
|
||||
Reflect.deleteProperty(props, 'currentUser');
|
||||
|
||||
return (
|
||||
<AttachmentButton
|
||||
{...props}
|
||||
extraOptions={extraOptions}
|
||||
>
|
||||
{children}
|
||||
</AttachmentButton>
|
||||
);
|
||||
}
|
||||
}
|
||||
66
app/components/profile_picture_button.test.js
Normal file
66
app/components/profile_picture_button.test.js
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React from 'react';
|
||||
import {shallow} from 'enzyme';
|
||||
|
||||
import Preferences from 'mattermost-redux/constants/preferences';
|
||||
|
||||
import ProfilePictureButton from './profile_picture_button.js';
|
||||
|
||||
import {Client4} from 'mattermost-redux/client';
|
||||
|
||||
describe('profile_picture_button', () => {
|
||||
const navigator = {
|
||||
setOnNavigatorEvent: jest.fn(),
|
||||
setButtons: jest.fn(),
|
||||
dismissModal: jest.fn(),
|
||||
push: jest.fn(),
|
||||
};
|
||||
|
||||
const baseProps = {
|
||||
theme: Preferences.THEMES.default,
|
||||
navigator,
|
||||
currentUser: {
|
||||
first_name: 'Dwight',
|
||||
last_name: 'Schrute',
|
||||
username: 'ieatbeets',
|
||||
email: 'dwight@schrutefarms.com',
|
||||
nickname: 'Dragon',
|
||||
position: 'position',
|
||||
},
|
||||
blurTextBox: jest.fn(),
|
||||
maxFileSize: 20 * 1024 * 1024,
|
||||
uploadFiles: jest.fn(),
|
||||
};
|
||||
|
||||
test('should match snapshot', async () => {
|
||||
const wrapper = shallow(
|
||||
<ProfilePictureButton {...baseProps}/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should NOT return option to remove when profile picture is default', () => {
|
||||
Client4.getProfilePictureUrl = jest.fn(() => 'image.png');
|
||||
const wrapper = shallow(
|
||||
<ProfilePictureButton {...baseProps}/>,
|
||||
);
|
||||
const instance = wrapper.instance();
|
||||
|
||||
// test default image (WITHOUT query param)
|
||||
instance.getRemoveProfileImageOption();
|
||||
expect(wrapper.state('extraOptions')).toEqual([null]);
|
||||
});
|
||||
|
||||
test('should return option to remove profile picture if customized', () => {
|
||||
Client4.getProfilePictureUrl = jest.fn(() => 'image.png?query');
|
||||
const wrapper = shallow(
|
||||
<ProfilePictureButton {...baseProps}/>,
|
||||
);
|
||||
const instance = wrapper.instance();
|
||||
|
||||
// test custom image (WITH query param)
|
||||
instance.getRemoveProfileImageOption();
|
||||
expect(wrapper.state('extraOptions')).not.toEqual([null]);
|
||||
});
|
||||
});
|
||||
112
app/screens/edit_profile/__snapshots__/edit_profile.test.js.snap
Normal file
112
app/screens/edit_profile/__snapshots__/edit_profile.test.js.snap
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`edit_profile should match snapshot 1`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"alignItems": "center",
|
||||
"justifyContent": "center",
|
||||
"padding": 25,
|
||||
}
|
||||
}
|
||||
>
|
||||
<ProfilePictureButton
|
||||
blurTextBox={[Function]}
|
||||
browseFileTypes="public.image"
|
||||
canBrowseVideoLibrary={false}
|
||||
canTakeVideo={false}
|
||||
currentUser={
|
||||
Object {
|
||||
"email": "dwight@schrutefarms.com",
|
||||
"first_name": "Dwight",
|
||||
"last_name": "Schrute",
|
||||
"nickname": "Dragon",
|
||||
"position": "position",
|
||||
"username": "ieatbeets",
|
||||
}
|
||||
}
|
||||
maxFileSize={20971520}
|
||||
navigator={
|
||||
Object {
|
||||
"dismissModal": [MockFunction],
|
||||
"push": [MockFunction],
|
||||
"setButtons": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
Object {
|
||||
"rightButtons": Array [
|
||||
Object {
|
||||
"disabled": true,
|
||||
"id": "update-profile",
|
||||
"showAsAction": "always",
|
||||
"title": undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
"setOnNavigatorEvent": [MockFunction] {
|
||||
"calls": Array [
|
||||
Array [
|
||||
[Function],
|
||||
],
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"isThrow": false,
|
||||
"value": undefined,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
onShowFileSizeWarning={[Function]}
|
||||
removeProfileImage={[Function]}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
uploadFiles={[Function]}
|
||||
wrapper={true}
|
||||
>
|
||||
<Connect(ProfilePicture)
|
||||
edit={true}
|
||||
imageUri={null}
|
||||
size={150}
|
||||
statusBorderWidth={6}
|
||||
statusSize={40}
|
||||
/>
|
||||
</ProfilePictureButton>
|
||||
</View>
|
||||
`;
|
||||
|
|
@ -21,8 +21,8 @@ import TextSetting from 'app/components/widgets/settings/text_setting';
|
|||
import Loading from 'app/components/loading';
|
||||
import ErrorText from 'app/components/error_text';
|
||||
import StatusBar from 'app/components/status_bar/index';
|
||||
import ProfilePictureButton from 'app/components/profile_picture_button';
|
||||
import ProfilePicture from 'app/components/profile_picture';
|
||||
import AttachmentButton from 'app/components/attachment_button';
|
||||
import mattermostBucket from 'app/mattermost_bucket';
|
||||
import LocalConfig from 'assets/config';
|
||||
import {getFormattedFileSize} from 'mattermost-redux/utils/file_utils';
|
||||
|
|
@ -59,6 +59,7 @@ export default class EditProfile extends PureComponent {
|
|||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
setProfileImageUri: PropTypes.func.isRequired,
|
||||
removeProfileImage: PropTypes.func.isRequired,
|
||||
updateUser: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
config: PropTypes.object.isRequired,
|
||||
|
|
@ -157,6 +158,7 @@ export default class EditProfile extends PureComponent {
|
|||
|
||||
const {
|
||||
profileImage,
|
||||
profileImageRemove,
|
||||
firstName,
|
||||
lastName,
|
||||
username,
|
||||
|
|
@ -172,13 +174,17 @@ export default class EditProfile extends PureComponent {
|
|||
position,
|
||||
email,
|
||||
};
|
||||
const {actions} = this.props;
|
||||
const {actions, currentUser} = this.props;
|
||||
|
||||
if (profileImage) {
|
||||
actions.setProfileImageUri(profileImage.uri);
|
||||
this.uploadProfileImage().catch(this.handleUploadError);
|
||||
}
|
||||
|
||||
if (profileImageRemove) {
|
||||
actions.removeProfileImage(currentUser.id);
|
||||
}
|
||||
|
||||
if (this.canUpdate()) {
|
||||
const {error} = await actions.updateUser(user);
|
||||
if (error) {
|
||||
|
|
@ -196,6 +202,14 @@ export default class EditProfile extends PureComponent {
|
|||
this.emitCanUpdateAccount(true);
|
||||
};
|
||||
|
||||
handleRemoveProfileImage = () => {
|
||||
this.setState({profileImageRemove: true});
|
||||
this.emitCanUpdateAccount(true);
|
||||
this.props.navigator.dismissModal({
|
||||
animationType: 'none',
|
||||
});
|
||||
}
|
||||
|
||||
uploadProfileImage = async () => {
|
||||
const {profileImage} = this.state;
|
||||
const {currentUser} = this.props;
|
||||
|
|
@ -452,7 +466,7 @@ export default class EditProfile extends PureComponent {
|
|||
this.scrollView = ref;
|
||||
};
|
||||
|
||||
render() {
|
||||
renderProfilePicture = () => {
|
||||
const {
|
||||
currentUser,
|
||||
theme,
|
||||
|
|
@ -461,12 +475,51 @@ export default class EditProfile extends PureComponent {
|
|||
|
||||
const {
|
||||
profileImage,
|
||||
profileImageRemove,
|
||||
} = this.state;
|
||||
|
||||
const style = getStyleSheet(theme);
|
||||
const uri = profileImage ? profileImage.uri : null;
|
||||
|
||||
return (
|
||||
<View style={style.top}>
|
||||
<ProfilePictureButton
|
||||
currentUser={currentUser}
|
||||
theme={theme}
|
||||
blurTextBox={emptyFunction}
|
||||
browseFileTypes={DocumentPickerUtil.images()}
|
||||
canTakeVideo={false}
|
||||
canBrowseVideoLibrary={false}
|
||||
maxFileSize={MAX_SIZE}
|
||||
navigator={navigator}
|
||||
wrapper={true}
|
||||
uploadFiles={this.handleUploadProfileImage}
|
||||
removeProfileImage={this.handleRemoveProfileImage}
|
||||
onShowFileSizeWarning={this.onShowFileSizeWarning}
|
||||
>
|
||||
<ProfilePicture
|
||||
userId={currentUser.id}
|
||||
size={150}
|
||||
statusBorderWidth={6}
|
||||
statusSize={40}
|
||||
edit={true}
|
||||
imageUri={uri}
|
||||
profileImageRemove={profileImageRemove}
|
||||
/>
|
||||
</ProfilePictureButton>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {theme} = this.props;
|
||||
|
||||
const {
|
||||
error,
|
||||
updating,
|
||||
} = this.state;
|
||||
|
||||
const style = getStyleSheet(theme);
|
||||
const uri = profileImage ? profileImage.uri : null;
|
||||
|
||||
if (updating) {
|
||||
return (
|
||||
|
|
@ -501,29 +554,7 @@ export default class EditProfile extends PureComponent {
|
|||
>
|
||||
{displayError}
|
||||
<View style={[style.scrollView]}>
|
||||
<View style={style.top}>
|
||||
<AttachmentButton
|
||||
blurTextBox={emptyFunction}
|
||||
browseFileTypes={DocumentPickerUtil.images()}
|
||||
canTakeVideo={false}
|
||||
canBrowseVideoLibrary={false}
|
||||
maxFileSize={MAX_SIZE}
|
||||
theme={theme}
|
||||
navigator={navigator}
|
||||
wrapper={true}
|
||||
uploadFiles={this.handleUploadProfileImage}
|
||||
onShowFileSizeWarning={this.onShowFileSizeWarning}
|
||||
>
|
||||
<ProfilePicture
|
||||
userId={currentUser.id}
|
||||
size={150}
|
||||
statusBorderWidth={6}
|
||||
statusSize={40}
|
||||
edit={true}
|
||||
imageUri={uri}
|
||||
/>
|
||||
</AttachmentButton>
|
||||
</View>
|
||||
{this.renderProfilePicture()}
|
||||
{this.renderFirstNameSettings()}
|
||||
<View style={style.separator}/>
|
||||
{this.renderLastNameSettings()}
|
||||
|
|
|
|||
84
app/screens/edit_profile/edit_profile.test.js
Normal file
84
app/screens/edit_profile/edit_profile.test.js
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React from 'react';
|
||||
import {shallow} from 'enzyme';
|
||||
|
||||
import Preferences from 'mattermost-redux/constants/preferences';
|
||||
|
||||
import EditProfile from './edit_profile.js';
|
||||
|
||||
jest.mock('react-intl');
|
||||
jest.mock('app/utils/theme', () => {
|
||||
const original = require.requireActual('app/utils/theme');
|
||||
return {
|
||||
...original,
|
||||
changeOpacity: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('edit_profile', () => {
|
||||
const navigator = {
|
||||
setOnNavigatorEvent: jest.fn(),
|
||||
setButtons: jest.fn(),
|
||||
dismissModal: jest.fn(),
|
||||
push: jest.fn(),
|
||||
};
|
||||
|
||||
const actions = {
|
||||
updateUser: jest.fn(),
|
||||
setProfileImageUri: jest.fn(),
|
||||
removeProfileImage: jest.fn(),
|
||||
};
|
||||
|
||||
const baseProps = {
|
||||
actions,
|
||||
config: {
|
||||
ShowEmailAddress: true,
|
||||
},
|
||||
theme: Preferences.THEMES.default,
|
||||
navigator,
|
||||
currentUser: {
|
||||
first_name: 'Dwight',
|
||||
last_name: 'Schrute',
|
||||
username: 'ieatbeets',
|
||||
email: 'dwight@schrutefarms.com',
|
||||
nickname: 'Dragon',
|
||||
position: 'position',
|
||||
},
|
||||
};
|
||||
|
||||
test('should match snapshot', async () => {
|
||||
const wrapper = shallow(
|
||||
<EditProfile {...baseProps}/>,
|
||||
{context: {intl: {formatMessage: jest.fn()}}},
|
||||
);
|
||||
expect(wrapper.instance().renderProfilePicture()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match state on handleRemoveProfileImage', () => {
|
||||
const newNavigator = {
|
||||
dismissModal: jest.fn(),
|
||||
setOnNavigatorEvent: jest.fn(),
|
||||
setButtons: jest.fn(),
|
||||
};
|
||||
const wrapper = shallow(
|
||||
<EditProfile
|
||||
{...baseProps}
|
||||
navigator={newNavigator}
|
||||
/>,
|
||||
{context: {intl: {formatMessage: jest.fn()}}},
|
||||
);
|
||||
wrapper.setProps({profileImageRemove: false});
|
||||
|
||||
const instance = wrapper.instance();
|
||||
instance.emitCanUpdateAccount = jest.fn();
|
||||
instance.handleRemoveProfileImage();
|
||||
|
||||
expect(wrapper.state('profileImageRemove')).toEqual(true);
|
||||
expect(instance.emitCanUpdateAccount).toHaveBeenCalledTimes(1);
|
||||
expect(instance.emitCanUpdateAccount).toBeCalledWith(true);
|
||||
|
||||
expect(newNavigator.dismissModal).toHaveBeenCalledTimes(1);
|
||||
expect(newNavigator.dismissModal).toBeCalledWith({animationType: 'none'});
|
||||
});
|
||||
});
|
||||
|
|
@ -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 {setProfileImageUri, updateUser} from 'app/actions/views/edit_profile';
|
||||
import {setProfileImageUri, removeProfileImage, updateUser} from 'app/actions/views/edit_profile';
|
||||
|
||||
import EditProfile from './edit_profile';
|
||||
|
||||
|
|
@ -22,6 +22,7 @@ function mapDispatchToProps(dispatch) {
|
|||
return {
|
||||
actions: bindActionCreators({
|
||||
setProfileImageUri,
|
||||
removeProfileImage,
|
||||
updateUser,
|
||||
}, dispatch),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@ export default class OptionsModalList extends PureComponent {
|
|||
|
||||
const options = items.map((item, index) => {
|
||||
let textComponent;
|
||||
let optionIconStyle = style.optionIcon;
|
||||
if (typeof item.iconStyle !== 'undefined') {
|
||||
optionIconStyle = item.iconStyle;
|
||||
}
|
||||
|
||||
if (item.text.hasOwnProperty('id')) {
|
||||
textComponent = (
|
||||
<FormattedText
|
||||
|
|
@ -66,7 +71,7 @@ export default class OptionsModalList extends PureComponent {
|
|||
<IconFont
|
||||
name={item.icon}
|
||||
size={18}
|
||||
style={style.optionIcon}
|
||||
style={optionIconStyle}
|
||||
/>
|
||||
}
|
||||
</TouchableOpacity>
|
||||
|
|
|
|||
|
|
@ -45,6 +45,11 @@ export default class OptionsModalList extends PureComponent {
|
|||
|
||||
const options = items.map((item, index) => {
|
||||
let textComponent;
|
||||
let optionIconStyle = style.optionIcon;
|
||||
if (typeof item.iconStyle !== 'undefined') {
|
||||
optionIconStyle = item.iconStyle;
|
||||
}
|
||||
|
||||
if (item.text.hasOwnProperty('id')) {
|
||||
textComponent = (
|
||||
<FormattedText
|
||||
|
|
@ -70,7 +75,7 @@ export default class OptionsModalList extends PureComponent {
|
|||
<IconFont
|
||||
name={item.icon}
|
||||
size={18}
|
||||
style={style.optionIcon}
|
||||
style={optionIconStyle}
|
||||
/>
|
||||
}
|
||||
</TouchableOpacity>
|
||||
|
|
|
|||
Loading…
Reference in a new issue