Chore: Hooks app/views/SetUsernameView (#4488)

* Chore: Hooks app/views/SetUsernameView

* semantic change of loading state

Co-authored-by: Gleidson Daniel <gleidson10daniel@hotmail.com>
This commit is contained in:
Reinaldo Neto 2022-09-06 13:53:21 -03:00 committed by GitHub
parent e3a99a93e4
commit eabb9f157c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 80 additions and 107 deletions

View File

@ -1,27 +1,28 @@
import { RouteProp } from '@react-navigation/native'; import { useNavigation } from '@react-navigation/native';
import { StackNavigationOptions, StackNavigationProp } from '@react-navigation/stack'; import { StackNavigationProp } from '@react-navigation/stack';
import React from 'react'; import React, { useEffect, useLayoutEffect, useState } from 'react';
import { ScrollView, StyleSheet, Text } from 'react-native'; import { ScrollView, StyleSheet, Text } from 'react-native';
import Orientation from 'react-native-orientation-locker'; import Orientation from 'react-native-orientation-locker';
import { connect } from 'react-redux'; import { useDispatch } from 'react-redux';
import { Dispatch } from 'redux'; import { useForm } from 'react-hook-form';
import * as yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import { loginRequest } from '../actions/login'; import { loginRequest } from '../actions/login';
import { themes } from '../lib/constants';
import Button from '../containers/Button'; import Button from '../containers/Button';
import SafeAreaView from '../containers/SafeAreaView'; import SafeAreaView from '../containers/SafeAreaView';
import StatusBar from '../containers/StatusBar'; import StatusBar from '../containers/StatusBar';
import { FormTextInput } from '../containers/TextInput'; import { ControlledFormTextInput } from '../containers/TextInput';
import { IApplicationState } from '../definitions';
import { SetUsernameStackParamList } from '../definitions/navigationTypes'; import { SetUsernameStackParamList } from '../definitions/navigationTypes';
import I18n from '../i18n'; import I18n from '../i18n';
import KeyboardView from '../containers/KeyboardView'; import KeyboardView from '../containers/KeyboardView';
import { getUserSelector } from '../selectors/login'; import { getUserSelector } from '../selectors/login';
import { TSupportedThemes, withTheme } from '../theme'; import { useTheme } from '../theme';
import { isTablet, showErrorAlert } from '../lib/methods/helpers'; import { isTablet, showErrorAlert } from '../lib/methods/helpers';
import scrollPersistTaps from '../lib/methods/helpers/scrollPersistTaps'; import scrollPersistTaps from '../lib/methods/helpers/scrollPersistTaps';
import sharedStyles from './Styles'; import sharedStyles from './Styles';
import { Services } from '../lib/services'; import { Services } from '../lib/services';
import { useAppSelector } from '../lib/hooks';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
loginTitle: { loginTitle: {
@ -30,100 +31,78 @@ const styles = StyleSheet.create({
} }
}); });
interface ISetUsernameViewState { interface ISubmit {
username: string; username: string;
saving: boolean;
} }
interface ISetUsernameViewProps { const schema = yup.object().shape({
navigation: StackNavigationProp<SetUsernameStackParamList, 'SetUsernameView'>; username: yup.string().required()
route: RouteProp<SetUsernameStackParamList, 'SetUsernameView'>;
server: string;
userId: string;
token: string;
theme: TSupportedThemes;
dispatch: Dispatch;
}
class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernameViewState> {
static navigationOptions = ({ route }: Pick<ISetUsernameViewProps, 'route'>): StackNavigationOptions => ({
title: route.params?.title
}); });
constructor(props: ISetUsernameViewProps) { const SetUsernameView = () => {
super(props); const {
this.state = { control,
username: '', handleSubmit,
saving: false formState: { isValid },
}; setValue
const { server } = this.props; } = useForm<ISubmit>({ mode: 'onChange', resolver: yupResolver(schema) });
props.navigation.setOptions({ title: server }); const [loading, setLoading] = useState(false);
const { colors } = useTheme();
const dispatch = useDispatch();
const { server, token } = useAppSelector(state => ({ server: state.server.server, token: getUserSelector(state).token }));
const navigation = useNavigation<StackNavigationProp<SetUsernameStackParamList, 'SetUsernameView'>>();
useLayoutEffect(() => {
navigation.setOptions({ title: server });
if (!isTablet) { if (!isTablet) {
Orientation.lockToPortrait(); Orientation.lockToPortrait();
} }
} }, [navigation, server]);
async componentDidMount() { useEffect(() => {
const init = async () => {
const suggestion = await Services.getUsernameSuggestion(); const suggestion = await Services.getUsernameSuggestion();
if (suggestion.success) { if (suggestion.success) {
this.setState({ username: suggestion.result }); setValue('username', suggestion.result, { shouldValidate: true });
}
} }
};
init();
}, []);
shouldComponentUpdate(nextProps: ISetUsernameViewProps, nextState: ISetUsernameViewState) { const submit = async ({ username }: ISubmit) => {
const { username, saving } = this.state; if (!isValid) {
const { theme } = this.props;
if (nextProps.theme !== theme) {
return true;
}
if (nextState.username !== username) {
return true;
}
if (nextState.saving !== saving) {
return true;
}
return false;
}
submit = async () => {
const { username } = this.state;
const { dispatch, token } = this.props;
if (!username.trim()) {
return; return;
} }
setLoading(true);
this.setState({ saving: true });
try { try {
await Services.saveUserProfile({ username }); await Services.saveUserProfile({ username });
dispatch(loginRequest({ resume: token })); dispatch(loginRequest({ resume: token }));
} catch (e: any) { } catch (e: any) {
showErrorAlert(e.message, I18n.t('Oops')); showErrorAlert(e.message, I18n.t('Oops'));
} }
this.setState({ saving: false }); setLoading(false);
}; };
render() {
const { username, saving } = this.state;
const { theme } = this.props;
return ( return (
<KeyboardView style={{ backgroundColor: themes[theme].auxiliaryBackground }} contentContainerStyle={sharedStyles.container}> <KeyboardView style={{ backgroundColor: colors.auxiliaryBackground }} contentContainerStyle={sharedStyles.container}>
<StatusBar /> <StatusBar />
<ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}> <ScrollView {...scrollPersistTaps} contentContainerStyle={sharedStyles.containerScrollView}>
<SafeAreaView testID='set-username-view'> <SafeAreaView testID='set-username-view'>
<Text style={[sharedStyles.loginTitle, sharedStyles.textBold, styles.loginTitle, { color: themes[theme].titleText }]}> <Text style={[sharedStyles.loginTitle, sharedStyles.textBold, styles.loginTitle, { color: colors.titleText }]}>
{I18n.t('Username')} {I18n.t('Username')}
</Text> </Text>
<Text style={[sharedStyles.loginSubtitle, sharedStyles.textRegular, { color: themes[theme].titleText }]}> <Text style={[sharedStyles.loginSubtitle, sharedStyles.textRegular, { color: colors.titleText }]}>
{I18n.t('Set_username_subtitle')} {I18n.t('Set_username_subtitle')}
</Text> </Text>
<FormTextInput <ControlledFormTextInput
control={control}
name='username'
autoFocus autoFocus
placeholder={I18n.t('Username')} placeholder={I18n.t('Username')}
returnKeyType='send' returnKeyType='send'
onChangeText={value => this.setState({ username: value })} onSubmitEditing={handleSubmit(submit)}
value={username}
onSubmitEditing={this.submit}
testID='set-username-view-input' testID='set-username-view-input'
clearButtonMode='while-editing' clearButtonMode='while-editing'
containerStyle={sharedStyles.inputLastChild} containerStyle={sharedStyles.inputLastChild}
@ -131,21 +110,15 @@ class SetUsernameView extends React.Component<ISetUsernameViewProps, ISetUsernam
<Button <Button
title={I18n.t('Register')} title={I18n.t('Register')}
type='primary' type='primary'
onPress={this.submit} onPress={handleSubmit(submit)}
testID='set-username-view-submit' testID='set-username-view-submit'
disabled={!username} disabled={!isValid}
loading={saving} loading={loading}
/> />
</SafeAreaView> </SafeAreaView>
</ScrollView> </ScrollView>
</KeyboardView> </KeyboardView>
); );
} };
}
const mapStateToProps = (state: IApplicationState) => ({ export default SetUsernameView;
server: state.server.server,
token: getUserSelector(state).token
});
export default connect(mapStateToProps)(withTheme(SetUsernameView));