Skip to content

Commit

Permalink
React Hook Form Migration and Bootstrap Fixes (#191)
Browse files Browse the repository at this point in the history
* Bootstrap changes and fixes, see CHANGELOG

* Disabled Dark Mode for now

* Updated CHANGELOG and bootstrap version

* Updated auto_assign group

* Fixed not working onBlur
  • Loading branch information
Santiago Fernández authored May 13, 2021
1 parent d394acd commit f99a7ba
Show file tree
Hide file tree
Showing 13 changed files with 88 additions and 42 deletions.
4 changes: 2 additions & 2 deletions .github/auto_assign.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ addAssignees: true
reviewers:
- sfernandez11
- guidoprinc
- mcavo
- mattgle

# A number of reviewers added to the pull request
# Set 0 to add all the reviewers (default: 0)
Expand All @@ -18,7 +18,7 @@ numberOfReviewers: 0
assignees:
- sfernandez11
- guidoprinc
- mcavo
- mattgle

# A number of assignees to add to the pull request
# Set to 0 to add all of the assignees.
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to this project will be documented in this file.

## [1.8.0] - 2021-XX-XX
- Fixed `CustomTextInput` focus handler
- Fixed `CustomTextInputController` TS interface
- Migrated `react-hook-form` configuration from v6 to v7
- Updated `firebaseFilesScript.sh` file
- Updated Firebase Crashlytics configuration
- Disabled Native DarkMode

## [1.7.0] - 2021-03-19
- Update to `redux-recompose` v3
- Updated some files and libs to support React Native 0.64
Expand Down
10 changes: 10 additions & 0 deletions generators/app/tasks/appSetup/coreFiles/androidProjectSetup.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,20 @@ function addRNReanimatedConfig() {
);
}

function disableDarkMode() {
const projectStyles = this.fs.read(`${this.projectName}/android/app/src/main/res/values/styles.xml`);
const updatedProjectStyles = projectStyles.replace(
'<item name="android:textColor">#000000</item>',
'<item name="android:textColor">#000000</item>\n\t\t<item name="android:forceDarkAllowed">false</item>'
);
this.fs.write(`${this.projectName}/android/app/src/main/res/values/styles.xml`, updatedProjectStyles);
}

module.exports = function androidProjectSetup() {
updateAppBuildGradle.bind(this)();
addRNGestureHandlerConfig.bind(this)();
updateAppProguardRules.bind(this)();
updateGradleProperties.bind(this)();
addRNReanimatedConfig.bind(this)();
disableDarkMode.bind(this)();
};
16 changes: 15 additions & 1 deletion generators/app/tasks/appSetup/coreFiles/iosProjectSetup.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const createSchemes = require('./multipleEnvIos/createSchemes');

