@modhamanish/rn-mm-template 1.0.4 → 1.1.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.
- package/MMTemplate/.eslintrc.js +95 -1
- package/MMTemplate/.husky/pre-commit +2 -0
- package/MMTemplate/.prettierrc.js +2 -0
- package/MMTemplate/App.tsx +27 -21
- package/MMTemplate/README.md +76 -35
- package/MMTemplate/__tests__/App.test.tsx +5 -3
- package/MMTemplate/babel.config.js +24 -1
- package/MMTemplate/index.js +1 -0
- package/MMTemplate/lint_errors.txt +7 -0
- package/MMTemplate/package.json +24 -4
- package/MMTemplate/src/components/AnimationView.tsx +54 -69
- package/MMTemplate/src/components/AppText.tsx +7 -4
- package/MMTemplate/src/components/CustomAlert.tsx +203 -0
- package/MMTemplate/src/components/CustomToast.tsx +2 -1
- package/MMTemplate/src/components/ErrorBoundaryFallback.tsx +127 -0
- package/MMTemplate/src/components/FeatureItem.tsx +8 -6
- package/MMTemplate/src/components/FullScreenContainer.tsx +9 -7
- package/MMTemplate/src/components/InfoCard.tsx +8 -6
- package/MMTemplate/src/components/LanguageSwitcher.tsx +8 -6
- package/MMTemplate/src/components/TextInput.tsx +25 -15
- package/MMTemplate/src/components/ThemeSwitcher.tsx +4 -3
- package/MMTemplate/src/context/AuthContext.tsx +5 -4
- package/MMTemplate/src/context/ThemeContext.tsx +10 -19
- package/MMTemplate/src/locales/en.json +4 -1
- package/MMTemplate/src/locales/hi.json +4 -1
- package/MMTemplate/src/navigation/AppNavigator.tsx +7 -8
- package/MMTemplate/src/navigation/AppStack.tsx +6 -6
- package/MMTemplate/src/navigation/AuthCheck.tsx +11 -10
- package/MMTemplate/src/navigation/AuthStack.tsx +6 -4
- package/MMTemplate/src/navigation/MainTab.tsx +19 -13
- package/MMTemplate/src/screens/AddNoteScreen.tsx +20 -14
- package/MMTemplate/src/screens/HomeScreen.tsx +21 -15
- package/MMTemplate/src/screens/LoginScreen.tsx +21 -18
- package/MMTemplate/src/screens/NoteScreen.tsx +18 -16
- package/MMTemplate/src/screens/ProfileScreen.tsx +16 -13
- package/MMTemplate/src/screens/SettingsScreen.tsx +14 -11
- package/MMTemplate/src/screens/WelcomeScreen.tsx +19 -13
- package/MMTemplate/src/services/axiosInstance.ts +7 -5
- package/MMTemplate/src/services/note.query.ts +7 -5
- package/MMTemplate/src/theme/{Colors.ts → colors.ts} +6 -0
- package/MMTemplate/src/types/components.types.ts +38 -0
- package/MMTemplate/src/types/navigation.types.ts +1 -1
- package/MMTemplate/src/utils/i18n.ts +8 -6
- package/MMTemplate/src/utils/navigationUtils.ts +2 -1
- package/MMTemplate/src/utils/storageHelper.ts +8 -8
- package/MMTemplate/src/utils/utilsHelper.ts +1 -0
- package/MMTemplate/tsconfig.json +27 -0
- package/README.md +3 -1
- package/package.json +4 -1
- package/release.js +75 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React, { FC, useMemo } from 'react';
|
|
1
2
|
import {
|
|
2
3
|
StyleSheet,
|
|
3
4
|
FlatList,
|
|
@@ -6,23 +7,24 @@ import {
|
|
|
6
7
|
ActivityIndicator,
|
|
7
8
|
RefreshControl,
|
|
8
9
|
} from 'react-native';
|
|
9
|
-
|
|
10
|
-
import React, { FC, useMemo } from 'react';
|
|
11
|
-
import FullScreenContainer from '../components/FullScreenContainer';
|
|
12
|
-
import { useTheme } from '../context/ThemeContext';
|
|
10
|
+
|
|
13
11
|
import { useTranslation } from 'react-i18next';
|
|
14
|
-
import { ThemeType } from '../theme/Colors';
|
|
15
|
-
import { useGetNotesQuery } from '../services/note.query';
|
|
16
|
-
import { Note } from '../types/services.types';
|
|
17
|
-
import AnimationView from '../components/AnimationView';
|
|
18
12
|
|
|
19
|
-
import {
|
|
20
|
-
import
|
|
13
|
+
import { Note } from '@app-types/services.types';
|
|
14
|
+
import AnimationView from '@components/AnimationView';
|
|
15
|
+
import AppText from '@components/AppText';
|
|
16
|
+
import FullScreenContainer from '@components/FullScreenContainer';
|
|
17
|
+
import { useTheme } from '@context/ThemeContext';
|
|
18
|
+
import Routes from '@navigation/routes';
|
|
19
|
+
import { useGetNotesQuery } from '@services/note.query';
|
|
20
|
+
import { ThemeType } from '@src/theme/colors';
|
|
21
|
+
import { navigate } from '@utils/navigationUtils';
|
|
22
|
+
import { hexWithOpacity } from '@utils/utilsHelper';
|
|
21
23
|
|
|
22
24
|
const NoteScreen: FC = () => {
|
|
23
25
|
const { t } = useTranslation();
|
|
24
26
|
const theme = useTheme();
|
|
25
|
-
const styles = getStyles(theme);
|
|
27
|
+
const styles = useMemo(() => getStyles(theme), [theme]);
|
|
26
28
|
|
|
27
29
|
const { data: notes, isLoading, refetch, isRefetching } = useGetNotesQuery();
|
|
28
30
|
|
|
@@ -156,7 +158,7 @@ const getStyles = ({ colors }: ThemeType) =>
|
|
|
156
158
|
letterSpacing: -0.5,
|
|
157
159
|
},
|
|
158
160
|
headerSubtitle: {
|
|
159
|
-
color: colors.textColor
|
|
161
|
+
color: hexWithOpacity(colors.textColor, 50),
|
|
160
162
|
marginTop: 4,
|
|
161
163
|
},
|
|
162
164
|
noteCard: {
|
|
@@ -165,7 +167,7 @@ const getStyles = ({ colors }: ThemeType) =>
|
|
|
165
167
|
padding: 16,
|
|
166
168
|
marginBottom: 16,
|
|
167
169
|
borderWidth: 1,
|
|
168
|
-
borderColor: colors.textColor
|
|
170
|
+
borderColor: hexWithOpacity(colors.textColor, 8),
|
|
169
171
|
shadowColor: colors.black,
|
|
170
172
|
shadowOffset: { width: 0, height: 2 },
|
|
171
173
|
shadowOpacity: 0.05,
|
|
@@ -184,7 +186,7 @@ const getStyles = ({ colors }: ThemeType) =>
|
|
|
184
186
|
marginRight: 8,
|
|
185
187
|
},
|
|
186
188
|
noteTag: {
|
|
187
|
-
backgroundColor: colors.primary
|
|
189
|
+
backgroundColor: hexWithOpacity(colors.primary, 8),
|
|
188
190
|
paddingHorizontal: 8,
|
|
189
191
|
paddingVertical: 4,
|
|
190
192
|
borderRadius: 8,
|
|
@@ -194,7 +196,7 @@ const getStyles = ({ colors }: ThemeType) =>
|
|
|
194
196
|
textTransform: 'uppercase',
|
|
195
197
|
},
|
|
196
198
|
noteContent: {
|
|
197
|
-
color: colors.textColor
|
|
199
|
+
color: hexWithOpacity(colors.textColor, 70),
|
|
198
200
|
lineHeight: 20,
|
|
199
201
|
},
|
|
200
202
|
emptyContainer: {
|
|
@@ -207,7 +209,7 @@ const getStyles = ({ colors }: ThemeType) =>
|
|
|
207
209
|
marginBottom: 16,
|
|
208
210
|
},
|
|
209
211
|
emptyText: {
|
|
210
|
-
color: colors.textColor
|
|
212
|
+
color: hexWithOpacity(colors.textColor, 50),
|
|
211
213
|
marginBottom: 24,
|
|
212
214
|
},
|
|
213
215
|
addNoteButtonSmall: {
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
import React, { FC } from 'react';
|
|
1
|
+
import React, { FC, useMemo } from 'react';
|
|
2
2
|
import { View, TouchableOpacity, StyleSheet, Alert } from 'react-native';
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import Routes from '
|
|
5
|
+
|
|
6
|
+
import AnimationView from '@components/AnimationView';
|
|
7
|
+
import AppText from '@components/AppText';
|
|
8
|
+
import FullScreenContainer from '@components/FullScreenContainer';
|
|
9
|
+
import InfoCard from '@components/InfoCard';
|
|
10
|
+
import { useAuth } from '@context/AuthContext';
|
|
11
|
+
import { useTheme } from '@context/ThemeContext';
|
|
12
|
+
import Routes from '@navigation/routes';
|
|
13
|
+
import { ThemeType } from '@src/theme/colors';
|
|
14
|
+
import { navigate } from '@utils/navigationUtils';
|
|
15
|
+
import { hexWithOpacity } from '@utils/utilsHelper';
|
|
13
16
|
|
|
14
17
|
const ProfileScreen: FC = () => {
|
|
15
18
|
const { t } = useTranslation();
|
|
16
19
|
const theme = useTheme();
|
|
17
|
-
const styles = getStyles(theme);
|
|
20
|
+
const styles = useMemo(() => getStyles(theme), [theme]);
|
|
18
21
|
const { user, handleLogout } = useAuth();
|
|
19
22
|
|
|
20
23
|
const confirmLogout = () => {
|
|
@@ -133,7 +136,7 @@ const getStyles = ({ colors }: ThemeType) =>
|
|
|
133
136
|
marginBottom: 4,
|
|
134
137
|
},
|
|
135
138
|
email: {
|
|
136
|
-
color: colors.textColor
|
|
139
|
+
color: hexWithOpacity(colors.textColor, 80),
|
|
137
140
|
},
|
|
138
141
|
infoRow: {
|
|
139
142
|
flexDirection: 'row',
|
|
@@ -145,7 +148,7 @@ const getStyles = ({ colors }: ThemeType) =>
|
|
|
145
148
|
color: colors.textColor,
|
|
146
149
|
},
|
|
147
150
|
infoValue: {
|
|
148
|
-
color: colors.textColor
|
|
151
|
+
color: hexWithOpacity(colors.textColor, 80),
|
|
149
152
|
},
|
|
150
153
|
logoutButton: {
|
|
151
154
|
backgroundColor: colors.primary,
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import React, { FC } from 'react';
|
|
1
|
+
import React, { FC, useMemo } from 'react';
|
|
2
2
|
import { View, StyleSheet, ScrollView } from 'react-native';
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import LanguageSwitcher from '
|
|
10
|
-
import ThemeSwitcher from '
|
|
5
|
+
|
|
6
|
+
import AnimationView from '@components/AnimationView';
|
|
7
|
+
import AppText from '@components/AppText';
|
|
8
|
+
import FullScreenContainer from '@components/FullScreenContainer';
|
|
9
|
+
import LanguageSwitcher from '@components/LanguageSwitcher';
|
|
10
|
+
import ThemeSwitcher from '@components/ThemeSwitcher';
|
|
11
|
+
import { useTheme } from '@context/ThemeContext';
|
|
12
|
+
import { ThemeType } from '@src/theme/colors';
|
|
13
|
+
import { hexWithOpacity } from '@utils/utilsHelper';
|
|
11
14
|
|
|
12
15
|
const SettingsScreen: FC = () => {
|
|
13
16
|
const { t } = useTranslation();
|
|
14
17
|
const theme = useTheme();
|
|
15
|
-
const styles = getStyles(theme);
|
|
18
|
+
const styles = useMemo(() => getStyles(theme), [theme]);
|
|
16
19
|
|
|
17
20
|
return (
|
|
18
21
|
<FullScreenContainer style={styles.container} barStyle="light-content">
|
|
@@ -81,7 +84,7 @@ const getStyles = ({ colors }: ThemeType) =>
|
|
|
81
84
|
marginBottom: 8,
|
|
82
85
|
},
|
|
83
86
|
subtitle: {
|
|
84
|
-
color: colors.textColor
|
|
87
|
+
color: hexWithOpacity(colors.textColor, 80),
|
|
85
88
|
},
|
|
86
89
|
section: {
|
|
87
90
|
marginBottom: 32,
|
|
@@ -91,7 +94,7 @@ const getStyles = ({ colors }: ThemeType) =>
|
|
|
91
94
|
marginBottom: 8,
|
|
92
95
|
},
|
|
93
96
|
sectionDescription: {
|
|
94
|
-
color: colors.textColor
|
|
97
|
+
color: hexWithOpacity(colors.textColor, 80),
|
|
95
98
|
marginBottom: 16,
|
|
96
99
|
},
|
|
97
100
|
});
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import React, { FC, useEffect, useMemo } from 'react';
|
|
1
2
|
import { StyleSheet, TouchableOpacity, View, Linking } from 'react-native';
|
|
2
|
-
|
|
3
|
+
|
|
3
4
|
import { useTranslation } from 'react-i18next';
|
|
4
|
-
import { ThemeContextType, useTheme } from '../context/ThemeContext';
|
|
5
|
-
import { Images } from '../assets/images';
|
|
6
5
|
import Animated, {
|
|
7
6
|
useSharedValue,
|
|
8
7
|
useAnimatedStyle,
|
|
@@ -11,15 +10,22 @@ import Animated, {
|
|
|
11
10
|
Easing,
|
|
12
11
|
ReduceMotion,
|
|
13
12
|
} from 'react-native-reanimated';
|
|
14
|
-
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
13
|
+
|
|
14
|
+
import { Images } from '@assets/images';
|
|
15
|
+
import AppText from '@components/AppText';
|
|
16
|
+
import FullScreenContainer from '@components/FullScreenContainer';
|
|
17
|
+
import { ThemeContextType, useTheme } from '@context/ThemeContext';
|
|
18
|
+
import Routes from '@navigation/routes';
|
|
19
|
+
import { navigate } from '@utils/navigationUtils';
|
|
20
|
+
import {
|
|
21
|
+
hexWithOpacity,
|
|
22
|
+
mobileScreenHeight,
|
|
23
|
+
mobileScreenWidth,
|
|
24
|
+
} from '@utils/utilsHelper';
|
|
19
25
|
|
|
20
26
|
const WelcomeScreen: FC = () => {
|
|
21
27
|
const theme = useTheme();
|
|
22
|
-
const styles = getStyles(theme);
|
|
28
|
+
const styles = useMemo(() => getStyles(theme), [theme]);
|
|
23
29
|
const { t } = useTranslation();
|
|
24
30
|
|
|
25
31
|
const height = useSharedValue(mobileScreenHeight);
|
|
@@ -42,7 +48,7 @@ const WelcomeScreen: FC = () => {
|
|
|
42
48
|
);
|
|
43
49
|
opacity.value = withDelay(1000, withTiming(1, { duration: 1000 }));
|
|
44
50
|
contentOpacity.value = withDelay(1200, withTiming(1, { duration: 800 }));
|
|
45
|
-
}, []);
|
|
51
|
+
}, [height, width, opacity, contentOpacity]);
|
|
46
52
|
|
|
47
53
|
const animatedLogoStyle = useAnimatedStyle(() => {
|
|
48
54
|
return {
|
|
@@ -169,7 +175,7 @@ const getStyles = ({ colors }: ThemeContextType) =>
|
|
|
169
175
|
width: '100%',
|
|
170
176
|
},
|
|
171
177
|
subtitleText: {
|
|
172
|
-
color: colors.white
|
|
178
|
+
color: hexWithOpacity(colors.white, 80),
|
|
173
179
|
textAlign: 'center',
|
|
174
180
|
lineHeight: 24,
|
|
175
181
|
},
|
|
@@ -184,11 +190,11 @@ const getStyles = ({ colors }: ThemeContextType) =>
|
|
|
184
190
|
alignSelf: 'center',
|
|
185
191
|
paddingVertical: 12,
|
|
186
192
|
paddingHorizontal: 30,
|
|
187
|
-
backgroundColor:
|
|
193
|
+
backgroundColor: hexWithOpacity(colors.white, 15),
|
|
188
194
|
borderRadius: 12,
|
|
189
195
|
marginBottom: 16,
|
|
190
196
|
borderWidth: 1,
|
|
191
|
-
borderColor:
|
|
197
|
+
borderColor: hexWithOpacity(colors.white, 30),
|
|
192
198
|
width: '100%',
|
|
193
199
|
alignItems: 'center',
|
|
194
200
|
},
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Platform } from 'react-native';
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import
|
|
2
|
+
|
|
3
|
+
import axios, { AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
|
4
|
+
|
|
5
|
+
import Routes from '@navigation/routes';
|
|
6
|
+
import { resetAndNavigate } from '@utils/navigationUtils';
|
|
7
|
+
import storageHelper from '@utils/storageHelper';
|
|
6
8
|
|
|
7
9
|
const axiosInstance = axios.create({
|
|
8
10
|
baseURL: 'https://user-driven-mock-api-generator-serv.vercel.app/man',
|
|
@@ -12,7 +14,7 @@ const ResponseInterceptor = (response: AxiosResponse) => {
|
|
|
12
14
|
return response;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
|
-
const RequestInterceptor = (config:
|
|
17
|
+
const RequestInterceptor = (config: InternalAxiosRequestConfig) => {
|
|
16
18
|
const token = storageHelper.getItem(storageHelper.STORAGE_KEYS.AUTH_TOKEN);
|
|
17
19
|
config.headers.device = Platform.OS;
|
|
18
20
|
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
2
|
-
import { QUERY_KEY } from './queryKeys';
|
|
3
|
-
import { axiosInstance } from './axiosInstance';
|
|
4
|
-
import { GetNotesResponse, Note } from '../types/services.types';
|
|
5
|
-
import Toast from 'react-native-toast-message';
|
|
6
2
|
import { useTranslation } from 'react-i18next';
|
|
7
|
-
import
|
|
3
|
+
import Toast from 'react-native-toast-message';
|
|
4
|
+
|
|
5
|
+
import { GetNotesResponse, Note } from '@app-types/services.types';
|
|
6
|
+
import { goBack } from '@utils/navigationUtils';
|
|
7
|
+
|
|
8
|
+
import { axiosInstance } from './axiosInstance';
|
|
9
|
+
import { QUERY_KEY } from './queryKeys';
|
|
8
10
|
|
|
9
11
|
export const useGetNotesQuery = () => {
|
|
10
12
|
return useQuery({
|
|
@@ -8,6 +8,9 @@ const lightTheme = {
|
|
|
8
8
|
backgroundColor: '#FFFFFF',
|
|
9
9
|
white: '#FFFFFF',
|
|
10
10
|
black: '#000000',
|
|
11
|
+
borderColor: '#E1E1E1',
|
|
12
|
+
error: '#D32F2F',
|
|
13
|
+
success: '#4CD964',
|
|
11
14
|
},
|
|
12
15
|
};
|
|
13
16
|
|
|
@@ -19,6 +22,9 @@ const darkTheme = {
|
|
|
19
22
|
backgroundColor: '#121212',
|
|
20
23
|
white: '#FFFFFF',
|
|
21
24
|
black: '#000000',
|
|
25
|
+
borderColor: '#333333',
|
|
26
|
+
error: '#D32F2F',
|
|
27
|
+
success: '#4CD964',
|
|
22
28
|
},
|
|
23
29
|
};
|
|
24
30
|
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
TextStyle,
|
|
7
7
|
ViewStyle,
|
|
8
8
|
} from 'react-native';
|
|
9
|
+
|
|
9
10
|
import { Edges } from 'react-native-safe-area-context';
|
|
10
11
|
|
|
11
12
|
export type AppTextSize =
|
|
@@ -57,3 +58,40 @@ export type FullScreenContainerProps = {
|
|
|
57
58
|
keyboardAvoidingViewStyle?: StyleProp<ViewStyle>;
|
|
58
59
|
isKeyboardAvoidingView?: boolean;
|
|
59
60
|
};
|
|
61
|
+
|
|
62
|
+
export interface AlertOptionsProps {
|
|
63
|
+
title?: string;
|
|
64
|
+
message?: string;
|
|
65
|
+
onConfirm?: () => void;
|
|
66
|
+
onCancel?: () => void;
|
|
67
|
+
onClose?: () => void;
|
|
68
|
+
confirmText?: string;
|
|
69
|
+
cancelText?: string;
|
|
70
|
+
boxStyle?: ViewStyle;
|
|
71
|
+
titleStyle?: TextStyle;
|
|
72
|
+
messageStyle?: TextStyle;
|
|
73
|
+
confirmButtonStyle?: ViewStyle;
|
|
74
|
+
cancelButtonStyle?: ViewStyle;
|
|
75
|
+
confirmTextStyle?: TextStyle;
|
|
76
|
+
cancelTextStyle?: TextStyle;
|
|
77
|
+
isCancellable?: boolean;
|
|
78
|
+
isError?: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type ShowAlert = (opts: AlertOptionsProps) => void;
|
|
82
|
+
|
|
83
|
+
export interface AnimationViewProps {
|
|
84
|
+
children: React.ReactNode;
|
|
85
|
+
animType:
|
|
86
|
+
| 'FadeIn'
|
|
87
|
+
| 'FadeOut'
|
|
88
|
+
| 'ZoomIn'
|
|
89
|
+
| 'ZoomOut'
|
|
90
|
+
| 'RotateIn'
|
|
91
|
+
| 'RotateOut'
|
|
92
|
+
| 'SlideInDown';
|
|
93
|
+
duration?: number;
|
|
94
|
+
delay?: number;
|
|
95
|
+
rotateValue?: number;
|
|
96
|
+
style?: StyleProp<ViewStyle | TextStyle>;
|
|
97
|
+
}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import
|
|
1
|
+
import appI18n from 'i18next';
|
|
2
2
|
import { initReactI18next } from 'react-i18next';
|
|
3
|
-
|
|
4
|
-
import en from '
|
|
5
|
-
import hi from '
|
|
3
|
+
|
|
4
|
+
import en from '@locales/en.json';
|
|
5
|
+
import hi from '@locales/hi.json';
|
|
6
|
+
import StorageHelper from '@utils/storageHelper';
|
|
6
7
|
|
|
7
8
|
// Get saved language or default to English
|
|
8
9
|
const savedLanguage = StorageHelper.getItem(
|
|
9
10
|
StorageHelper.STORAGE_KEYS.LANGUAGE,
|
|
10
11
|
);
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
// eslint-disable-next-line import/no-named-as-default-member
|
|
14
|
+
appI18n.use(initReactI18next).init({
|
|
13
15
|
resources: {
|
|
14
16
|
en: {
|
|
15
17
|
translation: en,
|
|
@@ -25,4 +27,4 @@ i18n.use(initReactI18next).init({
|
|
|
25
27
|
},
|
|
26
28
|
});
|
|
27
29
|
|
|
28
|
-
export default
|
|
30
|
+
export default appI18n;
|
|
@@ -4,7 +4,8 @@ import {
|
|
|
4
4
|
StackActions,
|
|
5
5
|
} from '@react-navigation/native';
|
|
6
6
|
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
import { ParamsType } from '@app-types/navigation.types';
|
|
8
9
|
|
|
9
10
|
export const navigationRef =
|
|
10
11
|
createNavigationContainerRef<NativeStackNavigationProp<ParamsType>>();
|
|
@@ -13,8 +13,8 @@ const saveItem = (key: STORAGE_KEYS, value: string) => {
|
|
|
13
13
|
try {
|
|
14
14
|
storage.set(key, value);
|
|
15
15
|
return true;
|
|
16
|
-
} catch
|
|
17
|
-
|
|
16
|
+
} catch {
|
|
17
|
+
// Silent catch
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
20
|
|
|
@@ -22,8 +22,8 @@ const removeItem = (key: STORAGE_KEYS) => {
|
|
|
22
22
|
try {
|
|
23
23
|
storage.remove(key);
|
|
24
24
|
return true;
|
|
25
|
-
} catch
|
|
26
|
-
|
|
25
|
+
} catch {
|
|
26
|
+
// Silent catch
|
|
27
27
|
}
|
|
28
28
|
};
|
|
29
29
|
|
|
@@ -31,16 +31,16 @@ const getItem = (key: STORAGE_KEYS) => {
|
|
|
31
31
|
try {
|
|
32
32
|
const value = storage.getString(key);
|
|
33
33
|
return value ? value : undefined;
|
|
34
|
-
} catch
|
|
35
|
-
|
|
34
|
+
} catch {
|
|
35
|
+
// Silent catch
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
const clearStorage = () => {
|
|
40
40
|
try {
|
|
41
41
|
storage.clearAll();
|
|
42
|
-
} catch
|
|
43
|
-
|
|
42
|
+
} catch {
|
|
43
|
+
// Silent catch
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
46
|
|
package/MMTemplate/tsconfig.json
CHANGED
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
"extends": "@react-native/typescript-config",
|
|
3
3
|
"compilerOptions": {
|
|
4
4
|
"types": ["jest"],
|
|
5
|
+
"baseUrl": ".",
|
|
6
|
+
"paths": {
|
|
7
|
+
"@src/*": ["src/*"],
|
|
8
|
+
"@src": ["src/index"],
|
|
9
|
+
"@assets/*": ["src/assets/*"],
|
|
10
|
+
"@assets": ["src/assets/index"],
|
|
11
|
+
"@components/*": ["src/components/*"],
|
|
12
|
+
"@components": ["src/components/index"],
|
|
13
|
+
"@context/*": ["src/context/*"],
|
|
14
|
+
"@context": ["src/context/index"],
|
|
15
|
+
"@locales/*": ["src/locales/*"],
|
|
16
|
+
"@locales": ["src/locales/index"],
|
|
17
|
+
"@mock/*": ["src/mock/*"],
|
|
18
|
+
"@mock": ["src/mock/index"],
|
|
19
|
+
"@navigation/*": ["src/navigation/*"],
|
|
20
|
+
"@navigation": ["src/navigation/index"],
|
|
21
|
+
"@screens/*": ["src/screens/*"],
|
|
22
|
+
"@screens": ["src/screens/index"],
|
|
23
|
+
"@services/*": ["src/services/*"],
|
|
24
|
+
"@services": ["src/services/index"],
|
|
25
|
+
"@theme/*": ["src/theme/*"],
|
|
26
|
+
"@theme": ["src/theme/index"],
|
|
27
|
+
"@app-types/*": ["src/types/*"],
|
|
28
|
+
"@app-types": ["src/types/index"],
|
|
29
|
+
"@utils/*": ["src/utils/*"],
|
|
30
|
+
"@utils": ["src/utils/index"]
|
|
31
|
+
}
|
|
5
32
|
},
|
|
6
33
|
"include": ["**/*.ts", "**/*.tsx"],
|
|
7
34
|
"exclude": ["**/node_modules", "**/Pods"]
|
package/README.md
CHANGED
|
@@ -18,9 +18,10 @@ This template includes the following key libraries and configurations:
|
|
|
18
18
|
|
|
19
19
|
* **Core**: React Native (0.83.1), React (19.2.0)
|
|
20
20
|
* **Language**: TypeScript (v5) for static type checking
|
|
21
|
-
* **Navigation**: [React Navigation v7](https://reactnavigation.org/) (Native Stack)
|
|
21
|
+
* **Navigation**: [React Navigation v7](https://reactnavigation.org/) (Native Stack & Bottom Tabs)
|
|
22
22
|
* **Internationalization**: [react-i18next](https://react.i18next.com/) with multi-language support (English/Hindi)
|
|
23
23
|
* **Storage**: [react-native-mmkv](https://github.com/mrousavy/react-native-mmkv) for high-performance persistence
|
|
24
|
+
* **Forms**: [Formik](https://formik.org/) & [Yup](https://github.com/jquense/yup) for form state management and validation
|
|
24
25
|
* **Animations**: [React Native Reanimated v4](https://docs.swmansion.com/react-native-reanimated/) & Worklets
|
|
25
26
|
* **UI/UX**:
|
|
26
27
|
* **Theme Support**: Light/Dark mode with persistence
|
|
@@ -28,6 +29,7 @@ This template includes the following key libraries and configurations:
|
|
|
28
29
|
* [React Native Safe Area Context](https://github.com/th3rdwave/react-native-safe-area-context) for handling safe areas
|
|
29
30
|
* [React Native Keyboard Controller](https://github.com/kirillzyusko/react-native-keyboard-controller) for advanced keyboard handling
|
|
30
31
|
* [React Native Toast Message](https://github.com/calintamas/react-native-toast-message) for in-app notifications
|
|
32
|
+
* **Error Handling**: [react-native-error-boundary](https://github.com/cawfree/react-native-error-boundary) for robust error catching
|
|
31
33
|
* **Testing**: Jest & React Test Renderer
|
|
32
34
|
|
|
33
35
|
## 📂 Project Structure
|
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modhamanish/rn-mm-template",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "A robust and modern React Native template built with TypeScript, designed to jumpstart your mobile application development.",
|
|
5
5
|
"repository": "https://github.com/modhamanish/mm-template.git",
|
|
6
6
|
"author": "Manish Modha",
|
|
7
7
|
"license": "ISC",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"release": "node release.js"
|
|
10
|
+
},
|
|
8
11
|
"keywords": [
|
|
9
12
|
"react-native",
|
|
10
13
|
"typescript",
|
package/release.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const readline = require('readline');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
const rl = readline.createInterface({
|
|
9
|
+
input: process.stdin,
|
|
10
|
+
output: process.stdout
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const run = (command, cwd = process.cwd()) => {
|
|
14
|
+
try {
|
|
15
|
+
console.log(`\x1b[36mRunning: ${command}\x1b[0m`);
|
|
16
|
+
execSync(command, { stdio: 'inherit', cwd });
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.error(`\x1b[31mError running command: ${command}\x1b[0m`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const pkgPath = path.join(__dirname, 'package.json');
|
|
24
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
25
|
+
|
|
26
|
+
console.log(`\x1b[35m\x1b[1mCurrent version: ${pkg.version}\x1b[0m`);
|
|
27
|
+
|
|
28
|
+
rl.question('Select release type (patch, minor, major) [patch]: ', (type) => {
|
|
29
|
+
const releaseType = type.trim() || 'patch';
|
|
30
|
+
|
|
31
|
+
if (!['patch', 'minor', 'major'].includes(releaseType)) {
|
|
32
|
+
console.error('\x1b[31mInvalid release type!\x1b[0m');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 1. Linting inside MMTemplate
|
|
37
|
+
console.log('\n\x1b[33m\x1b[1mStep 1: Linting check...\x1b[0m');
|
|
38
|
+
const mmTemplatePath = path.join(__dirname, 'MMTemplate');
|
|
39
|
+
|
|
40
|
+
if (!fs.existsSync(path.join(mmTemplatePath, 'node_modules'))) {
|
|
41
|
+
console.log('\x1b[33mNode modules missing in MMTemplate. Installing...\x1b[0m');
|
|
42
|
+
run('yarn install', mmTemplatePath);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
run('yarn lint', mmTemplatePath);
|
|
46
|
+
|
|
47
|
+
// 2. Version Bump
|
|
48
|
+
console.log('\n\x1b[33m\x1b[1mStep 2: Bumping version...\x1b[0m');
|
|
49
|
+
run(`npm version ${releaseType} --no-git-tag-version`);
|
|
50
|
+
|
|
51
|
+
const newPkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
52
|
+
const newVersion = newPkg.version;
|
|
53
|
+
|
|
54
|
+
// 3. Git Operations
|
|
55
|
+
console.log('\n\x1b[33m\x1b[1mStep 3: Git commit and tag...\x1b[0m');
|
|
56
|
+
run('git add .');
|
|
57
|
+
run(`git commit -m "chore: release v${newVersion}"`);
|
|
58
|
+
run(`git tag v${newVersion}`);
|
|
59
|
+
|
|
60
|
+
// 4. Final confirmation
|
|
61
|
+
rl.question(`\n\x1b[35m\x1b[1mPush to git and publish v${newVersion} to npm? (y/n) [n]: \x1b[0m`, (answer) => {
|
|
62
|
+
if (answer.toLowerCase() === 'y') {
|
|
63
|
+
console.log('\n\x1b[33m\x1b[1mStep 4: Pushing to Git...\x1b[0m');
|
|
64
|
+
run('git push origin main --tags');
|
|
65
|
+
|
|
66
|
+
console.log('\n\x1b[33m\x1b[1mStep 5: Publishing to npm...\x1b[0m');
|
|
67
|
+
run('npm publish --access public --registry https://registry.npmjs.org/');
|
|
68
|
+
|
|
69
|
+
console.log(`\n\x1b[32m\x1b[1mSuccessfully released v${newVersion}! 🚀✨\x1b[0m`);
|
|
70
|
+
} else {
|
|
71
|
+
console.log(`\n\x1b[33mVersion bumped to v${newVersion} and tagged locally, but not pushed/published.\x1b[0m`);
|
|
72
|
+
}
|
|
73
|
+
rl.close();
|
|
74
|
+
});
|
|
75
|
+
});
|