Skip to content

Commit

Permalink
chore: Add react-hook-form for form validation (#463)
Browse files Browse the repository at this point in the history
* Add react-hooks-form package

* Update login screen form

* Updaye circleci node version

* Style fixes

* Code cleanup

* Fix the auth error logic

* Change configure url screen validation

* Change reset password form validation

* Remove tcomb-form-native package

* Remove console/logs

* Android/iOS beta version 1.3.27
  • Loading branch information
muhsin-k committed Jan 12, 2022
1 parent 88c3a8d commit 3f57510
Show file tree
Hide file tree
Showing 14 changed files with 291 additions and 240 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ orbs:
jobs:
build-and-test:
docker:
- image: circleci/node:12.5.0
- image: circleci/node:12.22.0
steps:
- checkout
- restore_cache:
Expand Down
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ android {
applicationId "com.chatwoot.app"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 5026
versionName "1.3.26"
versionCode 5027
versionName "1.3.27"
multiDexEnabled true
}
splits {
Expand Down
8 changes: 4 additions & 4 deletions ios/Chatwoot.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -753,14 +753,14 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 150;
CURRENT_PROJECT_VERSION = 151;
DEVELOPMENT_TEAM = L7YLMN4634;
ENABLE_BITCODE = NO;
EXCLUDED_ARCHS = "";
INFOPLIST_FILE = Chatwoot/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.3.26;
MARKETING_VERSION = 1.3.27;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand All @@ -786,13 +786,13 @@
CODE_SIGN_ENTITLEMENTS = Chatwoot/Chatwoot.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 150;
CURRENT_PROJECT_VERSION = 151;
DEVELOPMENT_TEAM = L7YLMN4634;
EXCLUDED_ARCHS = "";
INFOPLIST_FILE = Chatwoot/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.3.26;
MARKETING_VERSION = 1.3.27;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@chatwoot/mobile-app",
"version": "1.3.26",
"version": "1.3.27",
"private": true,
"scripts": {
"clean": "rm -rf $TMPDIR/react-* && watchman watch-del-all && npm cache clean --force",
Expand All @@ -11,7 +11,7 @@
"android:release": "react-native run-android --variant=release",
"android:publish-internal": "cd android && ./gradlew clean && fastlane android beta_internal",
"android:publish-open": "cd android && ./gradlew clean && fastlane android beta_open",
"ios:publish-internal":"cd ios && fastlane ios beta",
"ios:publish-internal": "cd ios && fastlane ios beta",
"ios": "react-native run-ios",
"ios:clean-derived-data": "rm -rf ~/Library/Developer/Xcode/DerivedData/*",
"start": "react-native start",
Expand Down Expand Up @@ -46,6 +46,7 @@
"posthog-react-native": "^1.1.3",
"prop-types": "^15.7.2",
"react": "17.0.1",
"react-hook-form": "^7.22.5",
"react-native": "0.64.2",
"react-native-actions-sheet": "^0.4.2",
"react-native-animatable": "^1.3.3",
Expand Down Expand Up @@ -73,7 +74,6 @@
"redux-logger": "^3.0.6",
"redux-persist": "^6.0.0",
"redux-thunk": "^2.3.0",
"tcomb-form-native": "^0.6.20",
"validator": "^13.7.0",
"yarn": "^1.22.10"
},
Expand Down Expand Up @@ -113,4 +113,4 @@
"preset": "react-native",
"testRegex": "src/.*.spec.(js|jsx)$"
}
}
}
29 changes: 23 additions & 6 deletions src/actions/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,20 @@ export const doLogin =
showToast({ message: I18n.t('ERRORS.NO_ACCOUNTS_MESSAGE') });
dispatch({ type: LOGIN_ERROR, payload: '' });
}
} catch (error) {
if (error && error.status === 401) {
showToast({ message: I18n.t('ERRORS.AUTH') });
} catch ({ response }) {
dispatch({ type: LOGIN_ERROR, payload: response });
if (response && response.status === 401) {
const { errors } = response.data;
const hasAuthErrorMsg =
errors && errors.length && errors[0] && typeof errors[0] === 'string';
if (hasAuthErrorMsg) {
showToast({ message: errors[0] });
} else {
showToast({ message: I18n.t('ERRORS.AUTH') });
}
return;
}
dispatch({ type: LOGIN_ERROR, payload: error });
showToast({ message: I18n.t('ERRORS.COMMON_ERROR') });
}
};

Expand All @@ -57,11 +66,19 @@ export const onResetPassword =
try {
dispatch({ type: RESET_PASSWORD });
const response = await APIHelper.post('auth/password', { email });
let successMessage = I18n.t('FORGOT_PASSWORD.API_SUCCESS');
if (response.data && response.data.message) {
successMessage = response.data.message;
}
showToast({ message: successMessage });
const { data } = response;
showToast(data);

dispatch({ type: RESET_PASSWORD_SUCCESS, payload: data });
} catch (error) {
let errorMessage = I18n.t('ERRORS.AUTH');
if (error?.response?.data?.message) {
errorMessage = error.response.data.message;
}
showToast({ message: errorMessage });
dispatch({ type: RESET_PASSWORD_ERROR, payload: error });
}
};
Expand Down
81 changes: 81 additions & 0 deletions src/components/TextInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React from 'react';
import { View, TextInput } from 'react-native';
import { StyleService, useStyleSheet } from '@ui-kitten/components';
import PropTypes from 'prop-types';
import Text from './Text';

const themedStyles = StyleService.create({
textViewError: {
borderWidth: 1,
borderColor: 'color-danger-900',
borderRadius: 4,
marginTop: 8,
},
label: {
color: 'text-basic-color',
paddingBottom: 6,
fontSize: 'text-primary-size',
fontWeight: 'font-medium',
},
errorLabel: {
color: 'color-danger-900',
textAlign: 'left',
paddingTop: 2,
paddingBottom: 2,
fontSize: 'text-primary-size',
},
inputStyle: {
fontSize: 'input-font-size',
color: 'text-basic-color',
paddingVertical: 8,
paddingHorizontal: 16,
borderWidth: 1,
borderRadius: 4,
borderColor: 'color-basic-focus-border',
height: 48,
},
errorInputStyle: {
fontSize: 'input-font-size',
color: 'text-basic-color',
paddingVertical: 8,
paddingHorizontal: 16,
borderWidth: 1,
borderRadius: 4,
borderColor: 'color-danger-900',
height: 48,
},
});

const propTypes = {
onChangeText: PropTypes.func.isRequired,
error: PropTypes.object,
keyboardType: PropTypes.string,
secureTextEntry: PropTypes.bool,
label: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
};
const TextInputField = ({ onChangeText, error, keyboardType, secureTextEntry, label, value }) => {
const styles = useStyleSheet(themedStyles);

return (
<View>
<Text style={styles.label}>{label}</Text>
<TextInput
style={error ? styles.errorInputStyle : styles.inputStyle}
accessibilityLabel={label}
keyboardType={keyboardType}
secureTextEntry={secureTextEntry}
onChangeText={onChangeText}
value={value}
autoCapitalize="none"
autoComplete={false}
autoCorrect={false}
/>
{error && <Text style={styles.errorLabel}>{error.message}</Text>}
</View>
);
};

TextInputField.propTypes = propTypes;

export default TextInputField;
42 changes: 4 additions & 38 deletions src/helpers/formHelper.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,5 @@
import t from 'tcomb-form-native';
import validator from 'validator';
// eslint-disable-next-line no-useless-escape
const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const nameRegex = /^.{2}/;
const passwordRegex = /^.{6}/;
const mobileNumberValidator = (mobileNumber) => {
const regex = /^(?:(?:\+|0{0,2})91(\s*[-]\s*)?|[0]?)?[789]\d{9}$/g;
return regex.test(mobileNumber);
};
export const IndianMobileRegex = t.refinement(t.Number, mobileNumberValidator);
export const URL_WITHOUT_HTTP_REGEX =
/^(?:(ftp|http|https)?:\/\/)?(?:[\w-]+\.)+([a-z]|[A-Z]|[0-9]){2,6}$/gi;

export const isStringEmail = (email) => {
const re = emailRegex;
return re.test(email);
};
export const Email = t.refinement(t.String, (email) => isStringEmail(email));

export const isStringName = (name) => {
const re = nameRegex;
return re.test(name);
};
export const Name = t.refinement(t.String, (name) => isStringName(name));

export const isStringUrl = (url) => {
return validator.isURL(url);
};
export const URL = t.refinement(t.String, (url) => isStringUrl(url));

export const isStringPassword = (password) => {
const re = passwordRegex;
return re.test(password);
};
export const Password = t.refinement(t.String, (password) => isStringPassword(password));

export const isNumberValid = (number) => {
const regex = /^\+?\d{1,8}(?:\.\d{1,2})?$/;
return regex.test(number);
};
export const EMAIL_REGEX =
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
6 changes: 5 additions & 1 deletion src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"ENTER_URL": "Installation URL",
"DESCRIPTION": "If you are using a self-hosted Chatwoot installation, input your server URL. Otherwise, use app.chatwoot.com.",
"URL_ERROR": "Enter a valid URL",
"URL_REQUIRED": "URL is required",
"CONNECT": "Connect",
"CHANGE_LANGUAGE": "Change language",
"ERROR": "Invalid installation url"
Expand All @@ -25,7 +26,9 @@
"DESCRIPTION": "You are connected to {{baseUrl}}. Login with your email address and password.",
"EMAIL": "Email",
"PASSWORD": "Password",
"EMAIL_REQUIRED": "Email is required",
"EMAIL_ERROR": "Enter a valid email",
"PASSWORD_REQUIRED": "Password is required",
"PASSWORD_ERROR": "Enter a valid password",
"LOGIN": "Sign In",
"FORGOT_PASSWORD": "Forgot your password?",
Expand All @@ -43,7 +46,8 @@
"RESET_HERE": "Reset password",
"HEADER_TITLE": "Reset password",
"TITLE": "Forgot Password?",
"SUB_TITLE": "Don't worry! We got your back"
"SUB_TITLE": "Don't worry! We got your back",
"API_SUCCESS": "Password reset link has been sent to your email address"
},
"CONVERSATION": {
"DEFAULT_HEADER_TITLE": "Conversations",
Expand Down
2 changes: 0 additions & 2 deletions src/screens/ChatScreen/components/Attachment.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ const Attachment = ({ conversationId, eva: { style, theme }, onSelectAttachment
DocumentPicker.types.xlsx,
],
});
console.log('attachment', res);

const attachment = { uri: res.uri, type: res.type, fileSize: res.size, fileName: res.name };
onSelectAttachment({ attachment });
} catch (err) {
Expand Down
Loading

0 comments on commit 3f57510

Please sign in to comment.