module.exports = function fixBundleIndentifier() {
function fixBundleIndentifier() {
const iosProjectContent = this.fs.read(
`${this.projectName}/ios/${this.projectName}.xcodeproj/project.pbxproj`
);
Expand All @@ -11,4 +11,18 @@ module.exports = function fixBundleIndentifier() {
);
this.fs.write(`${this.projectName}/ios/${this.projectName}.xcodeproj/project.pbxproj`, fixedProjectContent);
createSchemes.bind(this)();
}

function disableDarkMode() {
const infoPlistContent = this.fs.read(`${this.projectName}/ios/${this.projectName}/Info.plist`);
const updatedInfoPlistContent = infoPlistContent.replace(
'<key>UIViewControllerBasedStatusBarAppearance</key>',
'<key>UIUserInterfaceStyle</key>\n\t<string>Light</string>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>'
);
this.fs.write(`${this.projectName}/ios/${this.projectName}/Info.plist`, updatedInfoPlistContent);
}

module.exports = function iosProjectSetup() {
fixBundleIndentifier.bind(this)();
disableDarkMode.bind(this)();
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ function addConfigToAndroidFiles() {
let buildGradleContent = this.fs.read(`${this.projectName}/android/build.gradle`);
buildGradleContent = buildGradleContent.replace(
'// NOTE: Do not place your application dependencies here; they belong',
"classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.1'\n\t\t// NOTE: Do not place your application dependencies here; they belong"
"classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.2'\n\t\t// NOTE: Do not place your application dependencies here; they belong"
);
this.fs.write(`${this.projectName}/android/build.gradle`, buildGradleContent);

Expand Down
2 changes: 2 additions & 0 deletions generators/app/tasks/configuringTasks/installDependencies.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const DEPENDENCIES = [
'cerealizr',
'i18next',
'react-hook-form',
'@hookform/devtools',
'@hookform/resolvers',
'react-native-config',
'react-native-flipper',
'react-native-gesture-handler',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
echo "Platform : " $2
echo "Variant founded : " $1
#!/bin/bash
set -e
set -x

echo "Platform:" $2
echo "Variant:" $1
echo "Replacing google files..."

# ANDROID
Expand All @@ -12,8 +16,7 @@ then
elif [[ $1 == *"Prod"* ]]; then
cp -f google-services/google-services-production.json ./google-services.json
else
echo "Setting qa by default"
cp -f google-services/google-services-qa.json ./google-services.json
echo "No valid variant detected"
fi
fi

Expand All @@ -27,8 +30,7 @@ then
elif [ $1 = "com.wolox.wolmorn" ]; then
cp -f GoogleServices/GoogleServiceProduction-Info.plist GoogleService-Info.plist
else
echo "Setting qa by default"
cp -f GoogleServices/GoogleServiceQa-Info.plist GoogleService-Info.plist
echo "No valid variant detected"
fi
fi

Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
import React, { forwardRef } from 'react';
import { TextInput } from 'react-native';
import { Controller, ControllerProps } from 'react-hook-form';
import { Controller, ControllerProps, Control } from 'react-hook-form';
import CustomTextInput from '@components/CustomTextInput';
import { CustomTextInputProps } from '@components/CustomTextInput/interface';

type Props = CustomTextInputProps & ControllerProps<typeof CustomTextInput>;
type Props = CustomTextInputProps & Omit<ControllerProps, 'control' | 'render'> & { control: Control<any> };

const CustomTextInputController = forwardRef<TextInput, Props>(function CustomTextInputController(
{ name, control, defaultValue = '', rules, onFocus, ...props },
{ name, control, defaultValue = '', rules, ...props },
ref
) {
return (
<Controller
render={({ onChange, onBlur, ...renderProps }) => (
control={control}
defaultValue={defaultValue}
name={name}
rules={rules}
render={({ field: { onChange, onBlur, ...fieldProps }, fieldState: { error } }) => (
<CustomTextInput
{...props}
{...fieldProps}
error={error?.message}
onBlur={e => {
onBlur(e);
if (props.onBlur) props.onBlur(e);
}}
onChange={e => {
onChange(e);
if (props.onChange) props.onChange(e);
}}
onBlur={e => {
onBlur();
if (props.onBlur) props.onBlur(e);
}}
{...renderProps}
ref={ref}
/>
)}
defaultValue={defaultValue}
name={name}
control={control}
rules={rules}
onFocus={onFocus}
/>
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, memo, forwardRef } from 'react';
import React, { useCallback, useState, memo, forwardRef } from 'react';
import { TextInput, View } from 'react-native';
import CustomText from '@components/CustomText';
import { transparent } from '@constants/colors';
Expand All @@ -18,12 +18,13 @@ const CustomTextInput = forwardRef<TextInput, Props>(function CustomTextInput(
errorStyle,
inputContainerStyle,
inputTextStyles,
isFocused,
isOptional,
label,
labelStyle,
multiline,
onBlur,
onChange,
onFocus,
placeholder,
placeholderColor,
secureTextEntry,
Expand All @@ -36,13 +37,31 @@ const CustomTextInput = forwardRef<TextInput, Props>(function CustomTextInput(
ref
) {
const [showPassword, setShowPassword] = useState(false);
const [isFocused, setIsFocused] = useState(false);

const handleShowPassword = () => setShowPassword(prevShowPassword => !prevShowPassword);
const handleFocus = useCallback(
e => {
setIsFocused(true);
if (onFocus) onFocus(e);
},
[onFocus]
);
const handleBlur = useCallback(
e => {
setIsFocused(false);
if (onBlur) onBlur(e);
},
[onBlur]
);

const borderColorStyle = () => {
if (disabled) return styles.bottomBorderLightGray;
if (isFocused) return styles.bottomBorderBlue;
if (showError) return styles.bottomBorderRed;
return {};
};

return (
<View style={[styles.container, animated && !!label && styles.withAnimatedLabel, style]}>
{label && (
Expand All @@ -67,6 +86,8 @@ const CustomTextInput = forwardRef<TextInput, Props>(function CustomTextInput(
autoCompleteType={secureTextEntry ? 'off' : autoCompleteType}
editable={!disabled}
multiline={multiline}
onBlur={handleBlur}
onFocus={handleFocus}
onChangeText={onChange}
placeholder={(isFocused || !animated) && value === '' ? placeholder : ''}
placeholderTextColor={placeholderColor}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export interface CustomTextInputProps extends TextInputProps, TextProps {
errorStyle?: TextStyle;
inputContainerStyle?: ViewProps['style'];
inputTextStyles?: TextStyle;
isFocused?: boolean;
isOptional?: boolean;
label?: string;
labelStyle?: TextStyle;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function Login({ navigation }: Navigation) {
const dispatch = useDispatch();
const hasLoginError = useSelector<State, boolean>((state: State) => !!state.auth.currentUserError);

const { handleSubmit, control, errors } = useForm<LoginFormValues>();
const { handleSubmit, control } = useForm<LoginFormValues>({ mode: 'onBlur' });

const handleLogin = (values: LoginFormValues) => dispatch(AuthActions.login(values));

Expand All @@ -37,7 +37,6 @@ function Login({ navigation }: Navigation) {
name={FIELDS.email}
placeholder={i18next.t('LOGIN:MAIL_PLACEHOLDER')}
showError={hasLoginError}
error={errors[FIELDS.email]?.message}
rules={{ ...validateRequired, ...validateEmail }}
/>
<ControlledCustomTextInput
Expand All @@ -48,7 +47,6 @@ function Login({ navigation }: Navigation) {
label={i18next.t('LOGIN:PASSWORD')}
name={FIELDS.password}
showError={hasLoginError}
error={errors[FIELDS.password]?.message}
rules={validateRequired}
/>
{hasLoginError && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ function SignUp({ navigation }: Navigation) {
});

const {
handleSubmit,
control,
errors,
formState: { isValid },
handleSubmit
} = useForm<SignupFormValues>({ mode: 'onTouched' });
formState: { isValid }
} = useForm<SignupFormValues>({ mode: 'onBlur' });

const hasSignUpError = !!error;
const handleSignUp = (values: SignupFormValues) => {
Expand All @@ -56,7 +55,6 @@ function SignUp({ navigation }: Navigation) {
label={i18next.t('SIGNUP:NAME')}
name={FIELDS.name}
showError={hasSignUpError}
error={errors[FIELDS.name]?.message}
rules={{ ...validateRequired, ...validateOnlyText }}
/>
<ControlledCustomTextInput
Expand All @@ -65,7 +63,6 @@ function SignUp({ navigation }: Navigation) {
label={i18next.t('SIGNUP:SURNAME')}
name={FIELDS.surname}
showError={hasSignUpError}
error={errors[FIELDS.surname]?.message}
rules={{ ...validateRequired, ...validateOnlyText }}
/>
<ControlledCustomTextInput
Expand All @@ -75,7 +72,6 @@ function SignUp({ navigation }: Navigation) {
name={FIELDS.birthDate}
placeholder={i18next.t('SIGNUP:BIRTH_DATE_PLACEHOLDER')}
showError={hasSignUpError}
error={errors[FIELDS.birthDate]?.message}
rules={validateRequired}
/>
<ControlledCustomTextInput
Expand All @@ -85,7 +81,6 @@ function SignUp({ navigation }: Navigation) {
name={FIELDS.sex}
placeholder={i18next.t('SIGNUP:SEX_PLACEHOLDER')}
showError={hasSignUpError}
error={errors[FIELDS.sex]?.message}
rules={{ ...validateRequired, ...validateOnlyText }}
/>
<ControlledCustomTextInput
Expand All @@ -96,7 +91,6 @@ function SignUp({ navigation }: Navigation) {
name={FIELDS.email}
placeholder={i18next.t('SIGNUP:MAIL_PLACEHOLDER')}
showError={hasSignUpError}
error={errors[FIELDS.email]?.message}
rules={{ ...validateRequired, ...validateEmail }}
/>
<ControlledCustomTextInput
Expand All @@ -107,7 +101,6 @@ function SignUp({ navigation }: Navigation) {
label={i18next.t('SIGNUP:PASSWORD')}
name={FIELDS.password}
showError={hasSignUpError}
error={errors[FIELDS.password]?.message}
rules={{ ...validateRequired, ...validateMinLength(8) }}
/>
<ControlledCustomTextInput
Expand All @@ -118,7 +111,6 @@ function SignUp({ navigation }: Navigation) {
label={i18next.t('SIGNUP:PHONE_NUMBER')}
name={FIELDS.phoneNumber}
placeholder={i18next.t('SIGNUP:PHONE_NUMBER_PLACEHOLDER')}
error={errors[FIELDS.phoneNumber]?.message}
showError={hasSignUpError}
/>
{hasSignUpError && (
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "generator-wolmo-bootstrap-rn",
"version": "1.7.0",
"version": "1.8.0",
"description": "A project generator for react native applications with some boilerplates already configured and ready to use.",
"files": [
"generators"
Expand Down

0 comments on commit f99a7ba

Please sign in to comment.