@fadyshawky/react-native-magic 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.vscode/settings.json +7 -0
  2. package/CHANGELOG.md +23 -0
  3. package/README.md +2 -4
  4. package/local.properties +1 -0
  5. package/package.json +1 -3
  6. package/template/.env.development +3 -0
  7. package/template/.env.production +4 -1
  8. package/template/.env.staging +4 -1
  9. package/template/App.tsx +0 -5
  10. package/template/android/app/build.gradle +71 -6
  11. package/template/android/app/src/main/AndroidManifest.xml +2 -0
  12. package/template/android/gradle.properties +0 -1
  13. package/template/babel.config.js +1 -0
  14. package/template/index.js +1 -1
  15. package/template/ios/Podfile +37 -6
  16. package/template/ios/Podfile.lock +2 -2
  17. package/template/ios/reactnativemagic/Info.plist +4 -0
  18. package/template/ios/reactnativemagic.xcodeproj/project.pbxproj +74 -74
  19. package/template/ios/tmp.xcconfig +2 -0
  20. package/template/metro.config.js +6 -1
  21. package/template/package-lock.json +4 -3
  22. package/template/package.json +7 -6
  23. package/template/src/common/components/Background.tsx +0 -1
  24. package/template/src/common/components/ImageCropPickerButton.tsx +4 -5
  25. package/template/src/common/components/LoadingComponent.tsx +1 -6
  26. package/template/src/common/localization/translations/loginLocalization.ts +18 -2
  27. package/template/src/core/store/user/userActions.ts +47 -3
  28. package/template/src/core/store/user/userSlice.ts +59 -2
  29. package/template/src/core/theme/fonts.ts +1 -7
  30. package/template/src/navigation/AuthStack.tsx +16 -0
  31. package/template/src/navigation/HeaderComponents.tsx +3 -5
  32. package/template/src/navigation/MainStack.tsx +0 -1
  33. package/template/src/navigation/types.ts +7 -1
  34. package/template/src/screens/Login/Login.tsx +54 -3
  35. package/template/src/screens/registration/RegistrationScreen.tsx +198 -0
  36. package/template/src/screens/resetPassword/ForgotPasswordScreen.tsx +129 -0
  37. package/template/src/types/react-native-config.d.ts +8 -0
@@ -2,7 +2,7 @@ import {createSlice} from '@reduxjs/toolkit';
2
2
  import {LoadState} from '../../../../types';
3
3
  import {newState} from '../../../common/utils/newState';
4
4
  import {handleErrorResponse} from '../../api/responseHandlers';
5
- import {userLogin} from './userActions';
5
+ import {resetPassword, userLogin, userRegister} from './userActions';
6
6
  import {UserInitialState, UserPayload, UserState} from './userState';
7
7
 
