@fadyshawky/react-native-magic 1.0.0

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 (165) hide show
  1. package/.vscode/settings.json +7 -0
  2. package/README.md +269 -0
  3. package/package.json +36 -0
  4. package/template/.bundle/config +2 -0
  5. package/template/.env.development +5 -0
  6. package/template/.env.production +5 -0
  7. package/template/.env.staging +5 -0
  8. package/template/.eslintrc.js +4 -0
  9. package/template/.prettierrc.js +7 -0
  10. package/template/.watchmanconfig +1 -0
  11. package/template/App.tsx +34 -0
  12. package/template/Gemfile +9 -0
  13. package/template/Gemfile.lock +117 -0
  14. package/template/README.md +79 -0
  15. package/template/__tests__/App.test.tsx +17 -0
  16. package/template/android/app/build.gradle +128 -0
  17. package/template/android/app/debug.keystore +0 -0
  18. package/template/android/app/proguard-rules.pro +10 -0
  19. package/template/android/app/src/debug/AndroidManifest.xml +9 -0
  20. package/template/android/app/src/main/AndroidManifest.xml +26 -0
  21. package/template/android/app/src/main/java/com/reactnativemagic/MainActivity.kt +22 -0
  22. package/template/android/app/src/main/java/com/reactnativemagic/MainApplication.kt +44 -0
  23. package/template/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
  24. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  25. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  26. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  27. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  28. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  29. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  30. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  31. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  32. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  33. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  34. package/template/android/app/src/main/res/values/strings.xml +3 -0
  35. package/template/android/app/src/main/res/values/styles.xml +9 -0
  36. package/template/android/build.gradle +21 -0
  37. package/template/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  38. package/template/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  39. package/template/android/gradle.properties +39 -0
  40. package/template/android/gradlew +252 -0
  41. package/template/android/gradlew.bat +94 -0
  42. package/template/android/settings.gradle +6 -0
  43. package/template/app.json +4 -0
  44. package/template/babel.config.js +3 -0
  45. package/template/index.js +9 -0
  46. package/template/install-dev.sh +1 -0
  47. package/template/install.sh +1 -0
  48. package/template/ios/.xcode.env +11 -0
  49. package/template/ios/Podfile +42 -0
  50. package/template/ios/Podfile.lock +2461 -0
  51. package/template/ios/reactnativemagic/AppDelegate.h +6 -0
  52. package/template/ios/reactnativemagic/AppDelegate.mm +31 -0
  53. package/template/ios/reactnativemagic/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  54. package/template/ios/reactnativemagic/Images.xcassets/Contents.json +6 -0
  55. package/template/ios/reactnativemagic/Info.plist +52 -0
  56. package/template/ios/reactnativemagic/LaunchScreen.storyboard +47 -0
  57. package/template/ios/reactnativemagic/PrivacyInfo.xcprivacy +46 -0
  58. package/template/ios/reactnativemagic/main.m +10 -0
  59. package/template/ios/reactnativemagic copy-Info.plist +52 -0
  60. package/template/ios/reactnativemagic.xcodeproj/project.pbxproj +836 -0
  61. package/template/ios/reactnativemagic.xcodeproj/xcshareddata/xcschemes/reactnativemagic.xcscheme +88 -0
  62. package/template/ios/reactnativemagic.xcworkspace/contents.xcworkspacedata +10 -0
  63. package/template/ios/reactnativemagic.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  64. package/template/ios/reactnativemagicTests/Info.plist +24 -0
  65. package/template/ios/reactnativemagicTests/reactnativemagicTests.m +66 -0
  66. package/template/ios/tmp.xcconfig +2 -0
  67. package/template/jest.config.js +3 -0
  68. package/template/metro.config.js +11 -0
  69. package/template/package-lock.json +18315 -0
  70. package/template/package.json +125 -0
  71. package/template/resources/symbols/SFSymbols.ts +2614 -0
  72. package/template/src/common/ImageResources.g.ts +14 -0
  73. package/template/src/common/components/Background.tsx +34 -0
  74. package/template/src/common/components/EmptyView.tsx +31 -0
  75. package/template/src/common/components/FlatListWrapper.tsx +66 -0
  76. package/template/src/common/components/IconPlatform.tsx +17 -0
  77. package/template/src/common/components/ImageCropPickerButton.tsx +108 -0
  78. package/template/src/common/components/LoadingComponent.tsx +16 -0
  79. package/template/src/common/components/PhotoTakingButton.tsx +99 -0
  80. package/template/src/common/components/PrimaryButton.tsx +305 -0
  81. package/template/src/common/components/PrimaryTextInput.tsx +287 -0
  82. package/template/src/common/components/RadioButton.tsx +73 -0
  83. package/template/src/common/components/RadioIcon.tsx +63 -0
  84. package/template/src/common/components/Separator.tsx +39 -0
  85. package/template/src/common/components/Svg.tsx +25 -0
  86. package/template/src/common/components/TouchablePlatform.tsx +70 -0
  87. package/template/src/common/components/TryAgain.tsx +56 -0
  88. package/template/src/common/helpers/arrayHelpers.ts +29 -0
  89. package/template/src/common/helpers/calculatePage.ts +16 -0
  90. package/template/src/common/helpers/colorHelpers.ts +34 -0
  91. package/template/src/common/helpers/defaultKeyIdExtractor.ts +5 -0
  92. package/template/src/common/helpers/dialogsHelpers.ts +66 -0
  93. package/template/src/common/helpers/imageHelpers.ts +5 -0
  94. package/template/src/common/helpers/inAppReviewHelper.ts +31 -0
  95. package/template/src/common/helpers/netInfoHelpers.ts +42 -0
  96. package/template/src/common/helpers/orientationHelpers.ts +25 -0
  97. package/template/src/common/helpers/regexHelpers.ts +7 -0
  98. package/template/src/common/helpers/shareHelpers.ts +47 -0
  99. package/template/src/common/helpers/stringsHelpers.ts +15 -0
  100. package/template/src/common/hooks/useBackHandler.ts +10 -0
  101. package/template/src/common/hooks/useDebounce.ts +17 -0
  102. package/template/src/common/hooks/useEventRegister.ts +50 -0
  103. package/template/src/common/hooks/useFlatListActions.ts +31 -0
  104. package/template/src/common/hooks/usePrevious.ts +11 -0
  105. package/template/src/common/hooks/useWhyDidYouUpdate.ts +27 -0
  106. package/template/src/common/localization/dateFormatter.ts +108 -0
  107. package/template/src/common/localization/intlFormatter.ts +37 -0
  108. package/template/src/common/localization/localization.ts +51 -0
  109. package/template/src/common/localization/translations/commonLocalization.ts +29 -0
  110. package/template/src/common/localization/translations/emptyLocalization.ts +6 -0
  111. package/template/src/common/localization/translations/errorsLocalization.ts +22 -0
  112. package/template/src/common/localization/translations/homeLocalization.ts +5 -0
  113. package/template/src/common/localization/translations/loginLocalization.ts +14 -0
  114. package/template/src/common/localization/translations/onboardingLocalization.ts +13 -0
  115. package/template/src/common/localization/translations/pagesLocalization.ts +14 -0
  116. package/template/src/common/localization/translations/profileLocalization.ts +6 -0
  117. package/template/src/common/urls/baseUrlOpener.ts +31 -0
  118. package/template/src/common/urls/emailUrl.ts +20 -0
  119. package/template/src/common/urls/httpUrl.ts +19 -0
  120. package/template/src/common/urls/mapUrl.ts +22 -0
  121. package/template/src/common/urls/phoneUrl.ts +16 -0
  122. package/template/src/common/utils/createPerfectSize.ts +15 -0
  123. package/template/src/common/utils/listHandlers.ts +30 -0
  124. package/template/src/common/utils/newState.ts +5 -0
  125. package/template/src/common/utils/serializeQueryParams.ts +10 -0
  126. package/template/src/common/validations/authValidations.ts +15 -0
  127. package/template/src/common/validations/commonValidations.ts +39 -0
  128. package/template/src/common/validations/errorValidations.ts +72 -0
  129. package/template/src/common/validations/hooks/useDatesError.ts +40 -0
  130. package/template/src/common/validations/hooks/useInputError.ts +30 -0
  131. package/template/src/common/validations/profileValidations.ts +30 -0
  132. package/template/src/common/validations/validationConstants.ts +20 -0
  133. package/template/src/core/api/responseHandlers.ts +43 -0
  134. package/template/src/core/api/serverHeaders.ts +39 -0
  135. package/template/src/core/store/app/appSlice.ts +12 -0
  136. package/template/src/core/store/app/appState.ts +3 -0
  137. package/template/src/core/store/reduxHelpers.ts +11 -0
  138. package/template/src/core/store/rootReducer.ts +10 -0
  139. package/template/src/core/store/store.tsx +41 -0
  140. package/template/src/core/store/user/userActions.ts +31 -0
  141. package/template/src/core/store/user/userSlice.ts +62 -0
  142. package/template/src/core/store/user/userState.ts +44 -0
  143. package/template/src/core/theme/colors.ts +117 -0
  144. package/template/src/core/theme/commonConsts.ts +45 -0
  145. package/template/src/core/theme/commonSizes.ts +70 -0
  146. package/template/src/core/theme/commonStyles.ts +228 -0
  147. package/template/src/core/theme/fonts.ts +12 -0
  148. package/template/src/navigation/AuthStack.tsx +39 -0
  149. package/template/src/navigation/HeaderComponents.tsx +104 -0
  150. package/template/src/navigation/MainNavigation.tsx +55 -0
  151. package/template/src/navigation/MainStack.tsx +99 -0
  152. package/template/src/navigation/RootNavigation.tsx +33 -0
  153. package/template/src/navigation/TabBar.tsx +94 -0
  154. package/template/src/navigation/TopTabBar.tsx +75 -0
  155. package/template/src/navigation/types.ts +5 -0
  156. package/template/src/screens/Login/Login.tsx +114 -0
  157. package/template/src/screens/Settings/Settings.tsx +5 -0
  158. package/template/src/screens/main/Main.tsx +5 -0
  159. package/template/src/screens/profile/Profile.tsx +5 -0
  160. package/template/src/screens/splash/Splash.tsx +19 -0
  161. package/template/src/sheetManager/sheets.tsx +14 -0
  162. package/template/tsconfig.json +3 -0
  163. package/template/types/index.ts +108 -0
  164. package/template/types/react-native-config.d.ts +19 -0
  165. package/template.config.js +4 -0
