@fadyshawky/react-native-magic 2.0.4 → 2.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 (80) hide show
  1. package/package.json +1 -1
  2. package/template/App.tsx +28 -19
  3. package/template/ios/reactnativemagic/AppDelegate.mm +5 -0
  4. package/template/src/common/components/Background.tsx +6 -4
  5. package/template/src/common/components/Container.tsx +6 -9
  6. package/template/src/common/components/OTPInput.tsx +3 -2
  7. package/template/src/common/components/PrimaryButton.tsx +23 -23
  8. package/template/src/common/components/PrimaryTextInput.tsx +189 -199
  9. package/template/src/common/components/RadioIcon.tsx +4 -4
  10. package/template/src/common/components/SafeText.tsx +41 -0
  11. package/template/src/common/components/SearchBar.tsx +19 -17
  12. package/template/src/common/components/TryAgain.tsx +3 -3
  13. package/template/src/common/localization/LocalizationProvider.tsx +14 -17
  14. package/template/src/common/localization/RTLInitializer.tsx +90 -0
  15. package/template/src/common/localization/localization.ts +8 -0
  16. package/template/src/common/localization/translations/commonLocalization.ts +33 -6
  17. package/template/src/common/localization/translations/emptyLocalization.ts +6 -2
  18. package/template/src/common/localization/translations/errorsLocalization.ts +33 -13
  19. package/template/src/common/localization/translations/homeLocalization.ts +6 -2
  20. package/template/src/common/localization/translations/loginLocalization.ts +32 -9
  21. package/template/src/common/localization/translations/mainNavigationLocalization.ts +30 -0
  22. package/template/src/common/localization/translations/navigationLocalization.ts +48 -0
  23. package/template/src/common/localization/translations/onboardingLocalization.ts +40 -9
  24. package/template/src/common/localization/translations/otpLocalization.ts +28 -0
  25. package/template/src/common/localization/translations/pagesLocalization.ts +13 -1
  26. package/template/src/common/localization/translations/passwordLocalization.ts +54 -0
  27. package/template/src/common/localization/translations/profileLocalization.ts +4 -4
  28. package/template/src/common/utils/FeesCaalculation.tsx +37 -0
  29. package/template/src/common/utils/index.tsx +11 -0
  30. package/template/src/common/utils/printData.tsx +161 -0
  31. package/template/src/common/validations/errorValidations.ts +3 -2
  32. package/template/src/core/api/serverHeaders.ts +62 -1
  33. package/template/src/core/store/Categories/categoryActions.ts +33 -0
  34. package/template/src/core/store/Categories/categorySlice.ts +75 -0
  35. package/template/src/core/store/Categories/categoryState.ts +41 -0
  36. package/template/src/core/store/Providers/providersActions.ts +102 -0
  37. package/template/src/core/store/Providers/providersSlice.ts +136 -0
  38. package/template/src/core/store/Providers/providersState.ts +37 -0
  39. package/template/src/core/store/Services/servicesActions.ts +191 -0
  40. package/template/src/core/store/Services/servicesSlice.ts +205 -0
  41. package/template/src/core/store/Services/servicesState.ts +466 -0
  42. package/template/src/core/store/app/appSlice.ts +13 -5
  43. package/template/src/core/store/app/appState.ts +10 -2
  44. package/template/src/core/store/rootReducer.ts +6 -1
  45. package/template/src/core/store/store.tsx +55 -2
  46. package/template/src/core/store/user/userActions.ts +164 -26
  47. package/template/src/core/store/user/userSlice.ts +193 -21
  48. package/template/src/core/store/user/userState.ts +148 -25
  49. package/template/src/core/theme/colors.ts +12 -0
  50. package/template/src/core/theme/themes.ts +1 -1
  51. package/template/src/core/utils/stringUtils.ts +114 -0
  52. package/template/src/navigation/AuthStack.tsx +8 -0
  53. package/template/src/navigation/HeaderComponents.tsx +52 -1
  54. package/template/src/navigation/MainNavigation.tsx +3 -1
  55. package/template/src/navigation/MainStack.tsx +39 -56
  56. package/template/src/navigation/TabBar.tsx +111 -59
  57. package/template/src/navigation/types.ts +24 -0
  58. package/template/src/screens/Login/Login.tsx +83 -85
  59. package/template/src/screens/OTP/OTPScreen.tsx +169 -0
  60. package/template/src/screens/home/Components/PayByCode.tsx +129 -0
  61. package/template/src/screens/home/HomeScreen.tsx +1 -103
  62. package/template/src/screens/home/hooks/useHomeData.ts +32 -38
  63. package/template/src/screens/index.tsx +24 -0
  64. package/template/src/common/components/Stepper.tsx +0 -153
  65. package/template/src/common/components/Svg.tsx +0 -25
  66. package/template/src/common/hooks/useDebounce.ts +0 -17
  67. package/template/src/common/hooks/usePrevious.ts +0 -11
  68. package/template/src/common/urls/emailUrl.ts +0 -20
  69. package/template/src/common/urls/mapUrl.ts +0 -22
  70. package/template/src/common/utils/listHandlers.ts +0 -30
  71. package/template/src/common/utils/serializeQueryParams.ts +0 -10
  72. package/template/src/common/validations/hooks/useDatesError.ts +0 -40
  73. package/template/src/common/validations/profileValidations.ts +0 -30
  74. package/template/src/navigation/TopTabBar.tsx +0 -77
  75. package/template/src/screens/Settings/Settings.tsx +0 -5
  76. package/template/src/screens/home/components/CarouselSection.tsx +0 -79
  77. package/template/src/screens/home/components/FeaturedCarousel.tsx +0 -128
  78. package/template/src/screens/main/Main.tsx +0 -5
  79. package/template/src/screens/registration/RegistrationScreen.tsx +0 -198
  80. package/template/src/screens/resetPassword/ForgotPasswordScreen.tsx +0 -129
