@modhamanish/rn-mm-template 1.0.1 → 1.0.3

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 (32) hide show
  1. package/MMTemplate/App.tsx +15 -2
  2. package/MMTemplate/package.json +3 -0
  3. package/MMTemplate/src/components/AppText.tsx +125 -0
  4. package/MMTemplate/src/components/CustomToast.tsx +8 -6
  5. package/MMTemplate/src/components/FeatureItem.tsx +11 -8
  6. package/MMTemplate/src/components/InfoCard.tsx +10 -6
  7. package/MMTemplate/src/components/LanguageSwitcher.tsx +8 -7
  8. package/MMTemplate/src/components/TextInput.tsx +214 -23
  9. package/MMTemplate/src/components/ThemeSwitcher.tsx +12 -7
  10. package/MMTemplate/src/context/ThemeContext.tsx +15 -1
  11. package/MMTemplate/src/locales/en.json +19 -2
  12. package/MMTemplate/src/locales/hi.json +19 -2
  13. package/MMTemplate/src/navigation/AppStack.tsx +2 -0
  14. package/MMTemplate/src/navigation/MainTab.tsx +15 -4
  15. package/MMTemplate/src/navigation/routes.ts +2 -0
  16. package/MMTemplate/src/screens/AddNoteScreen.tsx +155 -0
  17. package/MMTemplate/src/screens/HomeScreen.tsx +60 -33
  18. package/MMTemplate/src/screens/LoginScreen.tsx +67 -25
  19. package/MMTemplate/src/screens/NoteScreen.tsx +241 -0
  20. package/MMTemplate/src/screens/ProfileScreen.tsx +26 -25
  21. package/MMTemplate/src/screens/SettingsScreen.tsx +17 -16
  22. package/MMTemplate/src/screens/WelcomeScreen.tsx +23 -23
  23. package/MMTemplate/src/services/axiosInstance.ts +41 -0
  24. package/MMTemplate/src/services/note.query.ts +40 -0
  25. package/MMTemplate/src/services/queryKeys.ts +4 -0
  26. package/MMTemplate/src/types/components.types.ts +47 -1
  27. package/MMTemplate/src/types/navigation.types.ts +2 -0
  28. package/MMTemplate/src/types/services.types.ts +6 -0
  29. package/MMTemplate/src/utils/storageHelper.ts +2 -0
  30. package/MMTemplate/src/utils/validationSchemas.ts +6 -0
  31. package/README.md +1 -1
  32. package/package.json +1 -1
@@ -9,6 +9,7 @@ import {
9
9
  } from 'react';
10
10
  import { darkTheme, lightTheme, ThemeType } from '../theme/Colors';
11
11
  import { EdgeInsets, useSafeAreaInsets } from 'react-native-safe-area-context';
12
+ import storageHelper from '../utils/storageHelper';
12
13
 