8
8
  function loginHandler(state: UserState, payload: {payload: UserPayload}) {
@@ -32,6 +32,47 @@ function logoutHandler(state: UserState) {
32
32
  return newState(state, UserInitialState);
33
33
  }
34
34
 
35
+ function resetPasswordHandler(
36
+ state: UserState,
37
+ payload: {payload: UserPayload},
38
+ ) {
39
+ return newState(state, {
40
+ user: payload.payload.user,
41
+ accessToken: payload.payload.token,
42
+ loginLoading: LoadState['allIsLoaded'],
43
+ });
44
+ }
45
+
46
+ function resetPasswordLoadingHandler(state: UserState) {
47
+ return newState(state, {
48
+ loginLoading: LoadState['pullToRefresh'],
49
+ });
50
+ }
51
+
52
+ function registerHandler(state: UserState, payload: {payload: UserPayload}) {
53
+ return newState(state, {
54
+ user: payload.payload.user,
55
+ accessToken: payload.payload.token,
56
+ loginLoading: LoadState['allIsLoaded'],
57
+ });
58
+ }
59
+
60
+ function registerLoadingHandler(state: UserState) {
61
+ return newState(state, {
62
+ loginLoading: LoadState['pullToRefresh'],
63
+ });
64
+ }
65
+
66
+ function registerErrorHandler(
67
+ state: UserState,
68
+ payload: {payload: string | unknown},
69
+ ) {
70
+ handleErrorResponse((payload.payload as string) || 'Register failed');
71
+ return newState(state, {
72
+ loginLoading: LoadState['error'],
73
+ });
74
+ }
75
+
35
76
  function updateHandler(state: UserState, payload: any) {
36
77
  return newState(state, {
37
78
  user: {
@@ -41,6 +82,16 @@ function updateHandler(state: UserState, payload: any) {
41
82
  });
42
83
  }
43
84
 
85
+ function resetPasswordErrorHandler(
86
+ state: UserState,
87
+ payload: {payload: string | unknown},
88
+ ) {
89
+ handleErrorResponse((payload.payload as string) || 'Password reset failed');
90
+ return newState(state, {
91
+ loginLoading: LoadState['error'],
92
+ });
93
+ }
94
+
44
95
  export const {reducer: UserReducer, actions} = createSlice({
45
96
  name: 'user',
46
97
  initialState: UserInitialState,
@@ -55,7 +106,13 @@ export const {reducer: UserReducer, actions} = createSlice({
55
106
  builder
56
107
  .addCase(userLogin.fulfilled, loginHandler)
57
108
  .addCase(userLogin.rejected, loginErrorHandler)
58
- .addCase(userLogin.pending, loginLoadingHandler);
109
+ .addCase(userLogin.pending, loginLoadingHandler)
110
+ .addCase(resetPassword.fulfilled, resetPasswordHandler)
111
+ .addCase(resetPassword.rejected, resetPasswordErrorHandler)
112
+ .addCase(resetPassword.pending, resetPasswordLoadingHandler)
113
+ .addCase(userRegister.fulfilled, registerHandler)
114
+ .addCase(userRegister.rejected, registerErrorHandler)
115
+ .addCase(userRegister.pending, registerLoadingHandler);
59
116
  },
60
117
  });
61
118
 
@@ -1,7 +1 @@
1
- export const Fonts = {
2
- light: 'Poppins-Light',
3
- regular: 'Poppins-Regular',
4
- medium: 'Poppins-Medium',
5
- semiBold: 'Poppins-SemiBold',
6
- bold: 'Poppins-Bold',
7
- };
1
+ export const Fonts = {};
@@ -1,6 +1,8 @@
1
1
  import {createNativeStackNavigator} from '@react-navigation/native-stack';
2
2
  import {Login} from '../screens/Login/Login';
3
3
  import {Splash} from '../screens/splash/Splash';
4
+ import RegistrationScreen from '../screens/registration/RegistrationScreen';
5
+ import ForgotPasswordScreen from '../screens/resetPassword/ForgotPasswordScreen';
4
6
 
5
7
  const Stack = createNativeStackNavigator();
6
8
 
@@ -19,6 +21,20 @@ const AuthScreens = [
19
21
  headerShown: false,
20
22
  },
21
23
  },
24
+ {
25
+ id: 'Registration',
26
+ component: RegistrationScreen,
27
+ options: {
28
+ headerShown: false,
29
+ },
30
+ },
31
+ {
32
+ id: 'ForgotPassword',
33
+ component: ForgotPasswordScreen,
34
+ options: {
35
+ headerShown: false,
36
+ },
37
+ },
22
38
  ];
23
39
 
24
40
  export function AuthStack() {
@@ -1,10 +1,8 @@
1
+ import {NativeStackNavigationProp} from '@react-navigation/native-stack';
1
2
  import React from 'react';
2
- import {View, Text, TouchableOpacity, Image, StyleSheet} from 'react-native';
3
- import {CommonStyles, screenWidth} from '../core/theme/commonStyles';
4
- import {BottomTabHeaderProps} from '@react-navigation/bottom-tabs';
5
- import {ImageResources} from '../common/ImageResources.g';
3
+ import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native';
6
4
  import {CommonSizes} from '../core/theme/commonSizes';
7
- import {NativeStackNavigationProp} from '@react-navigation/native-stack';
5
+ import {CommonStyles, screenWidth} from '../core/theme/commonStyles';
8
6
  import {RootStackParamList} from './types';
9
7
 
10
8
  export function Header({title}: {title: string}) {
@@ -5,7 +5,6 @@ import {
5
5
  NativeStackNavigationProp,
6
6
  } from '@react-navigation/native-stack';
7
7
  import React from 'react';
8
- import {ImageResources} from '../common/ImageResources.g';
9
8
  import {localization} from '../common/localization/localization';
10
9
  import {Main} from '../screens/main/Main';
11
10
  import {Profile} from '../screens/profile/Profile';
@@ -1,5 +1,11 @@
1
1
  export type RootStackParamList = {
2
2
  Home: undefined;
3
3
  Details: {id: string};
4
- // ... add other screens as needed
4
+ Login: undefined;
5
+ Registration: undefined;
6
+ ForgotPassword: undefined;
7
+ Main: undefined;
8
+ Profile: undefined;
9
+ Settings: undefined;
10
+ Splash: undefined;
5
11
  };
@@ -1,31 +1,54 @@
1
1
  import {useNavigation} from '@react-navigation/native';
2
+ import type {NativeStackNavigationProp} from '@react-navigation/native-stack';
2
3
  import {toLower} from 'lodash';
3
4
  import React, {useRef, useState} from 'react';
4
5
  import {
6
+ findNodeHandle,
5
7
  NativeSyntheticEvent,
6
8
  StyleSheet,
7
9
  Text,
8
10
  TextInputFocusEventData,
9
- findNodeHandle,
10
11
  } from 'react-native';
11
12
  import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
12
13
  import {ButtonType} from '../../../types';
13
14
  import {PrimaryButton} from '../../common/components/PrimaryButton';
14
15
  import {PrimaryTextInput} from '../../common/components/PrimaryTextInput';
15
16
  import {localization} from '../../common/localization/localization';
17
+ import {emptyValidation} from '../../common/validations/commonValidations';
18
+ import {useInputError} from '../../common/validations/hooks/useInputError';
19
+ import {emailValidations} from '../../common/validations/profileValidations';
16
20
  import {useAppDispatch} from '../../core/store/reduxHelpers';
17
21
  import {userLogin} from '../../core/store/user/userActions';
18
22
  import {Colors} from '../../core/theme/colors';
19
23
  import {CommonSizes} from '../../core/theme/commonSizes';
20
24
  import {CommonStyles} from '../../core/theme/commonStyles';
25
+ import type {RootStackParamList} from '../../navigation/types';
21
26
 
22
27
  export function Login(): JSX.Element {
23
28
  const dispatch = useAppDispatch();
24
29
  const [email, setEmail] = useState('');
25
30
  const [password, setPassword] = useState('');
26
31
  const [loading, setLoading] = useState(false);
32
+ const navigation =
33
+ useNavigation<NativeStackNavigationProp<RootStackParamList>>();
34
+
35
+ const {error: emailError, recheckValue: recheckEmail} = useInputError(
36
+ email,
37
+ emailValidations,
38
+ );
39
+ const {error: passwordError, recheckValue: recheckPassword} = useInputError(
40
+ password,
41
+ emptyValidation,
42
+ );
27
43
 
28
44
  async function loginUser() {
45
+ const emailValid = recheckEmail() === null;
46
+ const passwordValid = recheckPassword() === null;
47
+
48
+ if (!emailValid || !passwordValid) {
49
+ return;
50
+ }
51
+
29
52
  setLoading(true);
30
53
  await dispatch(
31
54
  userLogin({
@@ -33,7 +56,6 @@ export function Login(): JSX.Element {
33
56
  password,
34
57
  }),
35
58
  );
36
-
37
59
  setLoading(false);
38
60
  }
39
61
  const scroll = useRef<KeyboardAwareScrollView>(null);
@@ -44,6 +66,15 @@ export function Login(): JSX.Element {
44
66
  scroll.current?.scrollToFocusedInput(reactNode);
45
67
  // }, 500);
46
68
  }
69
+
70
+ const goToRegistration = () => {
71
+ navigation.navigate('Registration');
72
+ };
73
+
74
+ const goToForgotPassword = () => {
75
+ navigation.navigate('ForgotPassword');
76
+ };
77
+
47
78
  return (
48
79
  <KeyboardAwareScrollView
49
80
  ref={scroll}
@@ -65,6 +96,7 @@ export function Login(): JSX.Element {
65
96
  containerStyle={CommonStyles.textInputContainer}
66
97
  label={localization.login.Email}
67
98
  placeholder={localization.login.EnterEmail}
99
+ error={emailError}
68
100
  />
69
101
  <PrimaryTextInput
70
102
  onFocus={(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
@@ -77,11 +109,12 @@ export function Login(): JSX.Element {
77
109
  containerStyle={CommonStyles.textInputContainer}
78
110
  label={localization.login.Password}
79
111
  placeholder={localization.login.EnterPassword}
112
+ error={passwordError}
80
113
  />
81
114
  <PrimaryButton
115
+ onPress={goToForgotPassword}
82
116
  label={localization.login.forgetPassword}
83
117
  type={ButtonType.borderless}
84
- style={{alignSelf: 'flex-end'}}
85
118
  />
86
119
  <PrimaryButton
87
120
  isLoading={loading}
@@ -89,6 +122,11 @@ export function Login(): JSX.Element {
89
122
  label={localization.login.continue}
90
123
  type={ButtonType.solid}
91
124
  />
125
+ <PrimaryButton
126
+ onPress={goToRegistration}
127
+ label={localization.login.notMember}
128
+ type={ButtonType.borderless}
129
+ />
92
130
  </KeyboardAwareScrollView>
93
131
  );
94
132
  }
@@ -111,4 +149,17 @@ const styles = StyleSheet.create({
111
149
  paddingVertical: 26,
112
150
  gap: 16,
113
151
  },
152
+ forgotPassword: {
153
+ ...CommonStyles.normalText,
154
+ color: Colors.primary100,
155
+ textAlign: 'right',
156
+ marginTop: 8,
157
+ marginBottom: 24,
158
+ },
159
+ registerLink: {
160
+ ...CommonStyles.normalText,
161
+ color: Colors.primary100,
162
+ textAlign: 'center',
163
+ marginTop: 16,
164
+ },
114
165
  });
@@ -0,0 +1,198 @@
1
+ import {useNavigation} from '@react-navigation/native';
2
+ import type {NativeStackNavigationProp} from '@react-navigation/native-stack';
3
+ import React, {useRef, useState} from 'react';
4
+ import {
5
+ NativeSyntheticEvent,
6
+ StyleSheet,
7
+ Text,
8
+ TextInputFocusEventData,
9
+ findNodeHandle,
10
+ } from 'react-native';
11
+ import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
12
+ import {ButtonType} from '../../../types';
13
+ import {PrimaryButton} from '../../common/components/PrimaryButton';
14
+ import {PrimaryTextInput} from '../../common/components/PrimaryTextInput';
15
+ import {localization} from '../../common/localization/localization';
16
+ import {emptyValidation} from '../../common/validations/commonValidations';
17
+ import {useInputError} from '../../common/validations/hooks/useInputError';
18
+ import {
19
+ emailValidations,
20
+ fullNameValidations,
21
+ } from '../../common/validations/profileValidations';
22
+ import {useAppDispatch} from '../../core/store/reduxHelpers';
23
+ import {userRegister} from '../../core/store/user/userActions';
24
+ import {Colors} from '../../core/theme/colors';
25
+ import {CommonSizes} from '../../core/theme/commonSizes';
26
+ import {CommonStyles} from '../../core/theme/commonStyles';
27
+ import type {RootStackParamList} from '../../navigation/types';
28
+
29
+ export default function RegistrationScreen(): JSX.Element {
30
+ const dispatch = useAppDispatch();
31
+ const navigation =
32
+ useNavigation<NativeStackNavigationProp<RootStackParamList>>();
33
+ const [loading, setLoading] = useState(false);
34
+ const [formData, setFormData] = useState({
35
+ fullName: '',
36
+ email: '',
37
+ password: '',
38
+ confirmPassword: '',
39
+ });
40
+
41
+ const scroll = useRef<KeyboardAwareScrollView>(null);
42
+
43
+ // Add validation hooks
44
+ const {error: fullNameError, recheckValue: recheckFullName} = useInputError(
45
+ formData.fullName,
46
+ fullNameValidations,
47
+ );
48
+ const {error: emailError, recheckValue: recheckEmail} = useInputError(
49
+ formData.email,
50
+ emailValidations,
51
+ );
52
+ const {error: passwordError, recheckValue: recheckPassword} = useInputError(
53
+ formData.password,
54
+ emptyValidation,
55
+ );
56
+ const {error: confirmPasswordError, recheckValue: recheckConfirmPassword} =
57
+ useInputError(formData.confirmPassword, emptyValidation);
58
+
59
+ function scrollToInput(reactNode: any) {
60
+ scroll.current?.scrollToFocusedInput(reactNode);
61
+ }
62
+
63
+ async function handleRegistration() {
64
+ // Validate all fields
65
+ const isFullNameValid = recheckFullName() === null;
66
+ const isEmailValid = recheckEmail() === null;
67
+ const isPasswordValid = recheckPassword() === null;
68
+ const isConfirmPasswordValid = recheckConfirmPassword() === null;
69
+
70
+ if (
71
+ !isFullNameValid ||
72
+ !isEmailValid ||
73
+ !isPasswordValid ||
74
+ !isConfirmPasswordValid
75
+ ) {
76
+ return;
77
+ }
78
+
79
+ if (formData.password !== formData.confirmPassword) {
80
+ // Add error handling for password mismatch
81
+ return;
82
+ }
83
+
84
+ setLoading(true);
85
+ await dispatch(
86
+ userRegister({
87
+ fullName: formData.fullName,
88
+ email: formData.email.toLowerCase(),
89
+ password: formData.password,
90
+ }),
91
+ );
92
+ setLoading(false);
93
+ }
94
+
95
+ const goToLogin = () => {
96
+ navigation.navigate('Login');
97
+ };
98
+
99
+ return (
100
+ <KeyboardAwareScrollView
101
+ ref={scroll}
102
+ resetScrollToCoords={{x: 0, y: 0}}
103
+ scrollEnabled={true}
104
+ enableOnAndroid={true}
105
+ contentContainerStyle={styles.contentContainer}
106
+ contentInsetAdjustmentBehavior={'automatic'}
107
+ style={styles.container}>
108
+ <Text style={CommonStyles.h1_semiBold}>
109
+ {localization.login.registration.title}
110
+ </Text>
111
+
112
+ <PrimaryTextInput
113
+ onFocus={(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
114
+ scrollToInput(findNodeHandle(event.target));
115
+ }}
116
+ value={formData.fullName}
117
+ onChangeText={text => setFormData({...formData, fullName: text})}
118
+ containerStyle={CommonStyles.textInputContainer}
119
+ label={localization.login.registration.fullName}
120
+ placeholder={localization.login.registration.fullName}
121
+ error={fullNameError}
122
+ />
123
+
124
+ <PrimaryTextInput
125
+ onFocus={(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
126
+ scrollToInput(findNodeHandle(event.target));
127
+ }}
128
+ autoCapitalize="none"
129
+ value={formData.email}
130
+ onChangeText={text => setFormData({...formData, email: text})}
131
+ containerStyle={CommonStyles.textInputContainer}
132
+ label={localization.login.registration.email}
133
+ placeholder={localization.login.EnterEmail}
134
+ error={emailError}
135
+ />
136
+
137
+ <PrimaryTextInput
138
+ onFocus={(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
139
+ scrollToInput(findNodeHandle(event.target));
140
+ }}
141
+ secureTextEntry
142
+ value={formData.password}
143
+ onChangeText={text => setFormData({...formData, password: text})}
144
+ containerStyle={CommonStyles.textInputContainer}
145
+ label={localization.login.registration.password}
146
+ placeholder={localization.login.EnterPassword}
147
+ error={passwordError}
148
+ />
149
+
150
+ <PrimaryTextInput
151
+ onFocus={(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
152
+ scrollToInput(findNodeHandle(event.target));
153
+ }}
154
+ secureTextEntry
155
+ value={formData.confirmPassword}
156
+ onChangeText={text => setFormData({...formData, confirmPassword: text})}
157
+ containerStyle={CommonStyles.textInputContainer}
158
+ label={localization.login.registration.confirmPassword}
159
+ placeholder={localization.login.registration.confirmPassword}
160
+ error={confirmPasswordError}
161
+ />
162
+
163
+ <PrimaryButton
164
+ isLoading={loading}
165
+ onPress={handleRegistration}
166
+ label={localization.login.registration.register}
167
+ type={ButtonType.solid}
168
+ />
169
+ <PrimaryButton
170
+ onPress={goToLogin}
171
+ label={localization.login.registration.alreadyHaveAccount}
172
+ type={ButtonType.borderless}
173
+ />
174
+ </KeyboardAwareScrollView>
175
+ );
176
+ }
177
+
178
+ const styles = StyleSheet.create({
179
+ container: {
180
+ flexGrow: 1,
181
+ backgroundColor: Colors.white,
182
+ borderTopRightRadius: CommonSizes.spacing.large,
183
+ borderTopLeftRadius: CommonSizes.spacing.large,
184
+ },
185
+ contentContainer: {
186
+ justifyContent: 'center',
187
+ alignItems: 'center',
188
+ paddingHorizontal: CommonSizes.spacing.large,
189
+ paddingVertical: 26,
190
+ gap: 16,
191
+ },
192
+ loginLink: {
193
+ ...CommonStyles.normalText,
194
+ color: Colors.primary100,
195
+ textAlign: 'center',
196
+ marginTop: 16,
197
+ },
198
+ });
@@ -0,0 +1,129 @@
1
+ import {useNavigation} from '@react-navigation/native';
2
+ import type {NativeStackNavigationProp} from '@react-navigation/native-stack';
3
+ import React, {useRef, useState} from 'react';
4
+ import {
5
+ NativeSyntheticEvent,
6
+ StyleSheet,
7
+ Text,
8
+ TextInputFocusEventData,
9
+ findNodeHandle,
10
+ } from 'react-native';
11
+ import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
12
+ import {ButtonType} from '../../../types';
13
+ import {PrimaryButton} from '../../common/components/PrimaryButton';
14
+ import {PrimaryTextInput} from '../../common/components/PrimaryTextInput';
15
+ import {localization} from '../../common/localization/localization';
16
+ import {useInputError} from '../../common/validations/hooks/useInputError';
17
+ import {emailValidations} from '../../common/validations/profileValidations';
18
+ import {useAppDispatch} from '../../core/store/reduxHelpers';
19
+ import {resetPassword} from '../../core/store/user/userActions';
20
+ import {Colors} from '../../core/theme/colors';
21
+ import {CommonSizes} from '../../core/theme/commonSizes';
22
+ import {CommonStyles} from '../../core/theme/commonStyles';
23
+ import type {RootStackParamList} from '../../navigation/types';
24
+
25
+ export default function ForgotPasswordScreen(): JSX.Element {
26
+ const dispatch = useAppDispatch();
27
+ const navigation =
28
+ useNavigation<NativeStackNavigationProp<RootStackParamList>>();
29
+ const [email, setEmail] = useState('');
30
+ const [loading, setLoading] = useState(false);
31
+
32
+ const scroll = useRef<KeyboardAwareScrollView>(null);
33
+
34
+ const {error: emailError, recheckValue: recheckEmail} = useInputError(
35
+ email,
36
+ emailValidations,
37
+ );
38
+
39
+ function scrollToInput(reactNode: any) {
40
+ scroll.current?.scrollToFocusedInput(reactNode);
41
+ }
42
+
43
+ async function handleResetPassword() {
44
+ const isEmailValid = recheckEmail() === null;
45
+ if (!isEmailValid) {
46
+ return;
47
+ }
48
+
49
+ setLoading(true);
50
+ await dispatch(resetPassword({email: email.toLowerCase()}));
51
+ setLoading(false);
52
+ }
53
+
54
+ const goToLogin = () => {
55
+ navigation.navigate('Login');
56
+ };
57
+
58
+ return (
59
+ <KeyboardAwareScrollView
60
+ ref={scroll}
61
+ resetScrollToCoords={{x: 0, y: 0}}
62
+ scrollEnabled={true}
63
+ enableOnAndroid={true}
64
+ contentContainerStyle={styles.contentContainer}
65
+ contentInsetAdjustmentBehavior={'automatic'}
66
+ style={styles.container}>
67
+ <Text style={CommonStyles.h1_semiBold}>
68
+ {localization.login.forgotPassword.title}
69
+ </Text>
70
+
71
+ <Text style={styles.description}>
72
+ {localization.login.forgotPassword.description}
73
+ </Text>
74
+
75
+ <PrimaryTextInput
76
+ onFocus={(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
77
+ scrollToInput(findNodeHandle(event.target));
78
+ }}
79
+ autoCapitalize="none"
80
+ value={email}
81
+ onChangeText={setEmail}
82
+ containerStyle={CommonStyles.textInputContainer}
83
+ label={localization.login.Email}
84
+ placeholder={localization.login.EnterEmail}
85
+ error={emailError}
86
+ />
87
+
88
+ <PrimaryButton
89
+ isLoading={loading}
90
+ onPress={handleResetPassword}
91
+ label={localization.login.forgotPassword.resetPassword}
92
+ type={ButtonType.solid}
93
+ />
94
+
95
+ <PrimaryButton
96
+ onPress={goToLogin}
97
+ label={localization.login.forgotPassword.backToLogin}
98
+ type={ButtonType.borderless}
99
+ />
100
+ </KeyboardAwareScrollView>
101
+ );
102
+ }
103
+
104
+ const styles = StyleSheet.create({
105
+ container: {
106
+ flexGrow: 1,
107
+ backgroundColor: Colors.white,
108
+ borderTopRightRadius: CommonSizes.spacing.large,
109
+ borderTopLeftRadius: CommonSizes.spacing.large,
110
+ },
111
+ contentContainer: {
112
+ justifyContent: 'center',
113
+ alignItems: 'center',
114
+ paddingHorizontal: CommonSizes.spacing.large,
115
+ paddingVertical: 26,
116
+ gap: 16,
117
+ },
118
+ description: {
119
+ ...CommonStyles.normalText,
120
+ textAlign: 'center',
121
+ marginBottom: 8,
122
+ },
123
+ loginLink: {
124
+ ...CommonStyles.normalText,
125
+ color: Colors.primary100,
126
+ textAlign: 'center',
127
+ marginTop: 16,
128
+ },
129
+ });
@@ -0,0 +1,8 @@
1
+ declare module 'react-native-config' {
2
+ export interface NativeConfig {
3
+ API_BASE_URL: string;
4
+ [key: string]: string;
5
+ }
6
+ const Config: NativeConfig;
7
+ export default Config;
8
+ }