@@ -0,0 +1,104 @@
1
+ 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';
6
+ import {CommonSizes} from '../core/theme/commonSizes';
7
+ import {NativeStackNavigationProp} from '@react-navigation/native-stack';
8
+ import {RootStackParamList} from './types';
9
+
10
+ export function Header({title}: {title: string}) {
11
+ return (
12
+ <View style={styles.headerBase}>
13
+ <Text style={CommonStyles.h2_regular}>{title}</Text>
14
+ </View>
15
+ );
16
+ }
17
+
18
+ export function HeaderBack({
19
+ title,
20
+ navigation,
21
+ }: {
22
+ title: string;
23
+ navigation: NativeStackNavigationProp<RootStackParamList>;
24
+ }) {
25
+ return (
26
+ <View style={styles.headerWithBack}>
27
+ <View style={styles.titleContainer}>
28
+ <Text style={CommonStyles.h2_regular}>{title}</Text>
29
+ </View>
30
+ <BackButton navigation={navigation} />
31
+ </View>
32
+ );
33
+ }
34
+
35
+ export function WebViewHeader({
36
+ navigation,
37
+ }: {
38
+ navigation: NativeStackNavigationProp<RootStackParamList>;
39
+ }) {
40
+ return (
41
+ <View style={styles.webViewHeader}>
42
+ <BackButton navigation={navigation} />
43
+ </View>
44
+ );
45
+ }
46
+
47
+ function BackButton({
48
+ navigation,
49
+ }: {
50
+ navigation: NativeStackNavigationProp<RootStackParamList>;
51
+ }) {
52
+ return (
53
+ <TouchableOpacity
54
+ style={styles.backButton}
55
+ onPress={() => navigation.pop()}>
56
+ <Image style={styles.backIcon} source={0} />
57
+ </TouchableOpacity>
58
+ );
59
+ }
60
+
61
+ const styles = StyleSheet.create({
62
+ headerBase: {
63
+ width: '100%',
64
+ height: 80,
65
+ backgroundColor: 'transparent',
66
+ justifyContent: 'flex-end',
67
+ alignItems: 'center',
68
+ marginBottom: 25,
69
+ },
70
+ headerWithBack: {
71
+ width: '100%',
72
+ height: 80,
73
+ backgroundColor: 'transparent',
74
+ justifyContent: 'flex-start',
75
+ alignItems: 'center',
76
+ paddingHorizontal: CommonSizes.spacing.large,
77
+ flexDirection: 'row',
78
+ },
79
+ webViewHeader: {
80
+ width: '100%',
81
+ height: 120,
82
+ backgroundColor: 'white',
83
+ justifyContent: 'flex-start',
84
+ alignItems: 'center',
85
+ paddingHorizontal: CommonSizes.spacing.large,
86
+ flexDirection: 'row',
87
+ },
88
+ titleContainer: {
89
+ width: screenWidth,
90
+ alignItems: 'center',
91
+ position: 'absolute',
92
+ zIndex: 0,
93
+ },
94
+ backButton: {
95
+ width: 60,
96
+ height: 40,
97
+ justifyContent: 'flex-end',
98
+ },
99
+ backIcon: {
100
+ width: 20,
101
+ height: 20,
102
+ resizeMode: 'contain',
103
+ },
104
+ });
@@ -0,0 +1,55 @@
1
+ // In App.js in a new project
2
+
3
+ import {NavigationContainer} from '@react-navigation/native';
4
+ import * as React from 'react';
5
+ import {useRef} from 'react';
6
+ import {useAppSelector} from '../core/store/reduxHelpers';
7
+ import {AuthStack} from './AuthStack';
8
+ import {AppMainNavigator} from './MainStack';
9
+ import {navigationRef} from './RootNavigation';
10
+
11
+ function AppNavigator() {
12
+ const routeNameRef = useRef<string | undefined>(undefined);
13
+ const {accessToken} = useAppSelector(state => state.user);
14
+
15
+ return (
16
+ <NavigationContainer
17
+ ref={navigationRef}
18
+ theme={{
19
+ dark: false,
20
+ colors: {
21
+ primary: '#000',
22
+ background: 'transparent',
23
+ card: '#fff',
24
+ text: '#000',
25
+ border: '#000',
26
+ notification: '#ff0000',
27
+ },
28
+ fonts: {
29
+ regular: {
30
+ fontFamily: 'System',
31
+ fontWeight: 'normal',
32
+ },
33
+ medium: {
34
+ fontFamily: 'System',
35
+ fontWeight: '500',
36
+ },
37
+ bold: {
38
+ fontFamily: 'System',
39
+ fontWeight: '700',
40
+ },
41
+ heavy: {
42
+ fontFamily: 'System',
43
+ fontWeight: '900',
44
+ },
45
+ },
46
+ }}
47
+ onReady={() => {
48
+ routeNameRef.current = navigationRef.current?.getCurrentRoute()?.name;
49
+ }}>
50
+ {!accessToken ? <AuthStack /> : <AppMainNavigator />}
51
+ </NavigationContainer>
52
+ );
53
+ }
54
+
55
+ export default AppNavigator;
@@ -0,0 +1,99 @@
1
+ import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
2
+ import {
3
+ createNativeStackNavigator,
4
+ NativeStackHeaderProps,
5
+ NativeStackNavigationProp,
6
+ } from '@react-navigation/native-stack';
7
+ import React from 'react';
8
+ import {ImageResources} from '../common/ImageResources.g';
9
+ import {localization} from '../common/localization/localization';
10
+ import {Main} from '../screens/main/Main';
11
+ import {Profile} from '../screens/profile/Profile';
12
+ import {Settings} from '../screens/Settings/Settings';
13
+ import {Header, HeaderBack} from './HeaderComponents';
14
+ import {TabBar} from './TabBar';
15
+ import {RootStackParamList} from './types';
16
+
17
+ const MainScreens = [
18
+ {
19
+ id: 'Main',
20
+ component: Main,
21
+ options: {
22
+ headerShown: false,
23
+ },
24
+ },
25
+ {
26
+ id: 'Profile',
27
+ component: Profile,
28
+ options: {
29
+ tabBarLabel: 'Profile',
30
+ header: () => {
31
+ return <Header title={localization.profile.studentProfile} />;
32
+ },
33
+ },
34
+ },
35
+ ];
36
+
37
+ const AppStack = [
38
+ {
39
+ id: 'Home',
40
+ component: MainTabs,
41
+ options: {
42
+ headerShown: false,
43
+ },
44
+ },
45
+ {
46
+ id: 'Settings',
47
+ component: Settings,
48
+ options: {
49
+ header: (props: NativeStackHeaderProps) => {
50
+ return (
51
+ <HeaderBack
52
+ title={'Settings'}
53
+ navigation={
54
+ props.navigation as NativeStackNavigationProp<RootStackParamList>
55
+ }
56
+ />
57
+ );
58
+ },
59
+ },
60
+ },
61
+ ];
62
+
63
+ const Stack = createNativeStackNavigator();
64
+
65
+ const Tab = createBottomTabNavigator();
66
+
67
+ function MainTabs() {
68
+ return (
69
+ <Tab.Navigator
70
+ initialRouteName="Main"
71
+ tabBar={props => <TabBar {...props} />}>
72
+ {MainScreens.map(s => (
73
+ <Tab.Screen
74
+ key={s.id}
75
+ name={s.id}
76
+ component={s.component}
77
+ options={s.options}
78
+ />
79
+ ))}
80
+ </Tab.Navigator>
81
+ );
82
+ }
83
+
84
+ export function AppMainNavigator() {
85
+ return (
86
+ <Stack.Navigator screenOptions={{animation: 'none'}}>
87
+ {AppStack.map(s => {
88
+ return (
89
+ <Stack.Screen
90
+ key={s.id}
91
+ name={s.id}
92
+ component={s.component}
93
+ options={s.options}
94
+ />
95
+ );
96
+ })}
97
+ </Stack.Navigator>
98
+ );
99
+ }
@@ -0,0 +1,33 @@
1
+ import {createNavigationContainerRef} from '@react-navigation/native';
2
+ import {CommonActions} from '@react-navigation/native';
3
+
4
+ type RootStackParamList = {
5
+ Home: undefined;
6
+ // Add other screens here
7
+ Profile: {userId: string};
8
+ Settings: undefined;
9
+ };
10
+
11
+ export const navigationRef = createNavigationContainerRef<RootStackParamList>();
12
+
13
+ export function navigate<T extends keyof RootStackParamList>(
14
+ name: never,
15
+ params?: RootStackParamList[T],
16
+ ) {
17
+ if (navigationRef.isReady()) {
18
+ // Type assertion is not needed since name and params are already properly typed
19
+ navigationRef.current?.navigate(name, params);
20
+ }
21
+ }
22
+
23
+ // Function to reset the navigation stack and navigate to the "Home" screen
24
+ export const resetToHomeScreen = () => {
25
+ navigationRef.dispatch(
26
+ CommonActions.reset({
27
+ index: 0,
28
+ routes: [{name: 'Home'}],
29
+ }),
30
+ );
31
+ };
32
+
33
+ // Call the function to reset the navigation stack and navigate to the "Home" screen
@@ -0,0 +1,94 @@
1
+ import React from 'react';
2
+ import {View, Text, TouchableOpacity, Image, StyleSheet} from 'react-native';
3
+ import {CommonStyles} from '../core/theme/commonStyles';
4
+ import {Colors} from '../core/theme/colors';
5
+ import {
6
+ BottomTabBarProps,
7
+ BottomTabNavigationOptions,
8
+ } from '@react-navigation/bottom-tabs';
9
+ import {ImageSourcePropType} from 'react-native';
10
+ import {toString} from 'lodash';
11
+
12
+ interface TabBarOptions extends BottomTabNavigationOptions {
13
+ selectedIcon: ImageSourcePropType;
14
+ icon: ImageSourcePropType;
15
+ tabBarTestID?: string;
16
+ }
17
+
18
+ export function TabBar({state, descriptors, navigation}: BottomTabBarProps) {
19
+ return (
20
+ <View style={styles.container}>
21
+ {state.routes.map((route, index) => {
22
+ const {options} = descriptors[route.key] as unknown as {
23
+ options: TabBarOptions;
24
+ };
25
+ const label =
26
+ options.tabBarLabel !== undefined
27
+ ? options.tabBarLabel
28
+ : options.title !== undefined
29
+ ? options.title
30
+ : route.name;
31
+
32
+ const isFocused = state.index === index;
33
+
34
+ const onPress = () => {
35
+ const event = navigation.emit({
36
+ type: 'tabPress',
37
+ target: route.key,
38
+ canPreventDefault: true,
39
+ });
40
+
41
+ if (!isFocused && !event.defaultPrevented) {
42
+ navigation.navigate(route.name, route.params);
43
+ }
44
+ };
45
+
46
+ const onLongPress = () => {
47
+ navigation.emit({
48
+ type: 'tabLongPress',
49
+ target: route.key,
50
+ });
51
+ };
52
+
53
+ return (
54
+ <TouchableOpacity
55
+ key={route.key}
56
+ accessibilityRole="button"
57
+ accessibilityState={isFocused ? {selected: true} : {}}
58
+ accessibilityLabel={options.tabBarAccessibilityLabel}
59
+ testID={options.tabBarTestID}
60
+ onPress={onPress}
61
+ onLongPress={onLongPress}
62
+ style={styles.tabButton}>
63
+ <Image source={isFocused ? options.selectedIcon : options.icon} />
64
+ <Text style={[styles.label, isFocused && styles.labelFocused]}>
65
+ {toString(label)}
66
+ </Text>
67
+ </TouchableOpacity>
68
+ );
69
+ })}
70
+ </View>
71
+ );
72
+ }
73
+
74
+ const styles = StyleSheet.create({
75
+ container: {
76
+ flexDirection: 'row',
77
+ alignItems: 'center',
78
+ height: 100,
79
+ borderTopLeftRadius: 50,
80
+ borderTopRightRadius: 50,
81
+ justifyContent: 'space-evenly',
82
+ ...CommonStyles.shadow,
83
+ },
84
+ tabButton: {
85
+ flex: 1,
86
+ alignItems: 'center',
87
+ },
88
+ label: {
89
+ color: Colors.gray,
90
+ },
91
+ labelFocused: {
92
+ color: Colors.primary100,
93
+ },
94
+ });
@@ -0,0 +1,75 @@
1
+ import {Animated, View, TouchableOpacity} from 'react-native';
2
+ import {Colors} from '../core/theme/colors';
3
+ import {CommonStyles, screenWidth} from '../core/theme/commonStyles';
4
+
5
+ export function TopBar({state, descriptors, navigation, position}: any) {
6
+ return (
7
+ <View
8
+ style={{
9
+ flexDirection: 'row',
10
+ backgroundColor: Colors.gray,
11
+ width: screenWidth - 60,
12
+ alignSelf: 'center',
13
+ height: 40,
14
+ borderRadius: 20,
15
+ marginBottom: 24,
16
+ }}>
17
+ {state.routes.map((route, index) => {
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 ? Colors.white : Colors.gray,
60
+ borderRadius: 20,
61
+ }}>
62
+ <Animated.Text
63
+ style={
64
+ isFocused
65
+ ? {...CommonStyles.h4_bold, fontWeight: 'bold'}
66
+ : CommonStyles.h4_regular
67
+ }>
68
+ {label}
69
+ </Animated.Text>
70
+ </TouchableOpacity>
71
+ );
72
+ })}
73
+ </View>
74
+ );
75
+ }
@@ -0,0 +1,5 @@
1
+ export type RootStackParamList = {
2
+ Home: undefined;
3
+ Details: {id: string};
4
+ // ... add other screens as needed
5
+ };
@@ -0,0 +1,114 @@
1
+ import {useNavigation} from '@react-navigation/native';
2
+ import {toLower} from 'lodash';
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 {useAppDispatch} from '../../core/store/reduxHelpers';
17
+ import {userLogin} from '../../core/store/user/userActions';
18
+ import {Colors} from '../../core/theme/colors';
19
+ import {CommonSizes} from '../../core/theme/commonSizes';
20
+ import {CommonStyles} from '../../core/theme/commonStyles';
21
+
22
+ export function Login(): JSX.Element {
23
+ const dispatch = useAppDispatch();
24
+ const [email, setEmail] = useState('');
25
+ const [password, setPassword] = useState('');
26
+ const [loading, setLoading] = useState(false);
27
+
28
+ async function loginUser() {
29
+ setLoading(true);
30
+ await dispatch(
31
+ userLogin({
32
+ email: toLower(email),
33
+ password,
34
+ }),
35
+ );
36
+
37
+ setLoading(false);
38
+ }
39
+ const scroll = useRef<KeyboardAwareScrollView>(null);
40
+ function scrollToInput(reactNode: any) {
41
+ // Add a 'scroll' ref to your ScrollView
42
+
43
+ // setTimeout(() => {
44
+ scroll.current?.scrollToFocusedInput(reactNode);
45
+ // }, 500);
46
+ }
47
+ return (
48
+ <KeyboardAwareScrollView
49
+ ref={scroll}
50
+ resetScrollToCoords={{x: 0, y: 0}}
51
+ scrollEnabled={true}
52
+ enableOnAndroid={true}
53
+ testID={'MainPageID'}
54
+ contentContainerStyle={styles.contentContainer}
55
+ contentInsetAdjustmentBehavior={'automatic'}
56
+ style={styles.container}>
57
+ <Text style={CommonStyles.h1_semiBold}>{localization.login.Login}</Text>
58
+ <PrimaryTextInput
59
+ onFocus={(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
60
+ scrollToInput(findNodeHandle(event.target));
61
+ }}
62
+ autoCapitalize="none"
63
+ value={email}
64
+ onChangeText={setEmail}
65
+ containerStyle={CommonStyles.textInputContainer}
66
+ label={localization.login.Email}
67
+ placeholder={localization.login.EnterEmail}
68
+ />
69
+ <PrimaryTextInput
70
+ onFocus={(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
71
+ scrollToInput(findNodeHandle(event.target));
72
+ }}
73
+ clearButtonMode="never"
74
+ value={password}
75
+ secureTextEntry
76
+ onChangeText={setPassword}
77
+ containerStyle={CommonStyles.textInputContainer}
78
+ label={localization.login.Password}
79
+ placeholder={localization.login.EnterPassword}
80
+ />
81
+ <PrimaryButton
82
+ label={localization.login.forgetPassword}
83
+ type={ButtonType.borderless}
84
+ style={{alignSelf: 'flex-end'}}
85
+ />
86
+ <PrimaryButton
87
+ isLoading={loading}
88
+ onPress={loginUser}
89
+ label={localization.login.continue}
90
+ type={ButtonType.solid}
91
+ />
92
+ </KeyboardAwareScrollView>
93
+ );
94
+ }
95
+
96
+ const styles = StyleSheet.create({
97
+ imageContainer: {
98
+ ...CommonStyles.flex1,
99
+ justifyContent: 'flex-end',
100
+ },
101
+ container: {
102
+ flexGrow: 1,
103
+ backgroundColor: Colors.white,
104
+ borderTopRightRadius: CommonSizes.spacing.large,
105
+ borderTopLeftRadius: CommonSizes.spacing.large,
106
+ },
107
+ contentContainer: {
108
+ justifyContent: 'center',
109
+ alignItems: 'center',
110
+ paddingHorizontal: CommonSizes.spacing.large,
111
+ paddingVertical: 26,
112
+ gap: 16,
113
+ },
114
+ });
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+
3
+ export function Settings(): JSX.Element {
4
+ return <></>;
5
+ }
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+
3
+ export function Main(): JSX.Element {
4
+ return <></>;
5
+ }
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+
3
+ export function Profile(): JSX.Element {
4
+ return <></>;
5
+ }
@@ -0,0 +1,19 @@
1
+ import {useNavigation} from '@react-navigation/native';
2
+ import React, {useEffect} from 'react';
3
+ import {LoadingComponent} from '../../common/components/LoadingComponent';
4
+ import {useAppSelector} from '../../core/store/reduxHelpers';
5
+
6
+ export function Splash(): JSX.Element {
7
+ const isUserLoggedIn = useAppSelector(state => state.user.accessToken);
8
+ const navigation = useNavigation();
9
+
10
+ useEffect(() => {
11
+ if (isUserLoggedIn) {
12
+ navigation.navigate('Main' as never);
13
+ } else {
14
+ navigation.navigate('Login' as never);
15
+ }
16
+ }, [isUserLoggedIn]);
17
+
18
+ return <LoadingComponent />;
19
+ }
@@ -0,0 +1,14 @@
1
+ // We extend some of the types here to give us great intellisense
2
+
3
+ import {registerSheet, SheetDefinition} from 'react-native-actions-sheet';
4
+
5
+ type Sheet = SheetDefinition;
6
+
7
+ // across the app for all registered sheets.
8
+ declare module 'react-native-actions-sheet' {
9
+ interface Sheets {
10
+ 'first-sheet': Sheet;
11
+ }
12
+ }
13
+
14
+ export {};
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "@react-native/typescript-config/tsconfig.json"
3
+ }