13
14
  export type ThemeContextType = {
14
15
  colors: ThemeType['colors'];
@@ -31,6 +32,11 @@ export const ThemeProvider: FC<ThemeProviderProps> = ({ children }) => {
31
32
  lightTheme.colors,
32
33
  );
33
34
 
35
+ useEffect(() => {
36
+ const theme = storageHelper.getItem(storageHelper.STORAGE_KEYS.THEME);
37
+ setCurrentTheme(theme === 'dark' ? 'dark' : 'light');
38
+ }, []);
39
+
34
40
  useEffect(() => {
35
41
  if (currentTheme === 'dark') {
36
42
  setColors(darkTheme.colors);
@@ -40,7 +46,15 @@ export const ThemeProvider: FC<ThemeProviderProps> = ({ children }) => {
40
46
  }, [currentTheme]);
41
47
 
42
48
  const toggleTheme = useCallback(() => {
43
- setCurrentTheme(prev => (prev === 'dark' ? 'light' : 'dark'));
49
+ setCurrentTheme(prev => {
50
+ if (prev === 'dark') {
51
+ storageHelper.saveItem(storageHelper.STORAGE_KEYS.THEME, 'light');
52
+ return 'light';
53
+ } else {
54
+ storageHelper.saveItem(storageHelper.STORAGE_KEYS.THEME, 'dark');
55
+ return 'dark';
56
+ }
57
+ });
44
58
  }, []);
45
59
 
46
60
  return (
@@ -15,11 +15,25 @@
15
15
  "error": "Error",
16
16
  "success": "Success",
17
17
  "home": "Home",
18
- "profile": "Profile"
18
+ "profile": "Profile",
19
+ "note": "Note",
20
+ "notes": "Notes",
21
+ "noNotesFound": "No notes found",
22
+ "addNote": "Add Note",
23
+ "searchNotes": "Search notes...",
24
+ "title": "Title",
25
+ "description": "Description",
26
+ "enterTitle": "Enter title",
27
+ "enterDescription": "Enter description",
28
+ "creating": "Creating...",
29
+ "noteCreated": "Note created successfully",
30
+ "titleRequired": "Title is required",
31
+ "descriptionRequired": "Description is required"
19
32
  },
20
33
  "auth": {
21
34
  "welcomeBack": "Welcome Back!",
22
35
  "signInToContinue": "Sign in to continue",
36
+ "mockCredentialsHint": "Use the following credentials to login:",
23
37
  "email": "Email",
24
38
  "password": "Password",
25
39
  "enterEmail": "Enter your email",
@@ -62,7 +76,10 @@
62
76
  "storageSupport": "Fast Storage",
63
77
  "storageDescription": "High-performance persistence with react-native-mmkv",
64
78
  "localesDescription": "Translation files for multi-language support.",
65
- "mockDescription": "Mock data for development and testing."
79
+ "mockDescription": "Mock data for development and testing.",
80
+ "assetsDescription": "Global assets like images, icons, and fonts.",
81
+ "servicesDescription": "API calls and external service integrations.",
82
+ "typesDescription": "TypeScript interfaces and type definitions."
66
83
  },
67
84
  "settings": {
68
85
  "settings": "Settings",
@@ -15,11 +15,25 @@
15
15
  "error": "त्रुटि",
16
16
  "success": "सफलता",
17
17
  "home": "होम",
18
- "profile": "प्रोफ़ाइल"
18
+ "profile": "प्रोफ़ाइल",
19
+ "note": "नोट",
20
+ "notes": "नोट्स",
21
+ "noNotesFound": "कोई नोट्स नहीं मिले",
22
+ "addNote": "नोट जोड़ें",
23
+ "searchNotes": "नोट्स खोजें...",
24
+ "title": "शीर्षक",
25
+ "description": "विवरण",
26
+ "enterTitle": "शीर्षक दर्ज करें",
27
+ "enterDescription": "विवरण दर्ज करें",
28
+ "creating": "बनाया जा रहा है...",
29
+ "noteCreated": "नोट सफलतापूर्वक बनाया गया",
30
+ "titleRequired": "शीर्षक आवश्यक है",
31
+ "descriptionRequired": "विवरण आवश्यक है"
19
32
  },
20
33
  "auth": {
21
34
  "welcomeBack": "वापसी पर स्वागत है!",
22
35
  "signInToContinue": "जारी रखने के लिए साइन इन करें",
36
+ "mockCredentialsHint": "लॉगिन करने के लिए निम्न क्रेडेंशियल का उपयोग करें:",
23
37
  "email": "ईमेल",
24
38
  "password": "पासवर्ड",
25
39
  "enterEmail": "अपना ईमेल दर्ज करें",
@@ -62,7 +76,10 @@
62
76
  "storageSupport": "तेज़ स्टोरेज",
63
77
  "storageDescription": "react-native-mmkv के साथ उच्च प्रदर्शन दृढ़ता",
64
78
  "localesDescription": "बहु-भाषा समर्थन के लिए अनुवाद फ़ाइलें।",
65
- "mockDescription": "विकास और परीक्षण के लिए मॉक डेटा।"
79
+ "mockDescription": "विकास और परीक्षण के लिए मॉक डेटा।",
80
+ "assetsDescription": "छवियों, आइकन और फोंट जैसे वैश्विक एसेट्स।",
81
+ "servicesDescription": "API कॉल और बाहरी सेवा एकीकरण।",
82
+ "typesDescription": "TypeScript इंटरफेस और टाइप परिभाषाएं।"
66
83
  },
67
84
  "settings": {
68
85
  "settings": "सेटिंग्स",
@@ -7,6 +7,7 @@ import { AppStackParamList } from '../types/navigation.types';
7
7
  // Screens
8
8
  import MainTab from './MainTab';
9
9
  import SettingsScreen from '../screens/SettingsScreen';
10
+ import AddNoteScreen from '../screens/AddNoteScreen';
10
11
 
11
12
  const Stack = createNativeStackNavigator<AppStackParamList>();
12
13
 
@@ -20,6 +21,7 @@ const AppStack: FC = () => {
20
21
  >
21
22
  <Stack.Screen name={Routes.MainTab} component={MainTab} />
22
23
  <Stack.Screen name={Routes.SettingsScreen} component={SettingsScreen} />
24
+ <Stack.Screen name={Routes.AddNoteScreen} component={AddNoteScreen} />
23
25
  </Stack.Navigator>
24
26
  );
25
27
  };
@@ -1,12 +1,15 @@
1
1
  import React, { FC } from 'react';
2
- import { Text } from 'react-native';
2
+ import AppText from '../components/AppText';
3
3
  import { useTranslation } from 'react-i18next';
4
4
  import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
5
5
  import Routes from './routes';
6
6
  import { MainTabParamList } from '../types/navigation.types';
7
+ import { useTheme } from '../context/ThemeContext';
8
+
9
+ // Screens
7
10
  import HomeScreen from '../screens/HomeScreen';
8
11
  import ProfileScreen from '../screens/ProfileScreen';
9
- import { useTheme } from '../context/ThemeContext';
12
+ import NoteScreen from '../screens/NoteScreen';
10
13
 
11
14
  const BottomTab = createBottomTabNavigator<MainTabParamList>();
12
15
 
@@ -32,7 +35,15 @@ const MainTab: FC = () => {
32
35
  component={HomeScreen}
33
36
  options={{
34
37
  tabBarLabel: t('common.home'),
35
- tabBarIcon: () => <Text>🏠</Text>,
38
+ tabBarIcon: () => <AppText>🏠</AppText>,
39
+ }}
40
+ />
41
+ <BottomTab.Screen
42
+ name={Routes.NoteScreen}
43
+ component={NoteScreen}
44
+ options={{
45
+ tabBarLabel: t('common.note'),
46
+ tabBarIcon: () => <AppText>📝</AppText>,
36
47
  }}
37
48
  />
38
49
  <BottomTab.Screen
@@ -40,7 +51,7 @@ const MainTab: FC = () => {
40
51
  component={ProfileScreen}
41
52
  options={{
42
53
  tabBarLabel: t('common.profile'),
43
- tabBarIcon: () => <Text>👤</Text>,
54
+ tabBarIcon: () => <AppText>👤</AppText>,
44
55
  }}
45
56
  />
46
57
  </BottomTab.Navigator>
@@ -10,8 +10,10 @@ enum Routes {
10
10
 
11
11
  // App Stack Screens
12
12
  HomeScreen = 'HomeScreen',
13
+ NoteScreen = 'NoteScreen',
13
14
  ProfileScreen = 'ProfileScreen',
14
15
  SettingsScreen = 'SettingsScreen',
16
+ AddNoteScreen = 'AddNoteScreen',
15
17
  }
16
18
 
17
19
  export default Routes;
@@ -0,0 +1,155 @@
1
+ import React, { FC } from 'react';
2
+ import {
3
+ StyleSheet,
4
+ View,
5
+ TouchableOpacity,
6
+ ActivityIndicator,
7
+ ScrollView,
8
+ } from 'react-native';
9
+ import AppText from '../components/AppText';
10
+ import { useTranslation } from 'react-i18next';
11
+ import { useTheme } from '../context/ThemeContext';
12
+ import { ThemeType } from '../theme/Colors';
13
+ import FullScreenContainer from '../components/FullScreenContainer';
14
+ import TextInput from '../components/TextInput';
15
+ import AnimationView from '../components/AnimationView';
16
+ import { useAddNoteMutation } from '../services/note.query';
17
+ import { goBack } from '../utils/navigationUtils';
18
+ import { useFormik } from 'formik';
19
+ import { NoteSchema } from '../utils/validationSchemas';
20
+
21
+ const AddNoteScreen: FC = () => {
22
+ const { t } = useTranslation();
23
+ const theme = useTheme();
24
+ const styles = getStyles(theme);
25
+
26
+ const { mutate: addNote, isPending } = useAddNoteMutation();
27
+
28
+ const formik = useFormik({
29
+ initialValues: {
30
+ title: '',
31
+ description: '',
32
+ },
33
+ validationSchema: NoteSchema,
34
+ onSubmit: values => {
35
+ addNote(values);
36
+ },
37
+ });
38
+
39
+ const { values, errors, touched, handleChange, handleBlur, handleSubmit } =
40
+ formik;
41
+
42
+ return (
43
+ <FullScreenContainer style={styles.container}>
44
+ <View style={styles.header}>
45
+ <TouchableOpacity style={styles.backButton} onPress={() => goBack()}>
46
+ <AppText size="xlarge" style={styles.backIcon}>
47
+
48
+ </AppText>
49
+ </TouchableOpacity>
50
+ <AppText variant="h3" style={styles.headerTitle}>
51
+ {t('common.addNote')}
52
+ </AppText>
53
+ <View style={{ width: 40 }} />
54
+ </View>
55
+
56
+ <ScrollView contentContainerStyle={styles.content}>
57
+ <AnimationView animType="FadeIn" duration={500}>
58
+ <TextInput
59
+ label={t('common.title')}
60
+ placeholder={t('common.enterTitle')}
61
+ value={values.title}
62
+ onChangeText={handleChange('title')}
63
+ onBlur={handleBlur('title')}
64
+ error={errors.title}
65
+ touched={touched.title}
66
+ />
67
+
68
+ <TextInput
69
+ label={t('common.description')}
70
+ placeholder={t('common.enterDescription')}
71
+ value={values.description}
72
+ onChangeText={handleChange('description')}
73
+ onBlur={handleBlur('description')}
74
+ error={errors.description}
75
+ touched={touched.description}
76
+ multiline
77
+ numberOfLines={10}
78
+ style={styles.textArea}
79
+ />
80
+
81
+ <TouchableOpacity
82
+ style={[styles.saveButton, isPending && styles.saveButtonDisabled]}
83
+ onPress={() => handleSubmit()}
84
+ disabled={isPending}
85
+ activeOpacity={0.8}
86
+ >
87
+ {isPending ? (
88
+ <ActivityIndicator color={theme.colors.white} />
89
+ ) : (
90
+ <AppText variant="bold" size={18} style={styles.saveButtonText}>
91
+ {t('common.save')}
92
+ </AppText>
93
+ )}
94
+ </TouchableOpacity>
95
+ </AnimationView>
96
+ </ScrollView>
97
+ </FullScreenContainer>
98
+ );
99
+ };
100
+
101
+ export default AddNoteScreen;
102
+
103
+ const getStyles = ({ colors }: ThemeType) =>
104
+ StyleSheet.create({
105
+ container: {
106
+ flex: 1,
107
+ backgroundColor: colors.backgroundColor,
108
+ },
109
+ header: {
110
+ flexDirection: 'row',
111
+ alignItems: 'center',
112
+ justifyContent: 'space-between',
113
+ paddingHorizontal: 16,
114
+ paddingVertical: 12,
115
+ borderBottomWidth: 1,
116
+ borderBottomColor: colors.textColor + '10',
117
+ },
118
+ backButton: {
119
+ width: 40,
120
+ height: 40,
121
+ justifyContent: 'center',
122
+ alignItems: 'center',
123
+ },
124
+ backIcon: {
125
+ color: colors.textColor,
126
+ },
127
+ headerTitle: {
128
+ color: colors.textColor,
129
+ },
130
+ content: {
131
+ padding: 20,
132
+ },
133
+ textArea: {
134
+ height: 150,
135
+ textAlignVertical: 'top',
136
+ },
137
+ saveButton: {
138
+ backgroundColor: colors.primary,
139
+ borderRadius: 12,
140
+ padding: 16,
141
+ alignItems: 'center',
142
+ marginTop: 24,
143
+ shadowColor: colors.primary,
144
+ shadowOffset: { width: 0, height: 4 },
145
+ shadowOpacity: 0.3,
146
+ shadowRadius: 8,
147
+ elevation: 5,
148
+ },
149
+ saveButtonDisabled: {
150
+ opacity: 0.6,
151
+ },
152
+ saveButtonText: {
153
+ color: colors.white,
154
+ },
155
+ });
@@ -1,4 +1,5 @@
1
- import { Image, StyleSheet, Text, View, ScrollView } from 'react-native';
1
+ import { Image, StyleSheet, View, ScrollView } from 'react-native';
2
+ import AppText from '../components/AppText';
2
3
  import React, { FC } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
4
5
  import FullScreenContainer from '../components/FullScreenContainer';
@@ -33,10 +34,10 @@ const HomeScreen: FC = () => {
33
34
  />
34
35
  </AnimationView>
35
36
  <AnimationView delay={400} animType="SlideInDown" duration={800}>
36
- <Text style={styles.welcomeText}>
37
+ <AppText variant="h2" style={styles.welcomeText}>
37
38
  {t('home.welcomeToTemplate')}
38
- </Text>
39
- <Text style={styles.subtitle}>{t('home.subtitle')}</Text>
39
+ </AppText>
40
+ <AppText style={styles.subtitle}>{t('home.subtitle')}</AppText>
40
41
  </AnimationView>
41
42
  </View>
42
43
  </AnimationView>
@@ -44,15 +45,23 @@ const HomeScreen: FC = () => {
44
45
  {/* Quick Start Section */}
45
46
  <AnimationView delay={600} animType="FadeIn" duration={800}>
46
47
  <InfoCard title={`🚀 ${t('home.quickStart')}`} icon="">
47
- <Text style={styles.cardText}>{t('home.quickStartDesc')}</Text>
48
+ <AppText style={styles.cardText}>
49
+ {t('home.quickStartDesc')}
50
+ </AppText>
48
51
  <View style={styles.codeBlock}>
49
- <Text style={styles.codeText}>yarn install</Text>
52
+ <AppText size={13} style={styles.codeText}>
53
+ yarn install
54
+ </AppText>
50
55
  </View>
51
56
  <View style={styles.codeBlock}>
52
- <Text style={styles.codeText}>cd ios && pod install</Text>
57
+ <AppText size={13} style={styles.codeText}>
58
+ cd ios && pod install
59
+ </AppText>
53
60
  </View>
54
61
  <View style={styles.codeBlock}>
55
- <Text style={styles.codeText}>yarn ios / yarn android</Text>
62
+ <AppText size={13} style={styles.codeText}>
63
+ yarn ios / yarn android
64
+ </AppText>
56
65
  </View>
57
66
  </InfoCard>
58
67
  </AnimationView>
@@ -100,6 +109,21 @@ const HomeScreen: FC = () => {
100
109
  title="context/"
101
110
  description="React Context for global state management."
102
111
  />
112
+ <FeatureItem
113
+ icon="🖼️"
114
+ title="assets/"
115
+ description={t('home.assetsDescription')}
116
+ />
117
+ <FeatureItem
118
+ icon="⚡"
119
+ title="services/"
120
+ description={t('home.servicesDescription')}
121
+ />
122
+ <FeatureItem
123
+ icon="🏷️"
124
+ title="types/"
125
+ description={t('home.typesDescription')}
126
+ />
103
127
  </InfoCard>
104
128
  </AnimationView>
105
129
 
@@ -183,33 +207,45 @@ const HomeScreen: FC = () => {
183
207
  {/* Next Steps Section */}
184
208
  <AnimationView delay={1400} animType="FadeIn" duration={800}>
185
209
  <InfoCard title={`🎯 ${t('home.nextSteps')}`} icon="">
186
- <Text style={styles.cardText}>
210
+ <AppText style={styles.cardText}>
187
211
  1. Customize the theme in{' '}
188
- <Text style={styles.highlight}>theme/Colors.ts</Text>
189
- </Text>
190
- <Text style={styles.cardText}>
212
+ <AppText variant="semiBold" style={styles.highlight}>
213
+ theme/Colors.ts
214
+ </AppText>
215
+ </AppText>
216
+ <AppText style={styles.cardText}>
191
217
  2. Add your screens in{' '}
192
- <Text style={styles.highlight}>screens/</Text>
193
- </Text>
194
- <Text style={styles.cardText}>
218
+ <AppText variant="semiBold" style={styles.highlight}>
219
+ screens/
220
+ </AppText>
221
+ </AppText>
222
+ <AppText style={styles.cardText}>
195
223
  3. Update navigation in{' '}
196
- <Text style={styles.highlight}>navigation/</Text>
197
- </Text>
198
- <Text style={styles.cardText}>
224
+ <AppText variant="semiBold" style={styles.highlight}>
225
+ navigation/
226
+ </AppText>
227
+ </AppText>
228
+ <AppText style={styles.cardText}>
199
229
  4. Create reusable components in{' '}
200
- <Text style={styles.highlight}>components/</Text>
201
- </Text>
202
- <Text style={styles.cardText}>
230
+ <AppText variant="semiBold" style={styles.highlight}>
231
+ components/
232
+ </AppText>
233
+ </AppText>
234
+ <AppText style={styles.cardText}>
203
235
  5. Configure your app name and bundle ID
204
- </Text>
236
+ </AppText>
205
237
  </InfoCard>
206
238
  </AnimationView>
207
239
 
208
240
  {/* Footer */}
209
241
  <AnimationView delay={1600} animType="FadeIn" duration={800}>
210
242
  <View style={styles.footer}>
211
- <Text style={styles.footerText}>{t('home.happyCoding')}</Text>
212
- <Text style={styles.footerSubtext}>{t('home.builtWith')}</Text>
243
+ <AppText variant="semiBold" size={18} style={styles.footerText}>
244
+ {t('home.happyCoding')}
245
+ </AppText>
246
+ <AppText size={13} style={styles.footerSubtext}>
247
+ {t('home.builtWith')}
248
+ </AppText>
213
249
  </View>
214
250
  </AnimationView>
215
251
  </ScrollView>
@@ -241,19 +277,15 @@ const getStyles = ({ colors }: ThemeType) =>
241
277
  marginBottom: 16,
242
278
  },
243
279
  welcomeText: {
244
- fontSize: 24,
245
- fontWeight: '700',
246
280
  color: colors.textColor,
247
281
  textAlign: 'center',
248
282
  marginBottom: 8,
249
283
  },
250
284
  subtitle: {
251
- fontSize: 14,
252
285
  color: colors.textColor + 'CC',
253
286
  textAlign: 'center',
254
287
  },
255
288
  cardText: {
256
- fontSize: 14,
257
289
  color: colors.textColor,
258
290
  lineHeight: 20,
259
291
  marginBottom: 8,
@@ -268,12 +300,10 @@ const getStyles = ({ colors }: ThemeType) =>
268
300
  },
269
301
  codeText: {
270
302
  fontFamily: 'monospace',
271
- fontSize: 13,
272
303
  color: colors.textColor,
273
304
  },
274
305
  highlight: {
275
306
  color: colors.primary,
276
- fontWeight: '600',
277
307
  fontFamily: 'monospace',
278
308
  },
279
309
  footer: {
@@ -284,13 +314,10 @@ const getStyles = ({ colors }: ThemeType) =>
284
314
  borderTopColor: colors.textColor + '20',
285
315
  },
286
316
  footerText: {
287
- fontSize: 18,
288
- fontWeight: '600',
289
317
  color: colors.primary,
290
318
  marginBottom: 4,
291
319
  },
292
320
  footerSubtext: {
293
- fontSize: 13,
294
321
  color: colors.textColor + 'CC',
295
322
  },
296
323
  });