Chore: Evaluate ProfileView - Typescript (#4091)

This commit is contained in:
Alex Junior 2022-05-06 23:11:07 -03:00 committed by GitHub
parent 1346154b65
commit 55d66c85db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 121 additions and 122 deletions

View File

@ -0,0 +1,31 @@
import React from 'react';
export interface IProfileParams {
name: string;
username: string;
email: string | null;
newPassword: string;
currentPassword: string;
}
export interface IAvatarButton {
key: string;
child: React.ReactNode;
onPress: () => void;
disabled: boolean;
}
export interface IAvatar {
data: {} | string | null;
url?: string;
contentType?: string;
service?: any;
}
export interface IAvatarSuggestion {
[service: string]: {
url: string;
blob: string;
contentType: string;
};
}

View File

@ -1,69 +0,0 @@
import { StackNavigationProp } from '@react-navigation/stack';
import React from 'react';
import { TSupportedThemes } from '../theme';
import { ProfileStackParamList } from '../stacks/types';
import { IUser } from './IUser';
export interface IParams {
name: string;
username: string;
email: string | null;
newPassword: string;
currentPassword: string;
}
export interface IAvatarButton {
key: string;
child: React.ReactNode;
onPress: () => void;
disabled: boolean;
}
export interface INavigationOptions {
navigation: StackNavigationProp<ProfileStackParamList, 'ProfileView'>;
isMasterDetail?: boolean;
}
export interface IProfileViewProps {
user: IUser;
baseUrl: string;
Accounts_AllowEmailChange: boolean;
Accounts_AllowPasswordChange: boolean;
Accounts_AllowRealNameChange: boolean;
Accounts_AllowUserAvatarChange: boolean;
Accounts_AllowUsernameChange: boolean;
Accounts_CustomFields: string;
setUser: Function;
theme: TSupportedThemes;
}
export interface IAvatar {
data: {} | string | null;
url?: string;
contentType?: string;
service?: any;
}
export interface IAvatarSuggestion {
[service: string]: {
url: string;
blob: string;
contentType: string;
};
}
export interface IProfileViewState {
saving: boolean;
name: string;
username: string;
email: string | null;
newPassword: string | null;
currentPassword: string | null;
avatarUrl: string | null;
avatar: IAvatar;
avatarSuggestions: IAvatarSuggestion;
customFields: {
[key: string | number]: string;
};
}

View File

@ -28,6 +28,7 @@ export * from './IUrl';
export * from './ICredentials';
export * from './ISearch';
export * from './TUserStatus';
export * from './IProfile';
export interface IBaseScreen<T extends Record<string, object | undefined>, S extends string> {
navigation: StackNavigationProp<T, S>;

View File

@ -1,4 +1,4 @@
import { IParams } from '../../IProfileViewInterfaces';
import { IProfileParams } from '../../IProfile';
import type { ITeam } from '../../ITeam';
import type { IUser } from '../../IUser';
import { INotificationPreferences, IUserPreferences, IUserRegistered } from '../../IUser';
@ -39,7 +39,10 @@ export type UsersEndpoints = {
POST: (params: { status: string; message: string }) => {};
};
'users.updateOwnBasicInfo': {
POST: (params: { data: IParams | Pick<IParams, 'username'>; customFields?: { [key: string | number]: string } }) => {
POST: (params: {
data: IProfileParams | Pick<IProfileParams, 'username'>;
customFields?: { [key: string | number]: string };
}) => {
user: IUser;
};
};

View File

@ -5,9 +5,10 @@ import {
IRoom,
IRoomNotifications,
SubscriptionType,
IUser
IUser,
IAvatarSuggestion,
IProfileParams
} from '../../definitions';
import { IAvatarSuggestion, IParams } from '../../definitions/IProfileViewInterfaces';
import { ISpotlight } from '../../definitions/ISpotlight';
import { TEAM_TYPE } from '../../definitions/ITeam';
import { Encryption } from '../encryption';
@ -561,7 +562,10 @@ export const saveRoomSettings = (
// RC 0.55.0
sdk.methodCallWrapper('saveRoomSettings', rid, params);
export const saveUserProfile = (data: IParams | Pick<IParams, 'username'>, customFields?: { [key: string | number]: string }) =>
export const saveUserProfile = (
data: IProfileParams | Pick<IProfileParams, 'username'>,
customFields?: { [key: string | number]: string }
) =>
// RC 0.62.2
sdk.post('users.updateOwnBasicInfo', { data, customFields });

View File

@ -1,5 +1,5 @@
import React from 'react';
import { Keyboard, ScrollView, View } from 'react-native';
import { Keyboard, ScrollView, TextInput, View } from 'react-native';
import { connect } from 'react-redux';
import prompt from 'react-native-prompt-android';
import { sha256 } from 'js-sha256';
@ -21,34 +21,62 @@ import log, { events, logEvent } from '../../utils/log';
import I18n from '../../i18n';
import Button from '../../containers/Button';
import Avatar from '../../containers/Avatar';
import { setUser as setUserAction } from '../../actions/login';
import { setUser } from '../../actions/login';
import { CustomIcon } from '../../containers/CustomIcon';
import * as HeaderButton from '../../containers/HeaderButton';
import StatusBar from '../../containers/StatusBar';
import { themes } from '../../lib/constants';
import { withTheme } from '../../theme';
import { TSupportedThemes, withTheme } from '../../theme';
import { getUserSelector } from '../../selectors/login';
import SafeAreaView from '../../containers/SafeAreaView';
import styles from './styles';
import { ProfileStackParamList } from '../../stacks/types';
import { Services } from '../../lib/services';
import {
IApplicationState,
IAvatar,
IAvatarButton,
INavigationOptions,
IParams,
IProfileViewProps,
IProfileViewState
} from '../../definitions/IProfileViewInterfaces';
import { IUser } from '../../definitions';
import { Services } from '../../lib/services';
IAvatarSuggestion,
IBaseScreen,
IProfileParams,
IUser
} from '../../definitions';
interface IProfileViewProps extends IBaseScreen<ProfileStackParamList, 'ProfileView'> {
user: IUser;
baseUrl: string;
Accounts_AllowEmailChange: boolean;
Accounts_AllowPasswordChange: boolean;
Accounts_AllowRealNameChange: boolean;
Accounts_AllowUserAvatarChange: boolean;
Accounts_AllowUsernameChange: boolean;
Accounts_CustomFields: string;
theme: TSupportedThemes;
}
interface IProfileViewState {
saving: boolean;
name: string;
username: string;
email: string | null;
newPassword: string | null;
currentPassword: string | null;
avatarUrl: string | null;
avatar: IAvatar;
avatarSuggestions: IAvatarSuggestion;
customFields: {
[key: string | number]: string;
};
}
class ProfileView extends React.Component<IProfileViewProps, IProfileViewState> {
private name: any;
private username: any;
private email: any;
private avatarUrl: any;
private newPassword: any;
private name?: TextInput | null;
private username?: TextInput | null;
private email?: TextInput;
private avatarUrl?: TextInput;
private newPassword?: TextInput;
static navigationOptions = ({ navigation, isMasterDetail }: INavigationOptions) => {
static navigationOptions = ({ navigation, isMasterDetail }: IProfileViewProps) => {
const options: StackNavigationOptions = {
title: I18n.t('Profile')
};
@ -150,7 +178,7 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
!newPassword &&
user.emails &&
user.emails[0].address === email &&
!avatar!.data &&
!avatar.data &&
!customFieldsChanged
);
};
@ -172,8 +200,8 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
this.setState({ saving: true });
const { name, username, email, newPassword, currentPassword, avatar, customFields } = this.state;
const { user, setUser } = this.props;
const params = {} as IParams;
const { user, dispatch } = this.props;
const params = {} as IProfileParams;
// Name
if (user.name !== name) {
@ -225,7 +253,7 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
}
try {
if (avatar!.url) {
if (avatar.url) {
try {
logEvent(events.PROFILE_SAVE_AVATAR);
await Services.setAvatarFromService(avatar);
@ -241,9 +269,9 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
if (result.success) {
logEvent(events.PROFILE_SAVE_CHANGES);
if (customFields) {
setUser({ customFields, ...params });
dispatch(setUser({ customFields, ...params }));
} else {
setUser({ ...params });
dispatch(setUser({ ...params }));
}
EventEmitter.emit(LISTENER, { message: I18n.t('Profile_saved_successfully') });
this.init();
@ -339,7 +367,7 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
})}
{this.renderAvatarButton({
child: <CustomIcon name='link' size={30} color={themes[theme].bodyText} />,
onPress: () => this.pickImageWithURL(avatarUrl!),
onPress: () => (avatarUrl ? this.pickImageWithURL(avatarUrl) : null),
disabled: !avatarUrl,
key: 'profile-view-avatar-url-button'
})}
@ -419,7 +447,7 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
// @ts-ignore
return this[array[index + 1]].focus();
}
this.avatarUrl.focus();
this.avatarUrl?.focus();
}}
theme={theme}
/>
@ -482,7 +510,7 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
value={name}
onChangeText={(value: string) => this.setState({ name: value })}
onSubmitEditing={() => {
this.username.focus();
this.username?.focus();
}}
testID='profile-view-name'
theme={theme}
@ -498,7 +526,7 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
value={username}
onChangeText={value => this.setState({ username: value })}
onSubmitEditing={() => {
this.email.focus();
this.email?.focus();
}}
testID='profile-view-username'
theme={theme}
@ -507,14 +535,16 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
editable={Accounts_AllowEmailChange}
inputStyle={[!Accounts_AllowEmailChange && styles.disabled]}
inputRef={e => {
if (e) {
this.email = e;
}
}}
label={I18n.t('Email')}
placeholder={I18n.t('Email')}
value={email!}
value={email || undefined}
onChangeText={value => this.setState({ email: value })}
onSubmitEditing={() => {
this.newPassword.focus();
this.newPassword?.focus();
}}
testID='profile-view-email'
theme={theme}
@ -523,18 +553,20 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
editable={Accounts_AllowPasswordChange}
inputStyle={[!Accounts_AllowPasswordChange && styles.disabled]}
inputRef={e => {
if (e) {
this.newPassword = e;
}
}}
label={I18n.t('New_Password')}
placeholder={I18n.t('New_Password')}
value={newPassword!}
value={newPassword || undefined}
onChangeText={value => this.setState({ newPassword: value })}
onSubmitEditing={() => {
if (Accounts_CustomFields && Object.keys(customFields).length) {
// @ts-ignore
return this[Object.keys(customFields)[0]].focus();
}
this.avatarUrl.focus();
this.avatarUrl?.focus();
}}
secureTextEntry
testID='profile-view-new-password'
@ -545,11 +577,13 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
editable={Accounts_AllowUserAvatarChange}
inputStyle={[!Accounts_AllowUserAvatarChange && styles.disabled]}
inputRef={e => {
if (e) {
this.avatarUrl = e;
}
}}
label={I18n.t('Avatar_Url')}
placeholder={I18n.t('Avatar_Url')}
value={avatarUrl!}
value={avatarUrl || undefined}
onChangeText={value => this.setState({ avatarUrl: value })}
onSubmitEditing={this.submit}
testID='profile-view-avatar-url'
@ -580,19 +614,15 @@ class ProfileView extends React.Component<IProfileViewProps, IProfileViewState>
}
}
const mapStateToProps = (state: any) => ({
const mapStateToProps = (state: IApplicationState) => ({
user: getUserSelector(state),
Accounts_AllowEmailChange: state.settings.Accounts_AllowEmailChange,
Accounts_AllowPasswordChange: state.settings.Accounts_AllowPasswordChange,
Accounts_AllowRealNameChange: state.settings.Accounts_AllowRealNameChange,
Accounts_AllowUserAvatarChange: state.settings.Accounts_AllowUserAvatarChange,
Accounts_AllowUsernameChange: state.settings.Accounts_AllowUsernameChange,
Accounts_CustomFields: state.settings.Accounts_CustomFields,
Accounts_AllowEmailChange: state.settings.Accounts_AllowEmailChange as boolean,
Accounts_AllowPasswordChange: state.settings.Accounts_AllowPasswordChange as boolean,
Accounts_AllowRealNameChange: state.settings.Accounts_AllowRealNameChange as boolean,
Accounts_AllowUserAvatarChange: state.settings.Accounts_AllowUserAvatarChange as boolean,
Accounts_AllowUsernameChange: state.settings.Accounts_AllowUsernameChange as boolean,
Accounts_CustomFields: state.settings.Accounts_CustomFields as string,
baseUrl: state.server.server
});
const mapDispatchToProps = (dispatch: any) => ({
setUser: (params: any) => dispatch(setUserAction(params))
});
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(ProfileView));
export default connect(mapStateToProps)(withTheme(ProfileView));

View File

@ -16,7 +16,7 @@ import StatusBar from '../../containers/StatusBar';
import RCTextInput from '../../containers/TextInput';
import { LISTENER } from '../../containers/Toast';
import { MultiSelect } from '../../containers/UIKit/MultiSelect';
import { IApplicationState, IBaseScreen, ISubscription, SubscriptionType, TSubscriptionModel } from '../../definitions';
import { IApplicationState, IBaseScreen, ISubscription, SubscriptionType, TSubscriptionModel, IAvatar } from '../../definitions';
import { ERoomType } from '../../definitions/ERoomType';
import I18n from '../../i18n';
import database from '../../lib/database';
@ -32,7 +32,6 @@ import log, { events, logEvent } from '../../utils/log';
import { MessageTypeValues } from '../../utils/messageTypes';
import random from '../../utils/random';
import scrollPersistTaps from '../../utils/scrollPersistTaps';
import { IAvatar } from '../../definitions/IProfileViewInterfaces';
import sharedStyles from '../Styles';
import styles from './styles';
import SwitchContainer from './SwitchContainer';