♻ Refactor using react-hook-form
This commit is contained in:
1 parent
1d66f1dfe3
commit
a6ae37cdac
3 files changed
+114
-221
No files matched your search
@@ -28,6 +28,7 @@
|
||||
"native-base": "^3.2.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^17.0.2",
|
||||
"react-hook-form": "^7.17.1",
|
||||
"react-is": "^17.0.2",
|
||||
"react-native": "0.66.0-rc.4",
|
||||
"react-native-confetti": "^0.1.0",
|
||||
|
||||
@@ -1,245 +1,132 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import React from 'react';
|
||||
import { Container, Input, Spinner, Button, Text, Icon, Toast, FormControl } from 'native-base';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import * as EmailValidator from 'email-validator';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
|
||||
import theme from '../../theme';
|
||||
import useUserRegister from './useUserRegister';
|
||||
|
||||
const FormInput = ({
|
||||
control,
|
||||
errors,
|
||||
name,
|
||||
label,
|
||||
rules = {
|
||||
required: true,
|
||||
},
|
||||
returnKeyType = 'next',
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
<Controller
|
||||
control={control}
|
||||
rules={rules}
|
||||
render={({ field: { onChange, onBlur, value } }) => (
|
||||
<FormControl isInvalid={errors.firstName}>
|
||||
<FormControl.Label>{label}</FormControl.Label>
|
||||
<Input returnKeyType={returnKeyType} onChangeText={onChange} onBlur={onBlur} value={value} {...rest} />
|
||||
{errors[name] && (
|
||||
<View>
|
||||
<Text>kan ikke være tomt.</Text>
|
||||
<Icon name="close-circle" />
|
||||
</View>
|
||||
)}
|
||||
</FormControl>
|
||||
)}
|
||||
name={name}
|
||||
defaultValue=""
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const Registerbutton = ({ isDisabled, onPress }) => (
|
||||
<Button full disabled={isDisabled} onPress={onPress} style={styles.registerButton}>
|
||||
<Text>Registrer meg</Text>
|
||||
</Button>
|
||||
);
|
||||
|
||||
const NonFieldErrors = ({ errors }) => {
|
||||
if (Object.keys(errors).length !== 0 && 'non_field_errors' in errors) {
|
||||
const err = errors.non_field_errors;
|
||||
const errorFormatted = err ? err[0] : 'Kunne ikke registrere bruker, prøv igjen...';
|
||||
return (
|
||||
<View style={styles.errorBox}>
|
||||
<Text style={styles.errorMessage}>{errorFormatted}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
if (Object.keys(errors).length !== 0 && 'detail' in errors) {
|
||||
const err = errors.detail;
|
||||
const errorFormatted = err || 'Kunne ikke registrere bruker, prøv igjen...';
|
||||
return (
|
||||
<View style={styles.errorBox}>
|
||||
<Text style={styles.errorMessage}>{errorFormatted}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return <View style={styles.errorBox} />;
|
||||
};
|
||||
|
||||
const UserRegister = () => {
|
||||
const [firstName, setFirstName] = useState('');
|
||||
const [lastName, setLastName] = useState('');
|
||||
const [email, setEmail] = useState('');
|
||||
const [phoneNumber, setPhoneNumber] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [errors, setErrors] = useState({});
|
||||
const [touched, setTouched] = useState(new Set());
|
||||
const { isRegisteringUser, onRegisterPress } = useUserRegister();
|
||||
// TODO: email validation
|
||||
// TODO: focus next field
|
||||
|
||||
const emailInputRef = useRef();
|
||||
const lastNameInputRef = useRef();
|
||||
const phoneInputRef = useRef();
|
||||
const passwordInputRef = useRef();
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
formState: { errors, isDirty, isValid },
|
||||
} = useForm();
|
||||
const isDisabled = !isDirty || isRegisteringUser || !isValid;
|
||||
const onSubmit = (data) => {
|
||||
console.log(data);
|
||||
// if (!canSubmitForm()) {
|
||||
// Toast.show({
|
||||
// text: 'Noen av feltene er ikke fylt ut riktig',
|
||||
// position: 'bottom',
|
||||
// buttonText: 'OK',
|
||||
// duration: 1500,
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
|
||||
const validateForm = (triggeredBy) => {
|
||||
const values = { firstName, lastName, email, phoneNumber, password };
|
||||
|
||||
const freshErrors = { ...errors };
|
||||
const freshTouched = new Set(touched).add(triggeredBy);
|
||||
|
||||
/* No empty fields */
|
||||
Object.entries(values).forEach(([key, value]) => {
|
||||
if (value === '') {
|
||||
freshErrors[key] = 'kan ikke være tomt';
|
||||
} else if (key === 'email' && !EmailValidator.validate(value)) {
|
||||
freshErrors[key] = 'er ikke en gyldig e-post';
|
||||
} else {
|
||||
delete freshErrors[key];
|
||||
}
|
||||
});
|
||||
setErrors(freshErrors);
|
||||
setTouched(freshTouched);
|
||||
};
|
||||
|
||||
const fieldHasError = (field) => {
|
||||
return touched.has(field) && field in errors;
|
||||
};
|
||||
|
||||
const canSubmitForm = () => {
|
||||
return Object.keys(errors).length === 0;
|
||||
};
|
||||
|
||||
// useEffect(() => {
|
||||
// if (prevRegisterError !== registerError) {
|
||||
// setErrors(registerError);
|
||||
// }
|
||||
// }, []);
|
||||
|
||||
const showFieldError = (field) => {
|
||||
if (!fieldHasError(field)) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<FormControl style={styles.errorText}>
|
||||
<Text style={styles.errorMessage}>{errors[field]}</Text>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
const firstNameInput = () => {
|
||||
return (
|
||||
<FormControl isInvalid={fieldHasError('firstName')}>
|
||||
<FormControl.Label>Fornavn</FormControl.Label>
|
||||
<Input
|
||||
autoFocus={true}
|
||||
returnKeyType="next"
|
||||
onChangeText={(value) => {
|
||||
setFirstName(value);
|
||||
validateForm('firstName');
|
||||
}}
|
||||
onSubmitEditing={() => {
|
||||
lastNameInputRef.current.focus();
|
||||
}}
|
||||
value={firstName}
|
||||
/>
|
||||
{fieldHasError('firstName') && <Icon name="close-circle" />}
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
const lastNameInput = () => {
|
||||
return (
|
||||
<FormControl isInvalid={fieldHasError('lastName')}>
|
||||
<FormControl.Label>Etternavn</FormControl.Label>
|
||||
<Input
|
||||
ref={lastNameInputRef}
|
||||
returnKeyType="next"
|
||||
onChangeText={(value) => {
|
||||
setLastName(value);
|
||||
validateForm('lastName');
|
||||
}}
|
||||
onSubmitEditing={() => {
|
||||
emailInputRef.current.focus();
|
||||
}}
|
||||
value={lastName}
|
||||
/>
|
||||
{fieldHasError('lastName') && <Icon name="close-circle" />}
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
const emailInput = () => {
|
||||
return (
|
||||
<FormControl isInvalid={fieldHasError('email')}>
|
||||
<FormControl.Label>E-post</FormControl.Label>
|
||||
<Input
|
||||
ref={emailInputRef}
|
||||
keyboardType="email-address"
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
returnKeyType="next"
|
||||
onChangeText={(value) => {
|
||||
setEmail(value);
|
||||
validateForm('email');
|
||||
}}
|
||||
onSubmitEditing={() => {
|
||||
phoneInputRef.current.focus();
|
||||
}}
|
||||
value={email}
|
||||
/>
|
||||
{fieldHasError('email') && <Icon name="close-circle" />}
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
const phoneNumberInput = () => {
|
||||
return (
|
||||
<FormControl isInvalid={fieldHasError('phoneNumber')}>
|
||||
<FormControl.Label>Mobilnummer</FormControl.Label>
|
||||
<Input
|
||||
ref={phoneInputRef}
|
||||
returnKeyType="next"
|
||||
keyboardType="phone-pad"
|
||||
onChangeText={(value) => {
|
||||
setPhoneNumber(value);
|
||||
validateForm('phoneNumber');
|
||||
}}
|
||||
onSubmitEditing={() => {
|
||||
passwordInputRef.current.focus();
|
||||
}}
|
||||
value={phoneNumber}
|
||||
/>
|
||||
{fieldHasError('phoneNumber') && <Icon name="close-circle" />}
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
const passwordInput = () => {
|
||||
return (
|
||||
<FormControl isInvalid={fieldHasError('password')}>
|
||||
<FormControl.Label>Passord</FormControl.Label>
|
||||
<Input
|
||||
ref={passwordInputRef}
|
||||
secureTextEntry={true}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
onChangeText={(value) => {
|
||||
setPassword(value);
|
||||
validateForm('password');
|
||||
}}
|
||||
onSubmitEditing={onRegisterPress}
|
||||
value={password}
|
||||
/>
|
||||
{fieldHasError('password') && <Icon name="close-circle" />}
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
const showNonFieldError = () => {
|
||||
if (Object.keys(errors).length !== 0 && 'non_field_errors' in errors) {
|
||||
const err = errors.non_field_errors;
|
||||
const errorFormatted = err ? err[0] : 'Kunne ikke registrere bruker, prøv igjen...';
|
||||
return (
|
||||
<View style={styles.errorBox}>
|
||||
<Text style={styles.errorMessage}>{errorFormatted}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
if (Object.keys(errors).length !== 0 && 'detail' in errors) {
|
||||
const err = errors.detail;
|
||||
const errorFormatted = err || 'Kunne ikke registrere bruker, prøv igjen...';
|
||||
return (
|
||||
<View style={styles.errorBox}>
|
||||
<Text style={styles.errorMessage}>{errorFormatted}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return <View style={styles.errorBox} />;
|
||||
};
|
||||
|
||||
const onSubmit = () => {
|
||||
if (!canSubmitForm()) {
|
||||
Toast.show({
|
||||
text: 'Noen av feltene er ikke fylt ut riktig',
|
||||
position: 'bottom',
|
||||
buttonText: 'OK',
|
||||
duration: 1500,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
onRegisterPress(firstName, lastName, email, phoneNumber, password);
|
||||
};
|
||||
|
||||
const registerbutton = () => {
|
||||
const isDisabled = touched.size === 0 || isRegisteringUser || !canSubmitForm();
|
||||
|
||||
return (
|
||||
<Button full disabled={isDisabled} onPress={onSubmit} style={styles.registerButton}>
|
||||
<Text>Registrer meg</Text>
|
||||
</Button>
|
||||
);
|
||||
// onRegisterPress(firstName, lastName, email, phoneNumber, password);
|
||||
};
|
||||
|
||||
return (
|
||||
<Container style={styles.container}>
|
||||
<View style={styles.card}>
|
||||
{firstNameInput()}
|
||||
{showFieldError('firstName')}
|
||||
{lastNameInput()}
|
||||
{showFieldError('lastName')}
|
||||
{emailInput()}
|
||||
{showFieldError('email')}
|
||||
{phoneNumberInput()}
|
||||
{showFieldError('phoneNumber')}
|
||||
{passwordInput()}
|
||||
{showFieldError('password')}
|
||||
{showNonFieldError()}
|
||||
{registerbutton()}
|
||||
<FormInput name="firstName" label="Fornavn" control={control} errors={errors} autoFocus={true} />
|
||||
<FormInput name="lastName" label="Etternavn" control={control} errors={errors} />
|
||||
<FormInput
|
||||
name="email"
|
||||
label="E-post"
|
||||
control={control}
|
||||
errors={errors}
|
||||
keyboardType="email-address"
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
/>
|
||||
<FormInput name="phoneNumber" label="Mobilnummer" control={control} errors={errors} keyboardType="phone-pad" />
|
||||
<FormInput
|
||||
name="password"
|
||||
label="Passord"
|
||||
control={control}
|
||||
errors={errors}
|
||||
secureTextEntry={true}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
/>
|
||||
<NonFieldErrors errors={errors} />
|
||||
<Registerbutton isDisabled={isDisabled} onPress={handleSubmit(onSubmit)} />
|
||||
{isRegisteringUser && <Spinner color="#f58220" />}
|
||||
</View>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserRegister;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
@@ -7495,6 +7495,11 @@ react-dom@^17.0.2:
|
||||
object-assign "^4.1.1"
|
||||
scheduler "^0.20.2"
|
||||
|
||||
react-hook-form@^7.17.1:
|
||||
version "7.17.1"
|
||||
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.17.1.tgz#dc257a5e34b3c353460ecdbbba5236e066cf80b1"
|
||||
integrity sha512-9nQ+qKFHFpnWzQHdDh6F4Egxa8iJkue1KU921F8qqeyUVbPPjgQZDXaQyNHABEYjRh0ndjTI24GDA+lwm2lQdg==
|
||||
|
||||
"react-is@^16.12.0 || ^17.0.0", react-is@^17.0.1, react-is@^17.0.2:
|
||||
version "17.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
|
||||
|
||||
Reference in new issue
Block a user