Chore: Migrate ProfileView to TypeScript
* Initial commit * Fix module import * Improve TextInput and KeyboardView interfaces and migrate scrollPersistTaps to TS * update interfaces * add new interfaces and extract them to their own file * chore: migrate style.js to ts Co-authored-by: AlexAlexandre <alexalexandrejr@gmail.com>
This commit is contained in:
parent
7d15e2d309
commit
8e4d47cf7b
|
@ -2,7 +2,7 @@ module.exports = {
|
||||||
settings: {
|
settings: {
|
||||||
'import/resolver': {
|
'import/resolver': {
|
||||||
node: {
|
node: {
|
||||||
extensions: ['.js', '.ios.js', '.android.js', '.native.js', '.ts', '.tsx']
|
extensions: ['.ts', '.tsx', '.js', '.ios.js', '.android.js', '.native.js']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,7 +16,7 @@ export interface IAvatar {
|
||||||
onPress(): void;
|
onPress(): void;
|
||||||
getCustomEmoji(): any;
|
getCustomEmoji(): any;
|
||||||
avatarETag: string;
|
avatarETag: string;
|
||||||
isStatic: boolean;
|
isStatic: boolean | string;
|
||||||
rid: string;
|
rid: string;
|
||||||
blockUnauthenticatedAccess: boolean;
|
blockUnauthenticatedAccess: boolean;
|
||||||
serverVersion: string;
|
serverVersion: string;
|
||||||
|
|
|
@ -58,7 +58,7 @@ interface IRCTextInputProps extends TextInputProps {
|
||||||
};
|
};
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
containerStyle?: StyleProp<ViewStyle>;
|
containerStyle?: StyleProp<ViewStyle>;
|
||||||
inputStyle?: TextStyle;
|
inputStyle?: StyleProp<TextStyle>;
|
||||||
inputRef?: React.Ref<unknown>;
|
inputRef?: React.Ref<unknown>;
|
||||||
testID?: string;
|
testID?: string;
|
||||||
iconLeft?: string;
|
iconLeft?: string;
|
||||||
|
|
|
@ -10,3 +10,4 @@ declare module '@rocket.chat/sdk';
|
||||||
declare module 'react-native-config-reader';
|
declare module 'react-native-config-reader';
|
||||||
declare module 'react-native-keycommands';
|
declare module 'react-native-keycommands';
|
||||||
declare module 'react-native-restart';
|
declare module 'react-native-restart';
|
||||||
|
declare module 'react-native-prompt-android';
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { KeyboardAwareScrollView } from '@codler/react-native-keyboard-aware-scroll-view';
|
import { KeyboardAwareScrollView, KeyboardAwareScrollViewProps } from '@codler/react-native-keyboard-aware-scroll-view';
|
||||||
|
|
||||||
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
import scrollPersistTaps from '../utils/scrollPersistTaps';
|
||||||
|
|
||||||
interface IKeyboardViewProps {
|
interface IKeyboardViewProps extends KeyboardAwareScrollViewProps {
|
||||||
style: any;
|
|
||||||
contentContainerStyle: any;
|
|
||||||
keyboardVerticalOffset: number;
|
keyboardVerticalOffset: number;
|
||||||
scrollEnabled: boolean;
|
children: React.ReactNode;
|
||||||
children: JSX.Element;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class KeyboardView extends React.PureComponent<IKeyboardViewProps, any> {
|
export default class KeyboardView extends React.PureComponent<IKeyboardViewProps, any> {
|
||||||
|
@ -22,9 +19,7 @@ export default class KeyboardView extends React.PureComponent<IKeyboardViewProps
|
||||||
contentContainerStyle={contentContainerStyle}
|
contentContainerStyle={contentContainerStyle}
|
||||||
scrollEnabled={scrollEnabled}
|
scrollEnabled={scrollEnabled}
|
||||||
alwaysBounceVertical={false}
|
alwaysBounceVertical={false}
|
||||||
extraHeight={keyboardVerticalOffset}
|
extraHeight={keyboardVerticalOffset}>
|
||||||
// @ts-ignore
|
|
||||||
behavior='position'>
|
|
||||||
{children}
|
{children}
|
||||||
</KeyboardAwareScrollView>
|
</KeyboardAwareScrollView>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
export default {
|
|
||||||
keyboardShouldPersistTaps: 'always',
|
|
||||||
keyboardDismissMode: 'interactive'
|
|
||||||
};
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { KeyboardAwareScrollViewProps } from '@codler/react-native-keyboard-aware-scroll-view';
|
||||||
|
|
||||||
|
const scrollPersistTaps: Partial<KeyboardAwareScrollViewProps> = {
|
||||||
|
keyboardShouldPersistTaps: 'always',
|
||||||
|
keyboardDismissMode: 'interactive'
|
||||||
|
};
|
||||||
|
|
||||||
|
export default scrollPersistTaps;
|
|
@ -1,13 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Keyboard, ScrollView, View } from 'react-native';
|
import { Keyboard, ScrollView, View } from 'react-native';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import prompt from 'react-native-prompt-android';
|
import prompt from 'react-native-prompt-android';
|
||||||
import SHA256 from 'js-sha256';
|
import { sha256 } from 'js-sha256';
|
||||||
import ImagePicker from 'react-native-image-crop-picker';
|
import ImagePicker, { Image } from 'react-native-image-crop-picker';
|
||||||
import RNPickerSelect from 'react-native-picker-select';
|
import RNPickerSelect from 'react-native-picker-select';
|
||||||
import { dequal } from 'dequal';
|
import { dequal } from 'dequal';
|
||||||
import omit from 'lodash/omit';
|
import omit from 'lodash/omit';
|
||||||
|
import { StackNavigationOptions } from '@react-navigation/stack';
|
||||||
|
|
||||||
import Touch from '../../utils/touch';
|
import Touch from '../../utils/touch';
|
||||||
import KeyboardView from '../../presentation/KeyboardView';
|
import KeyboardView from '../../presentation/KeyboardView';
|
||||||
|
@ -31,43 +31,40 @@ import { withTheme } from '../../theme';
|
||||||
import { getUserSelector } from '../../selectors/login';
|
import { getUserSelector } from '../../selectors/login';
|
||||||
import SafeAreaView from '../../containers/SafeAreaView';
|
import SafeAreaView from '../../containers/SafeAreaView';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
import { IAvatar, IAvatarButton, INavigationOptions, IParams, IProfileViewProps, IProfileViewState, IUser } from './interfaces';
|
||||||
|
|
||||||
class ProfileView extends React.Component {
|
class ProfileView extends React.Component<IProfileViewProps, IProfileViewState> {
|
||||||
static navigationOptions = ({ navigation, isMasterDetail }) => {
|
private name: any;
|
||||||
const options = {
|
private username: any;
|
||||||
|
private email: any;
|
||||||
|
private avatarUrl: any;
|
||||||
|
private newPassword: any;
|
||||||
|
|
||||||
|
static navigationOptions = ({ navigation, isMasterDetail }: INavigationOptions) => {
|
||||||
|
const options: StackNavigationOptions = {
|
||||||
title: I18n.t('Profile')
|
title: I18n.t('Profile')
|
||||||
};
|
};
|
||||||
if (!isMasterDetail) {
|
if (!isMasterDetail) {
|
||||||
options.headerLeft = () => <HeaderButton.Drawer navigation={navigation} />;
|
options.headerLeft = () => <HeaderButton.Drawer navigation={navigation} />;
|
||||||
}
|
}
|
||||||
options.headerRight = () => (
|
options.headerRight = () => (
|
||||||
<HeaderButton.Preferences onPress={() => navigation.navigate('UserPreferencesView')} testID='preferences-view-open' />
|
<HeaderButton.Preferences onPress={() => navigation?.navigate('UserPreferencesView')} testID='preferences-view-open' />
|
||||||
);
|
);
|
||||||
return options;
|
return options;
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
state: IProfileViewState = {
|
||||||
baseUrl: PropTypes.string,
|
|
||||||
user: PropTypes.object,
|
|
||||||
Accounts_AllowEmailChange: PropTypes.bool,
|
|
||||||
Accounts_AllowPasswordChange: PropTypes.bool,
|
|
||||||
Accounts_AllowRealNameChange: PropTypes.bool,
|
|
||||||
Accounts_AllowUserAvatarChange: PropTypes.bool,
|
|
||||||
Accounts_AllowUsernameChange: PropTypes.bool,
|
|
||||||
Accounts_CustomFields: PropTypes.string,
|
|
||||||
setUser: PropTypes.func,
|
|
||||||
theme: PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
saving: false,
|
saving: false,
|
||||||
name: null,
|
name: '',
|
||||||
username: null,
|
username: '',
|
||||||
email: null,
|
email: '',
|
||||||
newPassword: null,
|
newPassword: '',
|
||||||
currentPassword: null,
|
currentPassword: '',
|
||||||
avatarUrl: null,
|
avatarUrl: '',
|
||||||
avatar: {},
|
avatar: {
|
||||||
|
data: {},
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
avatarSuggestions: {},
|
avatarSuggestions: {},
|
||||||
customFields: {}
|
customFields: {}
|
||||||
};
|
};
|
||||||
|
@ -83,7 +80,7 @@ class ProfileView extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
UNSAFE_componentWillReceiveProps(nextProps: IProfileViewProps) {
|
||||||
const { user } = this.props;
|
const { user } = this.props;
|
||||||
/*
|
/*
|
||||||
* We need to ignore status because on Android ImagePicker
|
* We need to ignore status because on Android ImagePicker
|
||||||
|
@ -96,7 +93,7 @@ class ProfileView extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setAvatar = avatar => {
|
setAvatar = (avatar: IAvatar) => {
|
||||||
const { Accounts_AllowUserAvatarChange } = this.props;
|
const { Accounts_AllowUserAvatarChange } = this.props;
|
||||||
|
|
||||||
if (!Accounts_AllowUserAvatarChange) {
|
if (!Accounts_AllowUserAvatarChange) {
|
||||||
|
@ -106,7 +103,7 @@ class ProfileView extends React.Component {
|
||||||
this.setState({ avatar });
|
this.setState({ avatar });
|
||||||
};
|
};
|
||||||
|
|
||||||
init = user => {
|
init = (user?: IUser) => {
|
||||||
const { user: userProps } = this.props;
|
const { user: userProps } = this.props;
|
||||||
const { name, username, emails, customFields } = user || userProps;
|
const { name, username, emails, customFields } = user || userProps;
|
||||||
|
|
||||||
|
@ -117,7 +114,10 @@ class ProfileView extends React.Component {
|
||||||
newPassword: null,
|
newPassword: null,
|
||||||
currentPassword: null,
|
currentPassword: null,
|
||||||
avatarUrl: null,
|
avatarUrl: null,
|
||||||
avatar: {},
|
avatar: {
|
||||||
|
data: {},
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
customFields: customFields || {}
|
customFields: customFields || {}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -142,12 +142,12 @@ class ProfileView extends React.Component {
|
||||||
!newPassword &&
|
!newPassword &&
|
||||||
user.emails &&
|
user.emails &&
|
||||||
user.emails[0].address === email &&
|
user.emails[0].address === email &&
|
||||||
!avatar.data &&
|
!avatar!.data &&
|
||||||
!customFieldsChanged
|
!customFieldsChanged
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleError = (e, func, action) => {
|
handleError = (e: any, func: string, action: string) => {
|
||||||
if (e.data && e.data.error.includes('[error-too-many-requests]')) {
|
if (e.data && e.data.error.includes('[error-too-many-requests]')) {
|
||||||
return showErrorAlert(e.data.error);
|
return showErrorAlert(e.data.error);
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ class ProfileView extends React.Component {
|
||||||
|
|
||||||
const { name, username, email, newPassword, currentPassword, avatar, customFields } = this.state;
|
const { name, username, email, newPassword, currentPassword, avatar, customFields } = this.state;
|
||||||
const { user, setUser } = this.props;
|
const { user, setUser } = this.props;
|
||||||
const params = {};
|
const params = {} as IParams;
|
||||||
|
|
||||||
// Name
|
// Name
|
||||||
if (user.name !== name) {
|
if (user.name !== name) {
|
||||||
|
@ -189,7 +189,7 @@ class ProfileView extends React.Component {
|
||||||
|
|
||||||
// currentPassword
|
// currentPassword
|
||||||
if (currentPassword) {
|
if (currentPassword) {
|
||||||
params.currentPassword = SHA256(currentPassword);
|
params.currentPassword = sha256(currentPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
const requirePassword = !!params.email || newPassword;
|
const requirePassword = !!params.email || newPassword;
|
||||||
|
@ -202,7 +202,7 @@ class ProfileView extends React.Component {
|
||||||
{ text: I18n.t('Cancel'), onPress: () => {}, style: 'cancel' },
|
{ text: I18n.t('Cancel'), onPress: () => {}, style: 'cancel' },
|
||||||
{
|
{
|
||||||
text: I18n.t('Save'),
|
text: I18n.t('Save'),
|
||||||
onPress: p => {
|
onPress: (p: string) => {
|
||||||
this.setState({ currentPassword: p });
|
this.setState({ currentPassword: p });
|
||||||
this.submit();
|
this.submit();
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,7 @@ class ProfileView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (avatar.url) {
|
if (avatar!.url) {
|
||||||
try {
|
try {
|
||||||
logEvent(events.PROFILE_SAVE_AVATAR);
|
logEvent(events.PROFILE_SAVE_AVATAR);
|
||||||
await RocketChat.setAvatarFromService(avatar);
|
await RocketChat.setAvatarFromService(avatar);
|
||||||
|
@ -283,7 +283,7 @@ class ProfileView extends React.Component {
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
logEvent(events.PROFILE_PICK_AVATAR);
|
logEvent(events.PROFILE_PICK_AVATAR);
|
||||||
const response = await ImagePicker.openPicker(options);
|
const response: Image = await ImagePicker.openPicker(options);
|
||||||
this.setAvatar({ url: response.path, data: `data:image/jpeg;base64,${response.data}`, service: 'upload' });
|
this.setAvatar({ url: response.path, data: `data:image/jpeg;base64,${response.data}`, service: 'upload' });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logEvent(events.PROFILE_PICK_AVATAR_F);
|
logEvent(events.PROFILE_PICK_AVATAR_F);
|
||||||
|
@ -291,12 +291,12 @@ class ProfileView extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pickImageWithURL = avatarUrl => {
|
pickImageWithURL = (avatarUrl: string) => {
|
||||||
logEvent(events.PROFILE_PICK_AVATAR_WITH_URL);
|
logEvent(events.PROFILE_PICK_AVATAR_WITH_URL);
|
||||||
this.setAvatar({ url: avatarUrl, data: avatarUrl, service: 'url' });
|
this.setAvatar({ url: avatarUrl, data: avatarUrl, service: 'url' });
|
||||||
};
|
};
|
||||||
|
|
||||||
renderAvatarButton = ({ key, child, onPress, disabled = false }) => {
|
renderAvatarButton = ({ key, child, onPress, disabled = false }: IAvatarButton) => {
|
||||||
const { theme } = this.props;
|
const { theme } = this.props;
|
||||||
return (
|
return (
|
||||||
<Touch
|
<Touch
|
||||||
|
@ -331,7 +331,7 @@ class ProfileView extends React.Component {
|
||||||
})}
|
})}
|
||||||
{this.renderAvatarButton({
|
{this.renderAvatarButton({
|
||||||
child: <CustomIcon name='link' size={30} color={themes[theme].bodyText} />,
|
child: <CustomIcon name='link' size={30} color={themes[theme].bodyText} />,
|
||||||
onPress: () => this.pickImageWithURL(avatarUrl),
|
onPress: () => this.pickImageWithURL(avatarUrl!),
|
||||||
disabled: !avatarUrl,
|
disabled: !avatarUrl,
|
||||||
key: 'profile-view-avatar-url-button'
|
key: 'profile-view-avatar-url-button'
|
||||||
})}
|
})}
|
||||||
|
@ -365,19 +365,20 @@ class ProfileView extends React.Component {
|
||||||
const parsedCustomFields = JSON.parse(Accounts_CustomFields);
|
const parsedCustomFields = JSON.parse(Accounts_CustomFields);
|
||||||
return Object.keys(parsedCustomFields).map((key, index, array) => {
|
return Object.keys(parsedCustomFields).map((key, index, array) => {
|
||||||
if (parsedCustomFields[key].type === 'select') {
|
if (parsedCustomFields[key].type === 'select') {
|
||||||
const options = parsedCustomFields[key].options.map(option => ({ label: option, value: option }));
|
const options = parsedCustomFields[key].options.map((option: string) => ({ label: option, value: option }));
|
||||||
return (
|
return (
|
||||||
<RNPickerSelect
|
<RNPickerSelect
|
||||||
key={key}
|
key={key}
|
||||||
items={options}
|
items={options}
|
||||||
onValueChange={value => {
|
onValueChange={value => {
|
||||||
const newValue = {};
|
const newValue: { [key: string]: string } = {};
|
||||||
newValue[key] = value;
|
newValue[key] = value;
|
||||||
this.setState({ customFields: { ...customFields, ...newValue } });
|
this.setState({ customFields: { ...customFields, ...newValue } });
|
||||||
}}
|
}}
|
||||||
value={customFields[key]}>
|
value={customFields[key]}>
|
||||||
<RCTextInput
|
<RCTextInput
|
||||||
inputRef={e => {
|
inputRef={e => {
|
||||||
|
// @ts-ignore
|
||||||
this[key] = e;
|
this[key] = e;
|
||||||
}}
|
}}
|
||||||
label={key}
|
label={key}
|
||||||
|
@ -393,6 +394,7 @@ class ProfileView extends React.Component {
|
||||||
return (
|
return (
|
||||||
<RCTextInput
|
<RCTextInput
|
||||||
inputRef={e => {
|
inputRef={e => {
|
||||||
|
// @ts-ignore
|
||||||
this[key] = e;
|
this[key] = e;
|
||||||
}}
|
}}
|
||||||
key={key}
|
key={key}
|
||||||
|
@ -400,12 +402,13 @@ class ProfileView extends React.Component {
|
||||||
placeholder={key}
|
placeholder={key}
|
||||||
value={customFields[key]}
|
value={customFields[key]}
|
||||||
onChangeText={value => {
|
onChangeText={value => {
|
||||||
const newValue = {};
|
const newValue: { [key: string]: string } = {};
|
||||||
newValue[key] = value;
|
newValue[key] = value;
|
||||||
this.setState({ customFields: { ...customFields, ...newValue } });
|
this.setState({ customFields: { ...customFields, ...newValue } });
|
||||||
}}
|
}}
|
||||||
onSubmitEditing={() => {
|
onSubmitEditing={() => {
|
||||||
if (array.length - 1 > index) {
|
if (array.length - 1 > index) {
|
||||||
|
// @ts-ignore
|
||||||
return this[array[index + 1]].focus();
|
return this[array[index + 1]].focus();
|
||||||
}
|
}
|
||||||
this.avatarUrl.focus();
|
this.avatarUrl.focus();
|
||||||
|
@ -421,6 +424,7 @@ class ProfileView extends React.Component {
|
||||||
|
|
||||||
logoutOtherLocations = () => {
|
logoutOtherLocations = () => {
|
||||||
logEvent(events.PL_OTHER_LOCATIONS);
|
logEvent(events.PL_OTHER_LOCATIONS);
|
||||||
|
// @ts-ignore
|
||||||
showConfirmationAlert({
|
showConfirmationAlert({
|
||||||
message: I18n.t('You_will_be_logged_out_from_other_locations'),
|
message: I18n.t('You_will_be_logged_out_from_other_locations'),
|
||||||
confirmationText: I18n.t('Logout'),
|
confirmationText: I18n.t('Logout'),
|
||||||
|
@ -469,7 +473,7 @@ class ProfileView extends React.Component {
|
||||||
label={I18n.t('Name')}
|
label={I18n.t('Name')}
|
||||||
placeholder={I18n.t('Name')}
|
placeholder={I18n.t('Name')}
|
||||||
value={name}
|
value={name}
|
||||||
onChangeText={value => this.setState({ name: value })}
|
onChangeText={(value: string) => this.setState({ name: value })}
|
||||||
onSubmitEditing={() => {
|
onSubmitEditing={() => {
|
||||||
this.username.focus();
|
this.username.focus();
|
||||||
}}
|
}}
|
||||||
|
@ -500,7 +504,7 @@ class ProfileView extends React.Component {
|
||||||
}}
|
}}
|
||||||
label={I18n.t('Email')}
|
label={I18n.t('Email')}
|
||||||
placeholder={I18n.t('Email')}
|
placeholder={I18n.t('Email')}
|
||||||
value={email}
|
value={email!}
|
||||||
onChangeText={value => this.setState({ email: value })}
|
onChangeText={value => this.setState({ email: value })}
|
||||||
onSubmitEditing={() => {
|
onSubmitEditing={() => {
|
||||||
this.newPassword.focus();
|
this.newPassword.focus();
|
||||||
|
@ -516,10 +520,11 @@ class ProfileView extends React.Component {
|
||||||
}}
|
}}
|
||||||
label={I18n.t('New_Password')}
|
label={I18n.t('New_Password')}
|
||||||
placeholder={I18n.t('New_Password')}
|
placeholder={I18n.t('New_Password')}
|
||||||
value={newPassword}
|
value={newPassword!}
|
||||||
onChangeText={value => this.setState({ newPassword: value })}
|
onChangeText={value => this.setState({ newPassword: value })}
|
||||||
onSubmitEditing={() => {
|
onSubmitEditing={() => {
|
||||||
if (Accounts_CustomFields && Object.keys(customFields).length) {
|
if (Accounts_CustomFields && Object.keys(customFields).length) {
|
||||||
|
// @ts-ignore
|
||||||
return this[Object.keys(customFields)[0]].focus();
|
return this[Object.keys(customFields)[0]].focus();
|
||||||
}
|
}
|
||||||
this.avatarUrl.focus();
|
this.avatarUrl.focus();
|
||||||
|
@ -537,7 +542,7 @@ class ProfileView extends React.Component {
|
||||||
}}
|
}}
|
||||||
label={I18n.t('Avatar_Url')}
|
label={I18n.t('Avatar_Url')}
|
||||||
placeholder={I18n.t('Avatar_Url')}
|
placeholder={I18n.t('Avatar_Url')}
|
||||||
value={avatarUrl}
|
value={avatarUrl!}
|
||||||
onChangeText={value => this.setState({ avatarUrl: value })}
|
onChangeText={value => this.setState({ avatarUrl: value })}
|
||||||
onSubmitEditing={this.submit}
|
onSubmitEditing={this.submit}
|
||||||
testID='profile-view-avatar-url'
|
testID='profile-view-avatar-url'
|
||||||
|
@ -568,7 +573,7 @@ class ProfileView extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = (state: any) => ({
|
||||||
user: getUserSelector(state),
|
user: getUserSelector(state),
|
||||||
Accounts_AllowEmailChange: state.settings.Accounts_AllowEmailChange,
|
Accounts_AllowEmailChange: state.settings.Accounts_AllowEmailChange,
|
||||||
Accounts_AllowPasswordChange: state.settings.Accounts_AllowPasswordChange,
|
Accounts_AllowPasswordChange: state.settings.Accounts_AllowPasswordChange,
|
||||||
|
@ -579,8 +584,8 @@ const mapStateToProps = state => ({
|
||||||
baseUrl: state.server.server
|
baseUrl: state.server.server
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = (dispatch: any) => ({
|
||||||
setUser: params => dispatch(setUserAction(params))
|
setUser: (params: any) => dispatch(setUserAction(params))
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(ProfileView));
|
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(ProfileView));
|
|
@ -0,0 +1,79 @@
|
||||||
|
import { StackNavigationProp } from '@react-navigation/stack';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export interface IUser {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
username: string;
|
||||||
|
emails: {
|
||||||
|
[index: number]: {
|
||||||
|
address: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
customFields: {
|
||||||
|
[index: string | number]: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IParams {
|
||||||
|
name: string;
|
||||||
|
username: string;
|
||||||
|
email: string | null;
|
||||||
|
newPassword: string;
|
||||||
|
currentPassword: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAvatarButton {
|
||||||
|
key: React.Key;
|
||||||
|
child: React.ReactNode;
|
||||||
|
onPress: Function;
|
||||||
|
disabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface INavigationOptions {
|
||||||
|
navigation: StackNavigationProp<any, 'ProfileView'>;
|
||||||
|
isMasterDetail?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IProfileViewProps {
|
||||||
|
user: IUser;
|
||||||
|
navigation: StackNavigationProp<any, 'ProfileView'>;
|
||||||
|
isMasterDetail?: boolean;
|
||||||
|
baseUrl: string;
|
||||||
|
Accounts_AllowEmailChange: boolean;
|
||||||
|
Accounts_AllowPasswordChange: boolean;
|
||||||
|
Accounts_AllowRealNameChange: boolean;
|
||||||
|
Accounts_AllowUserAvatarChange: boolean;
|
||||||
|
Accounts_AllowUsernameChange: boolean;
|
||||||
|
Accounts_CustomFields: string;
|
||||||
|
setUser: Function;
|
||||||
|
theme: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAvatar {
|
||||||
|
data: {} | string | null;
|
||||||
|
url?: string;
|
||||||
|
contentType?: string;
|
||||||
|
service?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IProfileViewState {
|
||||||
|
saving: boolean;
|
||||||
|
name: string;
|
||||||
|
username: string;
|
||||||
|
email: string | null;
|
||||||
|
newPassword: string | null;
|
||||||
|
currentPassword: string | null;
|
||||||
|
avatarUrl: string | null;
|
||||||
|
avatar: IAvatar;
|
||||||
|
avatarSuggestions: {
|
||||||
|
[service: string]: {
|
||||||
|
url: string;
|
||||||
|
blob: string;
|
||||||
|
contentType: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
customFields: {
|
||||||
|
[key: string | number]: string;
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue