RegisterCredentials.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import React, { useEffect } from 'react';
  2. import { Alert, ImageBackground, StyleSheet, View, Dimensions, TouchableOpacity, TextInput } from 'react-native';
  3. import { Controller, useForm } from 'react-hook-form';
  4. import { Text, } from 'react-native-paper'
  5. import 'react-native-get-random-values';
  6. import { useRegistrationFormState } from '../contexts/RegisterContext';
  7. const RegisterCredentials = ({navigation, route}) => {
  8. const { dispatch, state: { username, email, password, } } = useRegistrationFormState();
  9. const { control, handleSubmit, watch, formState: {errors} } = useForm({
  10. mode: 'all'
  11. });
  12. const submitCredForm = (formData) => {
  13. dispatch({ type: "USERNAME_CHANGE", payload: formData.username });
  14. dispatch({ type: "EMAIL_CHANGE", payload: formData.email });
  15. dispatch({ type: "PASSWORD_CHANGE", payload: formData.password });
  16. navigation.navigate("Measurements");
  17. }
  18. useEffect(() =>
  19. navigation.addListener('beforeRemove', (e) => {
  20. e.preventDefault();
  21. Alert.alert(
  22. 'Going so soon?',
  23. 'Are you sure you want to cancel registration?',
  24. [
  25. { text: "Don't leave", style: 'cancel', onPress: () => {} },
  26. {
  27. text: 'Discard',
  28. style: 'destructive',
  29. onPress: () => {
  30. dispatch({ type: "USERNAME_CHANGE", payload: null });
  31. dispatch({ type: "EMAIL_CHANGE", payload: null });
  32. dispatch({ type: "PASSWORD_CHANGE", payload: null });
  33. dispatch({ type: "HEIGHT_CHANGE", payload: null })
  34. dispatch({ type: "WEIGHT_CHANGE", payload: null })
  35. navigation.dispatch(e.data.action)
  36. },
  37. },
  38. ]
  39. );
  40. }),
  41. [navigation]);
  42. return (
  43. <ImageBackground style={styles.container} source={require('../assets/cover-dark.png')}>
  44. <View style={styles.brandContainer}>
  45. <Text style={styles.title} >Welcome!</Text>
  46. </View>
  47. <View>
  48. <Text style={styles.subtitle} >Let's start with some basic account information.</Text>
  49. <View style={{margin: 20}}>
  50. <Controller
  51. defaultValue={username}
  52. control={control}
  53. render={({ field: { onChange, value }}) => (
  54. <TextInput
  55. mode="outlined"
  56. style={[styles.textInput, errors.username && styles.errorInput]}
  57. placeholder="Username"
  58. value={value}
  59. onChangeText={value => onChange(value)}
  60. ></TextInput>
  61. )}
  62. name="username"
  63. rules={{ required: true, minLength: 5, maxLength: 15}}
  64. />
  65. {errors.username?.type === "required" && <Text style={styles.errorText}>Username is required.</Text>}
  66. {errors.username?.type === "minLength" && <Text style={styles.errorText}>Username must be at least 5 characters.</Text>}
  67. {errors.username?.type === "maxLength" && <Text style={styles.errorText}>Username must be no more than 15 characters.</Text>}
  68. <Controller
  69. defaultValue={email}
  70. control={control}
  71. render={({ field: { onChange, value }}) => (
  72. <TextInput
  73. mode="outlined"
  74. style={[styles.textInput, errors.username && styles.errorInput]}
  75. placeholder="Email"
  76. value={value}
  77. onChangeText={value => onChange(value)} />
  78. )}
  79. rules={{
  80. required: true,
  81. pattern:
  82. {
  83. value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i
  84. }}}
  85. name="email"/>
  86. {errors.email?.type === "required" && <Text style={styles.errorText}>Email is required.</Text>}
  87. {errors.email?.type === "pattern" && <Text style={styles.errorText}>Must be a valid email address.</Text>}
  88. <Controller
  89. defaultValue={password}
  90. control={control}
  91. render={({ field: { onChange, value }}) => (
  92. <TextInput
  93. mode="outlined"
  94. style={[styles.textInput, errors.username && styles.errorInput]}
  95. placeholder="Password"
  96. autoCompleteType="password"
  97. secureTextEntry={true}
  98. value={value}
  99. onChangeText={value => onChange(value)} />
  100. )}
  101. rules={{
  102. required: true,
  103. pattern:
  104. {
  105. value: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[\w~@#$%^&*+=`|{}:;!.?\"()\[\]-]{8,}$/
  106. }}}
  107. name="password"/>
  108. {errors.password?.type === "required" && <Text style={styles.errorText}>Password is required.</Text>}
  109. {errors.password?.type === "pattern" && <Text style={styles.errorText}>Password must be at least 8 characters and contain one lowercase letter, one captial letter, and one number.</Text>}
  110. <Controller
  111. defaultValue={password}
  112. control={control}
  113. render={({ field: { onChange, value }}) => (
  114. <TextInput
  115. mode="outlined"
  116. style={[styles.textInput, errors.username && styles.errorInput]}
  117. placeholder="Confirm password"
  118. secureTextEntry={true}
  119. value={value}
  120. onChangeText={value => onChange(value)} />
  121. )}
  122. rules={{validate: value => value === watch('password')}}
  123. name="confirmPassword"/>
  124. {errors.confirmPassword && <Text style={styles.errorText}>Passwords do not match.</Text>}
  125. </View>
  126. <TouchableOpacity onPress={handleSubmit(submitCredForm)} style={styles.nextBtn} >
  127. <Text style={{ color: 'white', fontSize: 20 }}>Next</Text>
  128. </TouchableOpacity>
  129. </View>
  130. </ImageBackground>
  131. )
  132. }
  133. const styles = StyleSheet.create({
  134. container: {
  135. position: 'absolute',
  136. width: Dimensions.get('window').width,
  137. height: Dimensions.get('window').height,
  138. flex: 1,
  139. flexDirection: 'column',
  140. resizeMode: 'cover',
  141. },
  142. brandContainer: {
  143. marginTop: 50,
  144. height: 50,
  145. marginLeft: 25,
  146. flexDirection: 'column',
  147. justifyContent: 'space-evenly'
  148. },
  149. title: {
  150. fontFamily: 'RacingSansOne-Regular',
  151. color: 'white',
  152. fontSize: 20
  153. },
  154. subtitle: {
  155. fontFamily: 'RacingSansOne-Regular',
  156. color: 'white',
  157. fontSize: 15
  158. },
  159. title: {
  160. fontFamily: 'RacingSansOne-Regular',
  161. color: 'white',
  162. fontSize: 20
  163. },
  164. subtitle: {
  165. fontFamily: 'RacingSansOne-Regular',
  166. color: 'white',
  167. fontSize: 15,
  168. margin: 20
  169. },
  170. textContainer: {
  171. marginHorizontal: 20,
  172. marginBottom: 30,
  173. borderRadius: 50,
  174. },
  175. textInput: {
  176. marginVertical: 7,
  177. paddingLeft: 30,
  178. borderRadius: 50,
  179. overflow: 'hidden',
  180. backgroundColor: 'white',
  181. height: 50
  182. },
  183. errorText: {
  184. alignSelf: 'flex-end',
  185. color: 'red',
  186. fontSize: 15
  187. },
  188. errorInput: {
  189. borderWidth: 2,
  190. borderColor: 'red'
  191. },
  192. nextBtn: {
  193. marginHorizontal: 20,
  194. marginBottom: 100,
  195. borderRadius: 50,
  196. justifyContent: 'center',
  197. backgroundColor: '#df3f3f',
  198. margin: 5,
  199. height: 50,
  200. alignItems: 'center'
  201. },
  202. backBtn: {
  203. marginHorizontal: 20,
  204. marginBottom: 10,
  205. borderRadius: 50,
  206. borderColor: 'white',
  207. borderWidth: 2,
  208. justifyContent: 'center',
  209. backgroundColor: 'transparent',
  210. margin: 5,
  211. height: 50,
  212. alignItems: 'center'
  213. },
  214. })
  215. export default RegisterCredentials;