@modhamanish/rn-mm-template 1.0.1
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.
- package/MMTemplate/.bundle/config +2 -0
- package/MMTemplate/.eslintrc.js +4 -0
- package/MMTemplate/.prettierrc.js +5 -0
- package/MMTemplate/.watchmanconfig +1 -0
- package/MMTemplate/App.tsx +41 -0
- package/MMTemplate/Gemfile +16 -0
- package/MMTemplate/README.md +109 -0
- package/MMTemplate/__tests__/App.test.tsx +13 -0
- package/MMTemplate/_gitignore +79 -0
- package/MMTemplate/android/app/build.gradle +119 -0
- package/MMTemplate/android/app/debug.keystore +0 -0
- package/MMTemplate/android/app/proguard-rules.pro +10 -0
- package/MMTemplate/android/app/src/main/AndroidManifest.xml +27 -0
- package/MMTemplate/android/app/src/main/java/com/mmtemplate/MainActivity.kt +22 -0
- package/MMTemplate/android/app/src/main/java/com/mmtemplate/MainApplication.kt +27 -0
- package/MMTemplate/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
- package/MMTemplate/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/MMTemplate/android/app/src/main/res/values/strings.xml +3 -0
- package/MMTemplate/android/app/src/main/res/values/styles.xml +9 -0
- package/MMTemplate/android/build.gradle +21 -0
- package/MMTemplate/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/MMTemplate/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/MMTemplate/android/gradle.properties +44 -0
- package/MMTemplate/android/gradlew +251 -0
- package/MMTemplate/android/gradlew.bat +99 -0
- package/MMTemplate/android/settings.gradle +6 -0
- package/MMTemplate/app.json +4 -0
- package/MMTemplate/babel.config.js +8 -0
- package/MMTemplate/index.js +9 -0
- package/MMTemplate/ios/.xcode.env +11 -0
- package/MMTemplate/ios/MMTemplate/AppDelegate.swift +48 -0
- package/MMTemplate/ios/MMTemplate/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
- package/MMTemplate/ios/MMTemplate/Images.xcassets/Contents.json +6 -0
- package/MMTemplate/ios/MMTemplate/Info.plist +55 -0
- package/MMTemplate/ios/MMTemplate/LaunchScreen.storyboard +47 -0
- package/MMTemplate/ios/MMTemplate/PrivacyInfo.xcprivacy +37 -0
- package/MMTemplate/ios/MMTemplate.xcodeproj/project.pbxproj +480 -0
- package/MMTemplate/ios/MMTemplate.xcodeproj/xcshareddata/xcschemes/MMTemplate.xcscheme +88 -0
- package/MMTemplate/ios/Podfile +38 -0
- package/MMTemplate/jest.config.js +3 -0
- package/MMTemplate/metro.config.js +11 -0
- package/MMTemplate/package.json +55 -0
- package/MMTemplate/src/assets/images/index.ts +4 -0
- package/MMTemplate/src/assets/images/logo-dark.png +0 -0
- package/MMTemplate/src/assets/images/logo.png +0 -0
- package/MMTemplate/src/components/AnimationView.tsx +113 -0
- package/MMTemplate/src/components/CustomToast.tsx +46 -0
- package/MMTemplate/src/components/FeatureItem.tsx +59 -0
- package/MMTemplate/src/components/FullScreenContainer.tsx +60 -0
- package/MMTemplate/src/components/InfoCard.tsx +61 -0
- package/MMTemplate/src/components/LanguageSwitcher.tsx +80 -0
- package/MMTemplate/src/components/TextInput.tsx +74 -0
- package/MMTemplate/src/components/ThemeSwitcher.tsx +63 -0
- package/MMTemplate/src/context/AuthContext.tsx +76 -0
- package/MMTemplate/src/context/ThemeContext.tsx +67 -0
- package/MMTemplate/src/locales/en.json +83 -0
- package/MMTemplate/src/locales/hi.json +83 -0
- package/MMTemplate/src/mock/index.ts +5 -0
- package/MMTemplate/src/navigation/AppNavigator.tsx +45 -0
- package/MMTemplate/src/navigation/AppStack.tsx +27 -0
- package/MMTemplate/src/navigation/AuthCheck.tsx +50 -0
- package/MMTemplate/src/navigation/AuthStack.tsx +24 -0
- package/MMTemplate/src/navigation/MainTab.tsx +50 -0
- package/MMTemplate/src/navigation/routes.ts +17 -0
- package/MMTemplate/src/screens/HomeScreen.tsx +296 -0
- package/MMTemplate/src/screens/LoginScreen.tsx +199 -0
- package/MMTemplate/src/screens/ProfileScreen.tsx +171 -0
- package/MMTemplate/src/screens/SettingsScreen.tsx +96 -0
- package/MMTemplate/src/screens/WelcomeScreen.tsx +215 -0
- package/MMTemplate/src/theme/Colors.ts +25 -0
- package/MMTemplate/src/types/components.types.ts +13 -0
- package/MMTemplate/src/types/navigation.types.ts +35 -0
- package/MMTemplate/src/utils/i18n.ts +28 -0
- package/MMTemplate/src/utils/navigationUtils.ts +72 -0
- package/MMTemplate/src/utils/storageHelper.ts +51 -0
- package/MMTemplate/src/utils/utilsHelper.ts +34 -0
- package/MMTemplate/src/utils/validationSchemas.ts +58 -0
- package/MMTemplate/tsconfig.json +8 -0
- package/README.md +108 -0
- package/package.json +22 -0
- package/script.js +62 -0
- package/template.config.js +11 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, ScrollView } from 'react-native';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { useTheme } from '../context/ThemeContext';
|
|
5
|
+
import { ThemeType } from '../theme/Colors';
|
|
6
|
+
import FullScreenContainer from '../components/FullScreenContainer';
|
|
7
|
+
import AnimationView from '../components/AnimationView';
|
|
8
|
+
import LanguageSwitcher from '../components/LanguageSwitcher';
|
|
9
|
+
import ThemeSwitcher from '../components/ThemeSwitcher';
|
|
10
|
+
|
|
11
|
+
const SettingsScreen: FC = () => {
|
|
12
|
+
const { t } = useTranslation();
|
|
13
|
+
const theme = useTheme();
|
|
14
|
+
const styles = getStyles(theme);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<FullScreenContainer style={styles.container} barStyle="light-content">
|
|
18
|
+
<ScrollView
|
|
19
|
+
contentContainerStyle={styles.scrollContent}
|
|
20
|
+
showsVerticalScrollIndicator={false}
|
|
21
|
+
>
|
|
22
|
+
<AnimationView animType="FadeIn" duration={800}>
|
|
23
|
+
<View style={styles.header}>
|
|
24
|
+
<Text style={styles.title}>{t('settings.settings')}</Text>
|
|
25
|
+
<Text style={styles.subtitle}>
|
|
26
|
+
{t('settings.customizeYourExperience')}
|
|
27
|
+
</Text>
|
|
28
|
+
</View>
|
|
29
|
+
</AnimationView>
|
|
30
|
+
|
|
31
|
+
{/* Language Section */}
|
|
32
|
+
<AnimationView delay={200} animType="FadeIn" duration={800}>
|
|
33
|
+
<View style={styles.section}>
|
|
34
|
+
<Text style={styles.sectionTitle}>{t('settings.language')}</Text>
|
|
35
|
+
<Text style={styles.sectionDescription}>
|
|
36
|
+
{t('settings.chooseYourPreferredLanguage')}
|
|
37
|
+
</Text>
|
|
38
|
+
<LanguageSwitcher />
|
|
39
|
+
</View>
|
|
40
|
+
</AnimationView>
|
|
41
|
+
|
|
42
|
+
{/* Theme Section */}
|
|
43
|
+
<AnimationView delay={400} animType="FadeIn" duration={800}>
|
|
44
|
+
<View style={styles.section}>
|
|
45
|
+
<Text style={styles.sectionTitle}>{t('settings.theme')}</Text>
|
|
46
|
+
<Text style={styles.sectionDescription}>
|
|
47
|
+
{t('settings.switchBetweenLightAndDark')}
|
|
48
|
+
</Text>
|
|
49
|
+
<ThemeSwitcher />
|
|
50
|
+
</View>
|
|
51
|
+
</AnimationView>
|
|
52
|
+
</ScrollView>
|
|
53
|
+
</FullScreenContainer>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default SettingsScreen;
|
|
58
|
+
|
|
59
|
+
const getStyles = ({ colors }: ThemeType) =>
|
|
60
|
+
StyleSheet.create({
|
|
61
|
+
container: {
|
|
62
|
+
flex: 1,
|
|
63
|
+
backgroundColor: colors.backgroundColor,
|
|
64
|
+
},
|
|
65
|
+
scrollContent: {
|
|
66
|
+
padding: 20,
|
|
67
|
+
paddingTop: 60,
|
|
68
|
+
},
|
|
69
|
+
header: {
|
|
70
|
+
marginBottom: 32,
|
|
71
|
+
},
|
|
72
|
+
title: {
|
|
73
|
+
fontSize: 32,
|
|
74
|
+
fontWeight: '700',
|
|
75
|
+
color: colors.textColor,
|
|
76
|
+
marginBottom: 8,
|
|
77
|
+
},
|
|
78
|
+
subtitle: {
|
|
79
|
+
fontSize: 16,
|
|
80
|
+
color: colors.textColor + 'CC',
|
|
81
|
+
},
|
|
82
|
+
section: {
|
|
83
|
+
marginBottom: 32,
|
|
84
|
+
},
|
|
85
|
+
sectionTitle: {
|
|
86
|
+
fontSize: 18,
|
|
87
|
+
fontWeight: '600',
|
|
88
|
+
color: colors.textColor,
|
|
89
|
+
marginBottom: 8,
|
|
90
|
+
},
|
|
91
|
+
sectionDescription: {
|
|
92
|
+
fontSize: 14,
|
|
93
|
+
color: colors.textColor + 'CC',
|
|
94
|
+
marginBottom: 16,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StyleSheet,
|
|
3
|
+
Text,
|
|
4
|
+
TouchableOpacity,
|
|
5
|
+
View,
|
|
6
|
+
Linking,
|
|
7
|
+
} from 'react-native';
|
|
8
|
+
import React, { FC, useEffect } from 'react';
|
|
9
|
+
import { useTranslation } from 'react-i18next';
|
|
10
|
+
import { ThemeContextType, useTheme } from '../context/ThemeContext';
|
|
11
|
+
import { Images } from '../assets/images';
|
|
12
|
+
import Animated, {
|
|
13
|
+
useSharedValue,
|
|
14
|
+
useAnimatedStyle,
|
|
15
|
+
withTiming,
|
|
16
|
+
withDelay,
|
|
17
|
+
Easing,
|
|
18
|
+
ReduceMotion,
|
|
19
|
+
} from 'react-native-reanimated';
|
|
20
|
+
import { mobileScreenHeight, mobileScreenWidth } from '../utils/utilsHelper';
|
|
21
|
+
import FullScreenContainer from '../components/FullScreenContainer';
|
|
22
|
+
import { navigate } from '../utils/navigationUtils';
|
|
23
|
+
import Routes from '../navigation/routes';
|
|
24
|
+
|
|
25
|
+
const WelcomeScreen: FC = () => {
|
|
26
|
+
const theme = useTheme();
|
|
27
|
+
const styles = getStyles(theme);
|
|
28
|
+
const { t } = useTranslation();
|
|
29
|
+
|
|
30
|
+
const height = useSharedValue(mobileScreenHeight);
|
|
31
|
+
const width = useSharedValue(mobileScreenWidth * 0.6);
|
|
32
|
+
const opacity = useSharedValue(0);
|
|
33
|
+
const contentOpacity = useSharedValue(0);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
height.value = withDelay(
|
|
37
|
+
500,
|
|
38
|
+
withTiming(mobileScreenHeight * 0.25, { duration: 1000 }),
|
|
39
|
+
);
|
|
40
|
+
width.value = withDelay(
|
|
41
|
+
500,
|
|
42
|
+
withTiming(mobileScreenWidth * 0.45, {
|
|
43
|
+
duration: 1000,
|
|
44
|
+
easing: Easing.quad,
|
|
45
|
+
reduceMotion: ReduceMotion.System,
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
48
|
+
opacity.value = withDelay(1000, withTiming(1, { duration: 1000 }));
|
|
49
|
+
contentOpacity.value = withDelay(1200, withTiming(1, { duration: 800 }));
|
|
50
|
+
}, []);
|
|
51
|
+
|
|
52
|
+
const animatedLogoStyle = useAnimatedStyle(() => {
|
|
53
|
+
return {
|
|
54
|
+
height: height.value,
|
|
55
|
+
width: width.value,
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const animatedContentStyle = useAnimatedStyle(() => {
|
|
60
|
+
return {
|
|
61
|
+
opacity: contentOpacity.value,
|
|
62
|
+
transform: [
|
|
63
|
+
{
|
|
64
|
+
translateY: withTiming(contentOpacity.value === 1 ? 0 : 20, {
|
|
65
|
+
duration: 800,
|
|
66
|
+
}),
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const openGitHub = () => {
|
|
73
|
+
Linking.openURL('https://github.com/modhamanish/mm-template');
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<View style={styles.container}>
|
|
78
|
+
<View style={styles.imageContainer}>
|
|
79
|
+
<Animated.Image
|
|
80
|
+
source={Images.logo}
|
|
81
|
+
style={[animatedLogoStyle, styles.logo]}
|
|
82
|
+
/>
|
|
83
|
+
</View>
|
|
84
|
+
|
|
85
|
+
<Animated.View style={[styles.contentContainer, { opacity }]}>
|
|
86
|
+
<Text style={styles.titleText}>
|
|
87
|
+
<Text style={styles.titleBoldText}>{t('welcome.titleBold')}</Text>
|
|
88
|
+
{t('welcome.titleText')}
|
|
89
|
+
</Text>
|
|
90
|
+
<Text style={styles.matchBoldText}>{t('welcome.appName')}</Text>
|
|
91
|
+
|
|
92
|
+
<Animated.View style={[styles.infoContainer, animatedContentStyle]}>
|
|
93
|
+
<Text style={styles.subtitleText}>{t('welcome.subtitle')}</Text>
|
|
94
|
+
</Animated.View>
|
|
95
|
+
|
|
96
|
+
<FullScreenContainer
|
|
97
|
+
barStyle="light-content"
|
|
98
|
+
edges={['bottom']}
|
|
99
|
+
style={styles.fullScreenContainer}
|
|
100
|
+
>
|
|
101
|
+
<TouchableOpacity
|
|
102
|
+
onPress={openGitHub}
|
|
103
|
+
style={styles.githubButton}
|
|
104
|
+
activeOpacity={0.8}
|
|
105
|
+
>
|
|
106
|
+
<Text style={styles.githubButtonText}>
|
|
107
|
+
📦 {t('welcome.githubButton')}
|
|
108
|
+
</Text>
|
|
109
|
+
</TouchableOpacity>
|
|
110
|
+
|
|
111
|
+
<TouchableOpacity
|
|
112
|
+
onPress={() => navigate(Routes.LoginScreen)}
|
|
113
|
+
style={styles.button}
|
|
114
|
+
activeOpacity={0.8}
|
|
115
|
+
>
|
|
116
|
+
<Text style={styles.buttonText}>{t('welcome.loginButton')}</Text>
|
|
117
|
+
</TouchableOpacity>
|
|
118
|
+
</FullScreenContainer>
|
|
119
|
+
</Animated.View>
|
|
120
|
+
</View>
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export default WelcomeScreen;
|
|
125
|
+
|
|
126
|
+
const getStyles = ({ colors }: ThemeContextType) =>
|
|
127
|
+
StyleSheet.create({
|
|
128
|
+
container: {
|
|
129
|
+
flex: 1,
|
|
130
|
+
backgroundColor: colors.primary,
|
|
131
|
+
},
|
|
132
|
+
imageContainer: {
|
|
133
|
+
alignSelf: 'center',
|
|
134
|
+
marginTop: mobileScreenHeight * 0.05,
|
|
135
|
+
},
|
|
136
|
+
logo: {
|
|
137
|
+
resizeMode: 'contain',
|
|
138
|
+
tintColor: colors.white,
|
|
139
|
+
alignSelf: 'center',
|
|
140
|
+
},
|
|
141
|
+
contentContainer: {
|
|
142
|
+
flex: 1,
|
|
143
|
+
alignItems: 'center',
|
|
144
|
+
paddingHorizontal: 30,
|
|
145
|
+
},
|
|
146
|
+
titleText: {
|
|
147
|
+
color: colors.white,
|
|
148
|
+
fontWeight: '400',
|
|
149
|
+
textAlign: 'center',
|
|
150
|
+
fontSize: 32,
|
|
151
|
+
},
|
|
152
|
+
titleBoldText: {
|
|
153
|
+
fontWeight: '700',
|
|
154
|
+
},
|
|
155
|
+
matchBoldText: {
|
|
156
|
+
color: colors.white,
|
|
157
|
+
fontWeight: '800',
|
|
158
|
+
textAlign: 'center',
|
|
159
|
+
fontSize: 36,
|
|
160
|
+
marginTop: 4,
|
|
161
|
+
},
|
|
162
|
+
infoContainer: {
|
|
163
|
+
marginTop: 20,
|
|
164
|
+
width: '100%',
|
|
165
|
+
},
|
|
166
|
+
subtitleText: {
|
|
167
|
+
color: colors.white + 'CC',
|
|
168
|
+
fontSize: 16,
|
|
169
|
+
textAlign: 'center',
|
|
170
|
+
lineHeight: 24,
|
|
171
|
+
},
|
|
172
|
+
fullScreenContainer: {
|
|
173
|
+
flex: 1,
|
|
174
|
+
width: '100%',
|
|
175
|
+
backgroundColor: 'transparent',
|
|
176
|
+
justifyContent: 'flex-end',
|
|
177
|
+
paddingBottom: 40,
|
|
178
|
+
},
|
|
179
|
+
githubButton: {
|
|
180
|
+
alignSelf: 'center',
|
|
181
|
+
paddingVertical: 12,
|
|
182
|
+
paddingHorizontal: 30,
|
|
183
|
+
backgroundColor: 'rgba(255, 255, 255, 0.15)',
|
|
184
|
+
borderRadius: 12,
|
|
185
|
+
marginBottom: 16,
|
|
186
|
+
borderWidth: 1,
|
|
187
|
+
borderColor: 'rgba(255, 255, 255, 0.3)',
|
|
188
|
+
width: '100%',
|
|
189
|
+
alignItems: 'center',
|
|
190
|
+
},
|
|
191
|
+
githubButtonText: {
|
|
192
|
+
color: colors.white,
|
|
193
|
+
fontSize: 15,
|
|
194
|
+
fontWeight: '600',
|
|
195
|
+
},
|
|
196
|
+
button: {
|
|
197
|
+
alignSelf: 'center',
|
|
198
|
+
paddingVertical: 16,
|
|
199
|
+
paddingHorizontal: 35,
|
|
200
|
+
backgroundColor: colors.backgroundColor,
|
|
201
|
+
borderRadius: 16,
|
|
202
|
+
width: '100%',
|
|
203
|
+
shadowColor: '#000',
|
|
204
|
+
shadowOffset: { width: 0, height: 4 },
|
|
205
|
+
shadowOpacity: 0.2,
|
|
206
|
+
shadowRadius: 5,
|
|
207
|
+
elevation: 5,
|
|
208
|
+
},
|
|
209
|
+
buttonText: {
|
|
210
|
+
color: colors.textColor,
|
|
211
|
+
fontSize: 18,
|
|
212
|
+
textAlign: 'center',
|
|
213
|
+
fontWeight: '700',
|
|
214
|
+
},
|
|
215
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type ThemeType = typeof lightTheme | typeof darkTheme;
|
|
2
|
+
|
|
3
|
+
const lightTheme = {
|
|
4
|
+
colors: {
|
|
5
|
+
primary: '#EF1D0B',
|
|
6
|
+
secondary: '#FFD1D1',
|
|
7
|
+
textColor: '#23272D',
|
|
8
|
+
backgroundColor: '#FFFFFF',
|
|
9
|
+
white: '#FFFFFF',
|
|
10
|
+
black: '#000000',
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const darkTheme = {
|
|
15
|
+
colors: {
|
|
16
|
+
primary: '#EF1D0B',
|
|
17
|
+
secondary: '#FFD1D1',
|
|
18
|
+
textColor: '#FFFFFF',
|
|
19
|
+
backgroundColor: '#121212',
|
|
20
|
+
white: '#FFFFFF',
|
|
21
|
+
black: '#000000',
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export { lightTheme, darkTheme };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { StatusBarStyle, StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
import { Edges } from 'react-native-safe-area-context';
|
|
4
|
+
|
|
5
|
+
export type FullScreenContainerProps = {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
style?: StyleProp<ViewStyle>;
|
|
8
|
+
edges?: Edges;
|
|
9
|
+
barStyle?: StatusBarStyle;
|
|
10
|
+
statusBarHidden?: boolean;
|
|
11
|
+
keyboardAvoidingViewStyle?: StyleProp<ViewStyle>;
|
|
12
|
+
isKeyboardAvoidingView?: boolean;
|
|
13
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
|
2
|
+
|
|
3
|
+
import Routes from '../navigation/routes';
|
|
4
|
+
|
|
5
|
+
export type VerifyNumberScreenProps =
|
|
6
|
+
NativeStackScreenProps<RootStackParamList>;
|
|
7
|
+
|
|
8
|
+
export type RootStackParamList = {
|
|
9
|
+
[Routes.AuthCheck]: undefined;
|
|
10
|
+
[Routes.AuthStack]: undefined;
|
|
11
|
+
[Routes.AppStack]: undefined;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type MainTabParamList = {
|
|
15
|
+
[Routes.HomeScreen]: undefined;
|
|
16
|
+
[Routes.ProfileScreen]: undefined;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type AuthStackParamList = {
|
|
20
|
+
[Routes.WelcomeScreen]: undefined;
|
|
21
|
+
[Routes.LoginScreen]: undefined;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type AppStackParamList = {
|
|
25
|
+
[Routes.MainTab]: undefined;
|
|
26
|
+
[Routes.SettingsScreen]: undefined;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type ParamsType = RootStackParamList &
|
|
30
|
+
AuthStackParamList &
|
|
31
|
+
AppStackParamList &
|
|
32
|
+
MainTabParamList;
|
|
33
|
+
|
|
34
|
+
export type NavigationProps<RouteName extends keyof ParamsType> =
|
|
35
|
+
NativeStackScreenProps<ParamsType, RouteName>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import i18n from 'i18next';
|
|
2
|
+
import { initReactI18next } from 'react-i18next';
|
|
3
|
+
import StorageHelper from './storageHelper';
|
|
4
|
+
import en from '../locales/en.json';
|
|
5
|
+
import hi from '../locales/hi.json';
|
|
6
|
+
|
|
7
|
+
// Get saved language or default to English
|
|
8
|
+
const savedLanguage = StorageHelper.getItem(
|
|
9
|
+
StorageHelper.STORAGE_KEYS.LANGUAGE,
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
i18n.use(initReactI18next).init({
|
|
13
|
+
resources: {
|
|
14
|
+
en: {
|
|
15
|
+
translation: en,
|
|
16
|
+
},
|
|
17
|
+
hi: {
|
|
18
|
+
translation: hi,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
lng: savedLanguage || 'en',
|
|
22
|
+
fallbackLng: 'en',
|
|
23
|
+
interpolation: {
|
|
24
|
+
escapeValue: false,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export default i18n;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CommonActions,
|
|
3
|
+
createNavigationContainerRef,
|
|
4
|
+
StackActions,
|
|
5
|
+
} from '@react-navigation/native';
|
|
6
|
+
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
|
7
|
+
import { ParamsType } from '../types/navigation.types';
|
|
8
|
+
|
|
9
|
+
export const navigationRef =
|
|
10
|
+
createNavigationContainerRef<NativeStackNavigationProp<ParamsType>>();
|
|
11
|
+
|
|
12
|
+
export async function navigate<RouteName extends keyof ParamsType>(
|
|
13
|
+
routeName: RouteName,
|
|
14
|
+
params?: ParamsType[RouteName],
|
|
15
|
+
) {
|
|
16
|
+
if (navigationRef.isReady()) {
|
|
17
|
+
navigationRef.dispatch(CommonActions.navigateDeprecated(routeName, params));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function navigateTab<RouteName extends keyof ParamsType>(
|
|
22
|
+
routeName: RouteName,
|
|
23
|
+
params?: ParamsType[RouteName],
|
|
24
|
+
) {
|
|
25
|
+
if (navigationRef.isReady()) {
|
|
26
|
+
if (navigationRef.canGoBack()) {
|
|
27
|
+
navigationRef.dispatch(StackActions.popToTop());
|
|
28
|
+
}
|
|
29
|
+
navigate(routeName, params);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function replace<RouteName extends keyof ParamsType>(
|
|
34
|
+
routeName: RouteName,
|
|
35
|
+
params?: ParamsType[RouteName],
|
|
36
|
+
) {
|
|
37
|
+
if (navigationRef.isReady()) {
|
|
38
|
+
navigationRef.dispatch(StackActions.replace(routeName, params));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function resetAndNavigate<RouteName extends keyof ParamsType>(
|
|
43
|
+
routeName: RouteName,
|
|
44
|
+
) {
|
|
45
|
+
if (navigationRef.isReady()) {
|
|
46
|
+
navigationRef.dispatch(
|
|
47
|
+
CommonActions.reset({
|
|
48
|
+
index: 0,
|
|
49
|
+
routes: [{ name: routeName }],
|
|
50
|
+
}),
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function goBack() {
|
|
56
|
+
if (navigationRef.isReady()) {
|
|
57
|
+
navigationRef.dispatch(CommonActions.goBack());
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function push<RouteName extends keyof ParamsType>(
|
|
62
|
+
routeName: RouteName,
|
|
63
|
+
params?: ParamsType[RouteName],
|
|
64
|
+
) {
|
|
65
|
+
if (navigationRef.isReady()) {
|
|
66
|
+
navigationRef.dispatch(StackActions.push(routeName, params));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function prepareNavigation() {
|
|
71
|
+
return navigationRef.isReady();
|
|
72
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createMMKV } from 'react-native-mmkv';
|
|
2
|
+
|
|
3
|
+
export const storage = createMMKV();
|
|
4
|
+
|
|
5
|
+
enum STORAGE_KEYS {
|
|
6
|
+
USER = 'user',
|
|
7
|
+
LANGUAGE = 'language',
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const saveItem = (key: STORAGE_KEYS, value: string) => {
|
|
11
|
+
try {
|
|
12
|
+
storage.set(key, value);
|
|
13
|
+
return true;
|
|
14
|
+
} catch (error) {
|
|
15
|
+
console.log(error);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const removeItem = (key: STORAGE_KEYS) => {
|
|
20
|
+
try {
|
|
21
|
+
storage.remove(key);
|
|
22
|
+
return true;
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.log(error);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const getItem = (key: STORAGE_KEYS) => {
|
|
29
|
+
try {
|
|
30
|
+
const value = storage.getString(key);
|
|
31
|
+
return value ? value : undefined;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.log(error);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const clearStorage = () => {
|
|
38
|
+
try {
|
|
39
|
+
storage.clearAll();
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.log(error);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default {
|
|
46
|
+
removeItem,
|
|
47
|
+
getItem,
|
|
48
|
+
saveItem,
|
|
49
|
+
clearStorage,
|
|
50
|
+
STORAGE_KEYS,
|
|
51
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Dimensions, Platform } from 'react-native';
|
|
2
|
+
|
|
3
|
+
const { width: mobileWidth, height: mobileHeight } = Dimensions.get('window');
|
|
4
|
+
const { width: mobileScreenWidth, height: mobileScreenHeight } =
|
|
5
|
+
Dimensions.get('screen');
|
|
6
|
+
|
|
7
|
+
const isIos = Platform.OS === 'ios';
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
mobileHeight,
|
|
11
|
+
mobileWidth,
|
|
12
|
+
mobileScreenWidth,
|
|
13
|
+
mobileScreenHeight,
|
|
14
|
+
isIos,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const hexWithOpacity = (hex: string, opacityPercent: number) => {
|
|
18
|
+
hex = hex.replace('#', '');
|
|
19
|
+
|
|
20
|
+
if (hex.length === 3) {
|
|
21
|
+
hex = hex
|
|
22
|
+
.split('')
|
|
23
|
+
.map(ch => ch + ch)
|
|
24
|
+
.join('');
|
|
25
|
+
}
|
|
26
|
+
if (hex.length !== 6) {
|
|
27
|
+
return `#${hex}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const alpha = Math.round((opacityPercent / 100) * 255);
|
|
31
|
+
const alphaHex = alpha.toString(16).padStart(2, '0').toUpperCase();
|
|
32
|
+
|
|
33
|
+
return `#${hex}${alphaHex}`;
|
|
34
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as Yup from 'yup';
|
|
2
|
+
|
|
3
|
+
// Login Validation Schema
|
|
4
|
+
export const LoginSchema = Yup.object().shape({
|
|
5
|
+
email: Yup.string()
|
|
6
|
+
.email('Invalid email address')
|
|
7
|
+
.required('Email is required'),
|
|
8
|
+
password: Yup.string()
|
|
9
|
+
.min(6, 'Password must be at least 6 characters')
|
|
10
|
+
.required('Password is required'),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
// Sign Up Validation Schema
|
|
14
|
+
export const SignUpSchema = Yup.object().shape({
|
|
15
|
+
name: Yup.string()
|
|
16
|
+
.min(2, 'Name must be at least 2 characters')
|
|
17
|
+
.required('Name is required'),
|
|
18
|
+
email: Yup.string()
|
|
19
|
+
.email('Invalid email address')
|
|
20
|
+
.required('Email is required'),
|
|
21
|
+
password: Yup.string()
|
|
22
|
+
.min(6, 'Password must be at least 6 characters')
|
|
23
|
+
.required('Password is required'),
|
|
24
|
+
confirmPassword: Yup.string()
|
|
25
|
+
.oneOf([Yup.ref('password')], 'Passwords must match')
|
|
26
|
+
.required('Confirm password is required'),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Forgot Password Validation Schema
|
|
30
|
+
export const ForgotPasswordSchema = Yup.object().shape({
|
|
31
|
+
email: Yup.string()
|
|
32
|
+
.email('Invalid email address')
|
|
33
|
+
.required('Email is required'),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Change Password Validation Schema
|
|
37
|
+
export const ChangePasswordSchema = Yup.object().shape({
|
|
38
|
+
currentPassword: Yup.string().required('Current password is required'),
|
|
39
|
+
newPassword: Yup.string()
|
|
40
|
+
.min(6, 'Password must be at least 6 characters')
|
|
41
|
+
.required('New password is required'),
|
|
42
|
+
confirmPassword: Yup.string()
|
|
43
|
+
.oneOf([Yup.ref('newPassword')], 'Passwords must match')
|
|
44
|
+
.required('Confirm password is required'),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Profile Update Validation Schema
|
|
48
|
+
export const ProfileUpdateSchema = Yup.object().shape({
|
|
49
|
+
name: Yup.string()
|
|
50
|
+
.min(2, 'Name must be at least 2 characters')
|
|
51
|
+
.required('Name is required'),
|
|
52
|
+
email: Yup.string()
|
|
53
|
+
.email('Invalid email address')
|
|
54
|
+
.required('Email is required'),
|
|
55
|
+
phone: Yup.string()
|
|
56
|
+
.matches(/^[0-9]{10}$/, 'Phone number must be 10 digits')
|
|
57
|
+
.optional(),
|
|
58
|
+
});
|