@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.
Files changed (91) hide show
  1. package/MMTemplate/.bundle/config +2 -0
  2. package/MMTemplate/.eslintrc.js +4 -0
  3. package/MMTemplate/.prettierrc.js +5 -0
  4. package/MMTemplate/.watchmanconfig +1 -0
  5. package/MMTemplate/App.tsx +41 -0
  6. package/MMTemplate/Gemfile +16 -0
  7. package/MMTemplate/README.md +109 -0
  8. package/MMTemplate/__tests__/App.test.tsx +13 -0
  9. package/MMTemplate/_gitignore +79 -0
  10. package/MMTemplate/android/app/build.gradle +119 -0
  11. package/MMTemplate/android/app/debug.keystore +0 -0
  12. package/MMTemplate/android/app/proguard-rules.pro +10 -0
  13. package/MMTemplate/android/app/src/main/AndroidManifest.xml +27 -0
  14. package/MMTemplate/android/app/src/main/java/com/mmtemplate/MainActivity.kt +22 -0
  15. package/MMTemplate/android/app/src/main/java/com/mmtemplate/MainApplication.kt +27 -0
  16. package/MMTemplate/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
  17. package/MMTemplate/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  18. package/MMTemplate/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  19. package/MMTemplate/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  20. package/MMTemplate/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  21. package/MMTemplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  22. package/MMTemplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  23. package/MMTemplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  24. package/MMTemplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  25. package/MMTemplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  26. package/MMTemplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  27. package/MMTemplate/android/app/src/main/res/values/strings.xml +3 -0
  28. package/MMTemplate/android/app/src/main/res/values/styles.xml +9 -0
  29. package/MMTemplate/android/build.gradle +21 -0
  30. package/MMTemplate/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  31. package/MMTemplate/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  32. package/MMTemplate/android/gradle.properties +44 -0
  33. package/MMTemplate/android/gradlew +251 -0
  34. package/MMTemplate/android/gradlew.bat +99 -0
  35. package/MMTemplate/android/settings.gradle +6 -0
  36. package/MMTemplate/app.json +4 -0
  37. package/MMTemplate/babel.config.js +8 -0
  38. package/MMTemplate/index.js +9 -0
  39. package/MMTemplate/ios/.xcode.env +11 -0
  40. package/MMTemplate/ios/MMTemplate/AppDelegate.swift +48 -0
  41. package/MMTemplate/ios/MMTemplate/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  42. package/MMTemplate/ios/MMTemplate/Images.xcassets/Contents.json +6 -0
  43. package/MMTemplate/ios/MMTemplate/Info.plist +55 -0
  44. package/MMTemplate/ios/MMTemplate/LaunchScreen.storyboard +47 -0
  45. package/MMTemplate/ios/MMTemplate/PrivacyInfo.xcprivacy +37 -0
  46. package/MMTemplate/ios/MMTemplate.xcodeproj/project.pbxproj +480 -0
  47. package/MMTemplate/ios/MMTemplate.xcodeproj/xcshareddata/xcschemes/MMTemplate.xcscheme +88 -0
  48. package/MMTemplate/ios/Podfile +38 -0
  49. package/MMTemplate/jest.config.js +3 -0
  50. package/MMTemplate/metro.config.js +11 -0
  51. package/MMTemplate/package.json +55 -0
  52. package/MMTemplate/src/assets/images/index.ts +4 -0
  53. package/MMTemplate/src/assets/images/logo-dark.png +0 -0
  54. package/MMTemplate/src/assets/images/logo.png +0 -0
  55. package/MMTemplate/src/components/AnimationView.tsx +113 -0
  56. package/MMTemplate/src/components/CustomToast.tsx +46 -0
  57. package/MMTemplate/src/components/FeatureItem.tsx +59 -0
  58. package/MMTemplate/src/components/FullScreenContainer.tsx +60 -0
  59. package/MMTemplate/src/components/InfoCard.tsx +61 -0
  60. package/MMTemplate/src/components/LanguageSwitcher.tsx +80 -0
  61. package/MMTemplate/src/components/TextInput.tsx +74 -0
  62. package/MMTemplate/src/components/ThemeSwitcher.tsx +63 -0
  63. package/MMTemplate/src/context/AuthContext.tsx +76 -0
  64. package/MMTemplate/src/context/ThemeContext.tsx +67 -0
  65. package/MMTemplate/src/locales/en.json +83 -0
  66. package/MMTemplate/src/locales/hi.json +83 -0
  67. package/MMTemplate/src/mock/index.ts +5 -0
  68. package/MMTemplate/src/navigation/AppNavigator.tsx +45 -0
  69. package/MMTemplate/src/navigation/AppStack.tsx +27 -0
  70. package/MMTemplate/src/navigation/AuthCheck.tsx +50 -0
  71. package/MMTemplate/src/navigation/AuthStack.tsx +24 -0
  72. package/MMTemplate/src/navigation/MainTab.tsx +50 -0
  73. package/MMTemplate/src/navigation/routes.ts +17 -0
  74. package/MMTemplate/src/screens/HomeScreen.tsx +296 -0
  75. package/MMTemplate/src/screens/LoginScreen.tsx +199 -0
  76. package/MMTemplate/src/screens/ProfileScreen.tsx +171 -0
  77. package/MMTemplate/src/screens/SettingsScreen.tsx +96 -0
  78. package/MMTemplate/src/screens/WelcomeScreen.tsx +215 -0
  79. package/MMTemplate/src/theme/Colors.ts +25 -0
  80. package/MMTemplate/src/types/components.types.ts +13 -0
  81. package/MMTemplate/src/types/navigation.types.ts +35 -0
  82. package/MMTemplate/src/utils/i18n.ts +28 -0
  83. package/MMTemplate/src/utils/navigationUtils.ts +72 -0
  84. package/MMTemplate/src/utils/storageHelper.ts +51 -0
  85. package/MMTemplate/src/utils/utilsHelper.ts +34 -0
  86. package/MMTemplate/src/utils/validationSchemas.ts +58 -0
  87. package/MMTemplate/tsconfig.json +8 -0
  88. package/README.md +108 -0
  89. package/package.json +22 -0
  90. package/script.js +62 -0
  91. 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
+ });
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "@react-native/typescript-config",
3
+ "compilerOptions": {
4
+ "types": ["jest"],
5
+ },
6
+ "include": ["**/*.ts", "**/*.tsx"],
7
+ "exclude": ["**/node_modules", "**/Pods"]
8
+ }