@@ -1,30 +0,0 @@
1
- import {emptyValidation} from './commonValidations';
2
- import {isEmail} from '../helpers/regexHelpers';
3
- import {validationConstants} from './validationConstants';
4
- import {localization} from '../localization/localization';
5
-
6
- export function emailValidations(checkValue: string): string | null {
7
- const isEmpty = emptyValidation(checkValue);
8
-
9
- if (isEmpty != null) {
10
- return isEmpty;
11
- } else if (!isEmail(checkValue)) {
12
- return localization.errors.invalidEmail;
13
- } else {
14
- return null;
15
- }
16
- }
17
-
18
- export function fullNameValidations(checkValue: string): string | null {
19
- const isEmpty = emptyValidation(checkValue);
20
-
21
- if (isEmpty != null) {
22
- return isEmpty;
23
- } else if (
24
- checkValue.trim().length < validationConstants.fullName.minLength
25
- ) {
26
- return localization.errors.invalidFullName;
27
- } else {
28
- return null;
29
- }
30
- }
@@ -1,77 +0,0 @@
1
- import {Animated, View, TouchableOpacity} from 'react-native';
2
- import {CommonStyles, screenWidth} from '../core/theme/commonStyles';
3
- import {NaturalColors} from '../core/theme/colors';
4
-
5
- export function TopBar({state, descriptors, navigation, position}: any) {
6
- return (
7
- <View
8
- style={{
9
- flexDirection: 'row',
10
- backgroundColor: NaturalColors.grayScale_50,
11
- width: screenWidth - 60,
12
- alignSelf: 'center',
13
- height: 40,
14
- borderRadius: 20,
15
- marginBottom: 24,
16
- }}>
17
- {state.routes.map((route: any, index: any) => {
18
- const {options} = descriptors[route.key];
19
- const label =
20
- options.tabBarLabel !== undefined
21
- ? options.tabBarLabel
22
- : options.title !== undefined
23
- ? options.title
24
- : route.name;
25
-
26
- const isFocused = state.index === index;
27
-
28
- const onPress = () => {
29
- const event = navigation.emit({
30
- type: 'tabPress',
31
- target: route.key,
32
- canPreventDefault: true,
33
- });
34
-
35
- if (!isFocused && !event.defaultPrevented) {
36
- navigation.navigate(route.name, route.params);
37
- }
38
- };
39
-
40
- const onLongPress = () => {
41
- navigation.emit({
42
- type: 'tabLongPress',
43
- target: route.key,
44
- });
45
- };
46
-
47
- return (
48
- <TouchableOpacity
49
- accessibilityRole="button"
50
- accessibilityState={isFocused ? {selected: true} : {}}
51
- accessibilityLabel={options.tabBarAccessibilityLabel}
52
- testID={options.tabBarTestID}
53
- onPress={onPress}
54
- onLongPress={onLongPress}
55
- style={{
56
- flex: 1,
57
- alignItems: 'center',
58
- justifyContent: 'center',
59
- backgroundColor: isFocused
60
- ? NaturalColors.grayScale_0
61
- : NaturalColors.grayScale_50,
62
- borderRadius: 20,
63
- }}>
64
- <Animated.Text
65
- style={
66
- isFocused
67
- ? {...CommonStyles.h4_bold, fontWeight: 'bold'}
68
- : CommonStyles.h4_regular
69
- }>
70
- {label}
71
- </Animated.Text>
72
- </TouchableOpacity>
73
- );
74
- })}
75
- </View>
76
- );
77
- }
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
-
3
- export function Settings(): JSX.Element {
4
- return <></>;
5
- }
@@ -1,79 +0,0 @@
1
- import React from 'react';
2
- import {
3
- Image,
4
- ImageStyle,
5
- ScrollView,
6
- StyleSheet,
7
- Text,
8
- TouchableOpacity,
9
- View,
10
- } from 'react-native';
11
- import {CommonSizes} from '../../../core/theme/commonSizes';
12
- import {CarouselItem} from '../types';
13
- import {PrimaryColors} from '../../../core/theme/colors';
14
-
15
- interface CarouselSectionProps {
16
- items: CarouselItem[];
17
- imageStyle?: ImageStyle;
18
- }
19
-
20
- export function CarouselSection({
21
- items,
22
- imageStyle,
23
- }: CarouselSectionProps): JSX.Element {
24
- return (
25
- <ScrollView
26
- horizontal
27
- showsHorizontalScrollIndicator={false}
28
- contentContainerStyle={styles.container}>
29
- {items.map((item, index) => (
30
- <TouchableOpacity
31
- key={item.id}
32
- style={styles.itemContainer}
33
- onPress={() => item.onPress?.(item)}>
34
- <Image
35
- source={{uri: item.imageUrl}}
36
- style={[styles.image, imageStyle]}
37
- />
38
- <View style={styles.textContainer}>
39
- <Text style={styles.title} numberOfLines={1}>
40
- {item.title}
41
- </Text>
42
- {item.subtitle && (
43
- <Text style={styles.subtitle} numberOfLines={1}>
44
- {item.subtitle}
45
- </Text>
46
- )}
47
- </View>
48
- </TouchableOpacity>
49
- ))}
50
- </ScrollView>
51
- );
52
- }
53
-
54
- const styles = StyleSheet.create({
55
- container: {
56
- paddingHorizontal: CommonSizes.spacing.large,
57
- },
58
- itemContainer: {
59
- marginRight: CommonSizes.spacing.medium,
60
- },
61
- image: {
62
- width: 200,
63
- height: 150,
64
- borderRadius: CommonSizes.borderRadius.medium,
65
- },
66
- textContainer: {
67
- marginTop: CommonSizes.spacing.small,
68
- },
69
- title: {
70
- fontSize: 16,
71
- fontWeight: '600',
72
- color: PrimaryColors.PlatinateBlue_700,
73
- },
74
- subtitle: {
75
- fontSize: 14,
76
- color: PrimaryColors.PlatinateBlue_700,
77
- marginTop: 2,
78
- },
79
- });
@@ -1,128 +0,0 @@
1
- import React, {useRef, useState} from 'react';
2
- import {
3
- Dimensions,
4
- FlatList,
5
- Image,
6
- StyleSheet,
7
- Text,
8
- TouchableOpacity,
9
- View,
10
- } from 'react-native';
11
- import {CommonSizes} from '../../../core/theme/commonSizes';
12
- import {CarouselItem} from '../types';
13
- import {NaturalColors, PrimaryColors} from '../../../core/theme/colors';
14
-
15
- const {width} = Dimensions.get('window');
16
- const ITEM_WIDTH = width * 0.85;
17
-
18
- interface FeaturedCarouselProps {
19
- items: CarouselItem[];
20
- }
21
-
22
- export function FeaturedCarousel({items}: FeaturedCarouselProps): JSX.Element {
23
- const [activeIndex, setActiveIndex] = useState(0);
24
- const flatListRef = useRef<FlatList>(null);
25
-
26
- const renderItem = ({item}: {item: CarouselItem}) => (
27
- <TouchableOpacity
28
- style={styles.itemContainer}
29
- onPress={() => item.onPress?.(item)}>
30
- <Image source={{uri: item.imageUrl}} style={styles.image} />
31
- <View style={styles.overlay}>
32
- <Text style={styles.title}>{item.title}</Text>
33
- {item.subtitle && <Text style={styles.subtitle}>{item.subtitle}</Text>}
34
- </View>
35
- </TouchableOpacity>
36
- );
37
-
38
- const renderDot = (index: number) => (
39
- <View
40
- key={index}
41
- style={[styles.dot, index === activeIndex && styles.activeDot]}
42
- />
43
- );
44
-
45
- const handleScroll = (event: any) => {
46
- const slideSize = event.nativeEvent.layoutMeasurement.width;
47
- const index = event.nativeEvent.contentOffset.x / slideSize;
48
- const roundIndex = Math.round(index);
49
- setActiveIndex(roundIndex);
50
- };
51
-
52
- return (
53
- <View>
54
- <FlatList
55
- ref={flatListRef}
56
- data={items}
57
- renderItem={renderItem}
58
- horizontal
59
- pagingEnabled
60
- showsHorizontalScrollIndicator={false}
61
- onScroll={handleScroll}
62
- snapToAlignment="center"
63
- decelerationRate="fast"
64
- snapToInterval={ITEM_WIDTH}
65
- contentContainerStyle={styles.listContainer}
66
- getItemLayout={(_, index) => ({
67
- length: ITEM_WIDTH,
68
- offset: ITEM_WIDTH * index,
69
- index,
70
- })}
71
- />
72
- <View style={styles.pagination}>
73
- {items.map((_, index) => renderDot(index))}
74
- </View>
75
- </View>
76
- );
77
- }
78
-
79
- const styles = StyleSheet.create({
80
- listContainer: {
81
- paddingHorizontal: (width - ITEM_WIDTH) / 2,
82
- },
83
- itemContainer: {
84
- width: ITEM_WIDTH,
85
- height: 250,
86
- },
87
- image: {
88
- width: '100%',
89
- height: '100%',
90
- borderRadius: CommonSizes.borderRadius.large,
91
- },
92
- overlay: {
93
- ...StyleSheet.absoluteFillObject,
94
- backgroundColor: 'rgba(0, 0, 0, 0.3)',
95
- borderRadius: CommonSizes.borderRadius.large,
96
- padding: CommonSizes.spacing.large,
97
- justifyContent: 'flex-end',
98
- },
99
- title: {
100
- fontSize: 20,
101
- fontWeight: '600',
102
- color: NaturalColors.grayScale_0,
103
- },
104
- subtitle: {
105
- fontSize: 16,
106
- color: NaturalColors.grayScale_0,
107
- marginTop: CommonSizes.spacing.small,
108
- },
109
- pagination: {
110
- flexDirection: 'row',
111
- justifyContent: 'center',
112
- alignItems: 'center',
113
- marginTop: CommonSizes.spacing.medium,
114
- },
115
- dot: {
116
- width: 8,
117
- height: 8,
118
- borderRadius: 4,
119
- backgroundColor: NaturalColors.grayScale_50,
120
- marginHorizontal: 4,
121
- },
122
- activeDot: {
123
- backgroundColor: PrimaryColors.PlatinateBlue_700,
124
- width: 12,
125
- height: 12,
126
- borderRadius: 6,
127
- },
128
- });
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
-
3
- export function Main(): JSX.Element {
4
- return <></>;
5
- }
@@ -1,198 +0,0 @@
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 {CommonSizes} from '../../core/theme/commonSizes';
25
- import {CommonStyles} from '../../core/theme/commonStyles';
26
- import type {RootStackParamList} from '../../navigation/types';
27
- import {NaturalColors, PrimaryColors} from '../../core/theme/colors';
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: NaturalColors.grayScale_0,
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: PrimaryColors.PlatinateBlue_700,
195
- textAlign: 'center',
196
- marginTop: 16,
197
- },
198
- });
@@ -1,129 +0,0 @@
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 {CommonSizes} from '../../core/theme/commonSizes';
21
- import {CommonStyles} from '../../core/theme/commonStyles';
22
- import type {RootStackParamList} from '../../navigation/types';
23
- import {NaturalColors, PrimaryColors} from '../../core/theme/colors';
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: NaturalColors.grayScale_0,
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: PrimaryColors.PlatinateBlue_700,
126
- textAlign: 'center',
127
- marginTop: 16,
128
- },
129
- });