@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.
Files changed (50) hide show
  1. package/MMTemplate/.eslintrc.js +95 -1
  2. package/MMTemplate/.husky/pre-commit +2 -0
  3. package/MMTemplate/.prettierrc.js +2 -0
  4. package/MMTemplate/App.tsx +27 -21
  5. package/MMTemplate/README.md +76 -35
  6. package/MMTemplate/__tests__/App.test.tsx +5 -3
  7. package/MMTemplate/babel.config.js +24 -1
  8. package/MMTemplate/index.js +1 -0
  9. package/MMTemplate/lint_errors.txt +7 -0
  10. package/MMTemplate/package.json +24 -4
  11. package/MMTemplate/src/components/AnimationView.tsx +54 -69
  12. package/MMTemplate/src/components/AppText.tsx +7 -4
  13. package/MMTemplate/src/components/CustomAlert.tsx +203 -0
  14. package/MMTemplate/src/components/CustomToast.tsx +2 -1
  15. package/MMTemplate/src/components/ErrorBoundaryFallback.tsx +127 -0
  16. package/MMTemplate/src/components/FeatureItem.tsx +8 -6
  17. package/MMTemplate/src/components/FullScreenContainer.tsx +9 -7
  18. package/MMTemplate/src/components/InfoCard.tsx +8 -6
  19. package/MMTemplate/src/components/LanguageSwitcher.tsx +8 -6
  20. package/MMTemplate/src/components/TextInput.tsx +25 -15
  21. package/MMTemplate/src/components/ThemeSwitcher.tsx +4 -3
  22. package/MMTemplate/src/context/AuthContext.tsx +5 -4
  23. package/MMTemplate/src/context/ThemeContext.tsx +10 -19
  24. package/MMTemplate/src/locales/en.json +4 -1
  25. package/MMTemplate/src/locales/hi.json +4 -1
  26. package/MMTemplate/src/navigation/AppNavigator.tsx +7 -8
  27. package/MMTemplate/src/navigation/AppStack.tsx +6 -6
  28. package/MMTemplate/src/navigation/AuthCheck.tsx +11 -10
  29. package/MMTemplate/src/navigation/AuthStack.tsx +6 -4
  30. package/MMTemplate/src/navigation/MainTab.tsx +19 -13
  31. package/MMTemplate/src/screens/AddNoteScreen.tsx +20 -14
  32. package/MMTemplate/src/screens/HomeScreen.tsx +21 -15
  33. package/MMTemplate/src/screens/LoginScreen.tsx +21 -18
  34. package/MMTemplate/src/screens/NoteScreen.tsx +18 -16
  35. package/MMTemplate/src/screens/ProfileScreen.tsx +16 -13
  36. package/MMTemplate/src/screens/SettingsScreen.tsx +14 -11
  37. package/MMTemplate/src/screens/WelcomeScreen.tsx +19 -13
  38. package/MMTemplate/src/services/axiosInstance.ts +7 -5
  39. package/MMTemplate/src/services/note.query.ts +7 -5
  40. package/MMTemplate/src/theme/{Colors.ts → colors.ts} +6 -0
  41. package/MMTemplate/src/types/components.types.ts +38 -0
  42. package/MMTemplate/src/types/navigation.types.ts +1 -1
  43. package/MMTemplate/src/utils/i18n.ts +8 -6
  44. package/MMTemplate/src/utils/navigationUtils.ts +2 -1
  45. package/MMTemplate/src/utils/storageHelper.ts +8 -8
  46. package/MMTemplate/src/utils/utilsHelper.ts +1 -0
  47. package/MMTemplate/tsconfig.json +27 -0
  48. package/README.md +3 -1
  49. package/package.json +4 -1
  50. 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
- import AppText from '../components/AppText';
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 { navigate } from '../utils/navigationUtils';
20
- import Routes from '../navigation/routes';
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 + '80',
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 + '15',
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 + '15',
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 + 'B3',
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 + '80',
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
- import AppText from '../components/AppText';
3
+
4
4
  import { useTranslation } from 'react-i18next';
5
- import { useTheme } from '../context/ThemeContext';
6
- import { ThemeType } from '../theme/Colors';
7
- import FullScreenContainer from '../components/FullScreenContainer';
8
- import AnimationView from '../components/AnimationView';
9
- import { useAuth } from '../context/AuthContext';
10
- import InfoCard from '../components/InfoCard';
11
- import { navigate } from '../utils/navigationUtils';
12
- import Routes from '../navigation/routes';
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 + 'CC',
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 + 'CC',
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
- import AppText from '../components/AppText';
3
+
4
4
  import { useTranslation } from 'react-i18next';
5
- import { useTheme } from '../context/ThemeContext';
6
- import { ThemeType } from '../theme/Colors';
7
- import FullScreenContainer from '../components/FullScreenContainer';
8
- import AnimationView from '../components/AnimationView';
9
- import LanguageSwitcher from '../components/LanguageSwitcher';
10
- import ThemeSwitcher from '../components/ThemeSwitcher';
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 + 'CC',
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 + 'CC',
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
- import React, { FC, useEffect } from 'react';
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
- import { mobileScreenHeight, mobileScreenWidth } from '../utils/utilsHelper';
15
- import FullScreenContainer from '../components/FullScreenContainer';
16
- import { navigate } from '../utils/navigationUtils';
17
- import Routes from '../navigation/routes';
18
- import AppText from '../components/AppText';
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 + 'CC',
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: 'rgba(255, 255, 255, 0.15)',
193
+ backgroundColor: hexWithOpacity(colors.white, 15),
188
194
  borderRadius: 12,
189
195
  marginBottom: 16,
190
196
  borderWidth: 1,
191
- borderColor: 'rgba(255, 255, 255, 0.3)',
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
- import axios, { AxiosResponse, AxiosRequestConfig } from 'axios';
3
- import Routes from '../navigation/routes';
4
- import storageHelper from '../utils/storageHelper';
5
- import { resetAndNavigate } from '../utils/navigationUtils';
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: AxiosRequestConfig | any) => {
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 { goBack } from '../utils/navigationUtils';
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,6 +1,6 @@
1
1
  import { NativeStackScreenProps } from '@react-navigation/native-stack';
2
2
 
3
- import Routes from '../navigation/routes';
3
+ import Routes from '@navigation/routes';
4
4
 
5
5
  export type VerifyNumberScreenProps =
6
6
  NativeStackScreenProps<RootStackParamList>;
@@ -1,15 +1,17 @@
1
- import i18n from 'i18next';
1
+ import appI18n from 'i18next';
2
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';
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
- i18n.use(initReactI18next).init({
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 i18n;
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
- import { ParamsType } from '../types/navigation.types';
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 (error) {
17
- console.log(error);
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 (error) {
26
- console.log(error);
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 (error) {
35
- console.log(error);
34
+ } catch {
35
+ // Silent catch
36
36
  }
37
37
  };
38
38
 
39
39
  const clearStorage = () => {
40
40
  try {
41
41
  storage.clearAll();
42
- } catch (error) {
43
- console.log(error);
42
+ } catch {
43
+ // Silent catch
44
44
  }
45
45
  };
46
46
 
@@ -15,6 +15,7 @@ export {
15
15
  };
16
16
 
17
17
  export const hexWithOpacity = (hex: string, opacityPercent: number) => {
18
+ 'worklet';
18
19
  hex = hex.replace('#', '');
19
20
 
20
21
  if (hex.length === 3) {
@@ -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.4",
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
+ });