@modhamanish/rn-mm-template 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MMTemplate/.bundle/config +2 -0
- package/MMTemplate/.eslintrc.js +4 -0
- package/MMTemplate/.prettierrc.js +5 -0
- package/MMTemplate/.watchmanconfig +1 -0
- package/MMTemplate/App.tsx +41 -0
- package/MMTemplate/Gemfile +16 -0
- package/MMTemplate/README.md +109 -0
- package/MMTemplate/__tests__/App.test.tsx +13 -0
- package/MMTemplate/_gitignore +79 -0
- package/MMTemplate/android/app/build.gradle +119 -0
- package/MMTemplate/android/app/debug.keystore +0 -0
- package/MMTemplate/android/app/proguard-rules.pro +10 -0
- package/MMTemplate/android/app/src/main/AndroidManifest.xml +27 -0
- package/MMTemplate/android/app/src/main/java/com/mmtemplate/MainActivity.kt +22 -0
- package/MMTemplate/android/app/src/main/java/com/mmtemplate/MainApplication.kt +27 -0
- package/MMTemplate/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
- package/MMTemplate/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/MMTemplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/MMTemplate/android/app/src/main/res/values/strings.xml +3 -0
- package/MMTemplate/android/app/src/main/res/values/styles.xml +9 -0
- package/MMTemplate/android/build.gradle +21 -0
- package/MMTemplate/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/MMTemplate/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/MMTemplate/android/gradle.properties +44 -0
- package/MMTemplate/android/gradlew +251 -0
- package/MMTemplate/android/gradlew.bat +99 -0
- package/MMTemplate/android/settings.gradle +6 -0
- package/MMTemplate/app.json +4 -0
- package/MMTemplate/babel.config.js +8 -0
- package/MMTemplate/index.js +9 -0
- package/MMTemplate/ios/.xcode.env +11 -0
- package/MMTemplate/ios/MMTemplate/AppDelegate.swift +48 -0
- package/MMTemplate/ios/MMTemplate/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
- package/MMTemplate/ios/MMTemplate/Images.xcassets/Contents.json +6 -0
- package/MMTemplate/ios/MMTemplate/Info.plist +55 -0
- package/MMTemplate/ios/MMTemplate/LaunchScreen.storyboard +47 -0
- package/MMTemplate/ios/MMTemplate/PrivacyInfo.xcprivacy +37 -0
- package/MMTemplate/ios/MMTemplate.xcodeproj/project.pbxproj +480 -0
- package/MMTemplate/ios/MMTemplate.xcodeproj/xcshareddata/xcschemes/MMTemplate.xcscheme +88 -0
- package/MMTemplate/ios/Podfile +38 -0
- package/MMTemplate/jest.config.js +3 -0
- package/MMTemplate/metro.config.js +11 -0
- package/MMTemplate/package.json +55 -0
- package/MMTemplate/src/assets/images/index.ts +4 -0
- package/MMTemplate/src/assets/images/logo-dark.png +0 -0
- package/MMTemplate/src/assets/images/logo.png +0 -0
- package/MMTemplate/src/components/AnimationView.tsx +113 -0
- package/MMTemplate/src/components/CustomToast.tsx +46 -0
- package/MMTemplate/src/components/FeatureItem.tsx +59 -0
- package/MMTemplate/src/components/FullScreenContainer.tsx +60 -0
- package/MMTemplate/src/components/InfoCard.tsx +61 -0
- package/MMTemplate/src/components/LanguageSwitcher.tsx +80 -0
- package/MMTemplate/src/components/TextInput.tsx +74 -0
- package/MMTemplate/src/components/ThemeSwitcher.tsx +63 -0
- package/MMTemplate/src/context/AuthContext.tsx +76 -0
- package/MMTemplate/src/context/ThemeContext.tsx +67 -0
- package/MMTemplate/src/locales/en.json +83 -0
- package/MMTemplate/src/locales/hi.json +83 -0
- package/MMTemplate/src/mock/index.ts +5 -0
- package/MMTemplate/src/navigation/AppNavigator.tsx +45 -0
- package/MMTemplate/src/navigation/AppStack.tsx +27 -0
- package/MMTemplate/src/navigation/AuthCheck.tsx +50 -0
- package/MMTemplate/src/navigation/AuthStack.tsx +24 -0
- package/MMTemplate/src/navigation/MainTab.tsx +50 -0
- package/MMTemplate/src/navigation/routes.ts +17 -0
- package/MMTemplate/src/screens/HomeScreen.tsx +296 -0
- package/MMTemplate/src/screens/LoginScreen.tsx +199 -0
- package/MMTemplate/src/screens/ProfileScreen.tsx +171 -0
- package/MMTemplate/src/screens/SettingsScreen.tsx +96 -0
- package/MMTemplate/src/screens/WelcomeScreen.tsx +215 -0
- package/MMTemplate/src/theme/Colors.ts +25 -0
- package/MMTemplate/src/types/components.types.ts +13 -0
- package/MMTemplate/src/types/navigation.types.ts +35 -0
- package/MMTemplate/src/utils/i18n.ts +28 -0
- package/MMTemplate/src/utils/navigationUtils.ts +72 -0
- package/MMTemplate/src/utils/storageHelper.ts +51 -0
- package/MMTemplate/src/utils/utilsHelper.ts +34 -0
- package/MMTemplate/src/utils/validationSchemas.ts +58 -0
- package/MMTemplate/tsconfig.json +8 -0
- package/README.md +108 -0
- package/package.json +22 -0
- package/script.js +62 -0
- package/template.config.js +11 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { Image, StyleSheet, Text, View, ScrollView } from 'react-native';
|
|
2
|
+
import React, { FC } from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import FullScreenContainer from '../components/FullScreenContainer';
|
|
5
|
+
import InfoCard from '../components/InfoCard';
|
|
6
|
+
import FeatureItem from '../components/FeatureItem';
|
|
7
|
+
import { Images } from '../assets/images';
|
|
8
|
+
import { ThemeType } from '../theme/Colors';
|
|
9
|
+
import { mobileScreenHeight, mobileScreenWidth } from '../utils/utilsHelper';
|
|
10
|
+
import { useTheme } from '../context/ThemeContext';
|
|
11
|
+
import AnimationView from '../components/AnimationView';
|
|
12
|
+
|
|
13
|
+
const HomeScreen: FC = () => {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
const theme = useTheme();
|
|
16
|
+
const styles = getStyles(theme);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<FullScreenContainer style={styles.container} barStyle="light-content">
|
|
20
|
+
<ScrollView
|
|
21
|
+
showsVerticalScrollIndicator={false}
|
|
22
|
+
contentContainerStyle={styles.scrollContent}
|
|
23
|
+
>
|
|
24
|
+
{/* Header Section */}
|
|
25
|
+
<AnimationView animType="FadeIn" duration={800}>
|
|
26
|
+
<View style={styles.header}>
|
|
27
|
+
<AnimationView animType="ZoomIn" duration={1000}>
|
|
28
|
+
<Image
|
|
29
|
+
source={
|
|
30
|
+
theme.currentTheme === 'dark' ? Images.logoDark : Images.logo
|
|
31
|
+
}
|
|
32
|
+
style={styles.logo}
|
|
33
|
+
/>
|
|
34
|
+
</AnimationView>
|
|
35
|
+
<AnimationView delay={400} animType="SlideInDown" duration={800}>
|
|
36
|
+
<Text style={styles.welcomeText}>
|
|
37
|
+
{t('home.welcomeToTemplate')}
|
|
38
|
+
</Text>
|
|
39
|
+
<Text style={styles.subtitle}>{t('home.subtitle')}</Text>
|
|
40
|
+
</AnimationView>
|
|
41
|
+
</View>
|
|
42
|
+
</AnimationView>
|
|
43
|
+
|
|
44
|
+
{/* Quick Start Section */}
|
|
45
|
+
<AnimationView delay={600} animType="FadeIn" duration={800}>
|
|
46
|
+
<InfoCard title={`🚀 ${t('home.quickStart')}`} icon="">
|
|
47
|
+
<Text style={styles.cardText}>{t('home.quickStartDesc')}</Text>
|
|
48
|
+
<View style={styles.codeBlock}>
|
|
49
|
+
<Text style={styles.codeText}>yarn install</Text>
|
|
50
|
+
</View>
|
|
51
|
+
<View style={styles.codeBlock}>
|
|
52
|
+
<Text style={styles.codeText}>cd ios && pod install</Text>
|
|
53
|
+
</View>
|
|
54
|
+
<View style={styles.codeBlock}>
|
|
55
|
+
<Text style={styles.codeText}>yarn ios / yarn android</Text>
|
|
56
|
+
</View>
|
|
57
|
+
</InfoCard>
|
|
58
|
+
</AnimationView>
|
|
59
|
+
|
|
60
|
+
{/* Project Structure Section */}
|
|
61
|
+
<AnimationView delay={800} animType="FadeIn" duration={800}>
|
|
62
|
+
<InfoCard title={`📁 ${t('home.projectStructure')}`} icon="">
|
|
63
|
+
<FeatureItem
|
|
64
|
+
icon="📱"
|
|
65
|
+
title="screens/"
|
|
66
|
+
description="All your screen components. Add new screens here."
|
|
67
|
+
/>
|
|
68
|
+
<FeatureItem
|
|
69
|
+
icon="🧩"
|
|
70
|
+
title="components/"
|
|
71
|
+
description="Reusable UI components used across screens."
|
|
72
|
+
/>
|
|
73
|
+
<FeatureItem
|
|
74
|
+
icon="🧭"
|
|
75
|
+
title="navigation/"
|
|
76
|
+
description="Navigation setup with AuthStack and AppStack."
|
|
77
|
+
/>
|
|
78
|
+
<FeatureItem
|
|
79
|
+
icon="🎨"
|
|
80
|
+
title="theme/"
|
|
81
|
+
description="Centralized colors and styling configuration."
|
|
82
|
+
/>
|
|
83
|
+
<FeatureItem
|
|
84
|
+
icon="🌍"
|
|
85
|
+
title="locales/"
|
|
86
|
+
description={t('home.localesDescription')}
|
|
87
|
+
/>
|
|
88
|
+
<FeatureItem
|
|
89
|
+
icon="🧪"
|
|
90
|
+
title="mock/"
|
|
91
|
+
description={t('home.mockDescription')}
|
|
92
|
+
/>
|
|
93
|
+
<FeatureItem
|
|
94
|
+
icon="🔧"
|
|
95
|
+
title="utils/"
|
|
96
|
+
description="Helper functions and utility methods."
|
|
97
|
+
/>
|
|
98
|
+
<FeatureItem
|
|
99
|
+
icon="📦"
|
|
100
|
+
title="context/"
|
|
101
|
+
description="React Context for global state management."
|
|
102
|
+
/>
|
|
103
|
+
</InfoCard>
|
|
104
|
+
</AnimationView>
|
|
105
|
+
|
|
106
|
+
{/* Features Section */}
|
|
107
|
+
<AnimationView delay={1000} animType="FadeIn" duration={800}>
|
|
108
|
+
<InfoCard title={`✨ ${t('home.includedFeatures')}`} icon="">
|
|
109
|
+
<FeatureItem
|
|
110
|
+
icon="⚡"
|
|
111
|
+
title="React Navigation v7"
|
|
112
|
+
description="Pre-configured navigation with stack navigators"
|
|
113
|
+
/>
|
|
114
|
+
<FeatureItem
|
|
115
|
+
icon="🎬"
|
|
116
|
+
title="Reanimated v4"
|
|
117
|
+
description="Smooth animations with worklets support"
|
|
118
|
+
/>
|
|
119
|
+
<FeatureItem
|
|
120
|
+
icon="🔷"
|
|
121
|
+
title="TypeScript"
|
|
122
|
+
description="Full type safety and better developer experience"
|
|
123
|
+
/>
|
|
124
|
+
<FeatureItem
|
|
125
|
+
icon="🌓"
|
|
126
|
+
title={t('settings.theme')}
|
|
127
|
+
description={t('home.themeDescription')}
|
|
128
|
+
/>
|
|
129
|
+
<FeatureItem
|
|
130
|
+
icon="🌐"
|
|
131
|
+
title={t('home.i18nSupport')}
|
|
132
|
+
description={t('home.i18nDescription')}
|
|
133
|
+
/>
|
|
134
|
+
<FeatureItem
|
|
135
|
+
icon="🔐"
|
|
136
|
+
title={t('home.authSupport')}
|
|
137
|
+
description={t('home.authDescription')}
|
|
138
|
+
/>
|
|
139
|
+
<FeatureItem
|
|
140
|
+
icon="💾"
|
|
141
|
+
title={t('home.storageSupport')}
|
|
142
|
+
description={t('home.storageDescription')}
|
|
143
|
+
/>
|
|
144
|
+
<FeatureItem
|
|
145
|
+
icon="⌨️"
|
|
146
|
+
title="Keyboard Controller"
|
|
147
|
+
description="Advanced keyboard handling for better UX"
|
|
148
|
+
/>
|
|
149
|
+
<FeatureItem
|
|
150
|
+
icon="🔔"
|
|
151
|
+
title="Toast Messages"
|
|
152
|
+
description="Beautiful in-app notifications"
|
|
153
|
+
/>
|
|
154
|
+
</InfoCard>
|
|
155
|
+
</AnimationView>
|
|
156
|
+
|
|
157
|
+
{/* Best Practices Section */}
|
|
158
|
+
<AnimationView delay={1200} animType="FadeIn" duration={800}>
|
|
159
|
+
<InfoCard title={`💡 ${t('home.bestPractices')}`} icon="">
|
|
160
|
+
<FeatureItem
|
|
161
|
+
icon="📝"
|
|
162
|
+
title="Naming Conventions"
|
|
163
|
+
description="Use PascalCase for components, camelCase for functions"
|
|
164
|
+
/>
|
|
165
|
+
<FeatureItem
|
|
166
|
+
icon="🗂️"
|
|
167
|
+
title="File Organization"
|
|
168
|
+
description="Keep related files together, one component per file"
|
|
169
|
+
/>
|
|
170
|
+
<FeatureItem
|
|
171
|
+
icon="🎯"
|
|
172
|
+
title="Component Design"
|
|
173
|
+
description="Create small, reusable components with single responsibility"
|
|
174
|
+
/>
|
|
175
|
+
<FeatureItem
|
|
176
|
+
icon="🔐"
|
|
177
|
+
title="Type Safety"
|
|
178
|
+
description="Always define TypeScript types for props and state"
|
|
179
|
+
/>
|
|
180
|
+
</InfoCard>
|
|
181
|
+
</AnimationView>
|
|
182
|
+
|
|
183
|
+
{/* Next Steps Section */}
|
|
184
|
+
<AnimationView delay={1400} animType="FadeIn" duration={800}>
|
|
185
|
+
<InfoCard title={`🎯 ${t('home.nextSteps')}`} icon="">
|
|
186
|
+
<Text style={styles.cardText}>
|
|
187
|
+
1. Customize the theme in{' '}
|
|
188
|
+
<Text style={styles.highlight}>theme/Colors.ts</Text>
|
|
189
|
+
</Text>
|
|
190
|
+
<Text style={styles.cardText}>
|
|
191
|
+
2. Add your screens in{' '}
|
|
192
|
+
<Text style={styles.highlight}>screens/</Text>
|
|
193
|
+
</Text>
|
|
194
|
+
<Text style={styles.cardText}>
|
|
195
|
+
3. Update navigation in{' '}
|
|
196
|
+
<Text style={styles.highlight}>navigation/</Text>
|
|
197
|
+
</Text>
|
|
198
|
+
<Text style={styles.cardText}>
|
|
199
|
+
4. Create reusable components in{' '}
|
|
200
|
+
<Text style={styles.highlight}>components/</Text>
|
|
201
|
+
</Text>
|
|
202
|
+
<Text style={styles.cardText}>
|
|
203
|
+
5. Configure your app name and bundle ID
|
|
204
|
+
</Text>
|
|
205
|
+
</InfoCard>
|
|
206
|
+
</AnimationView>
|
|
207
|
+
|
|
208
|
+
{/* Footer */}
|
|
209
|
+
<AnimationView delay={1600} animType="FadeIn" duration={800}>
|
|
210
|
+
<View style={styles.footer}>
|
|
211
|
+
<Text style={styles.footerText}>{t('home.happyCoding')}</Text>
|
|
212
|
+
<Text style={styles.footerSubtext}>{t('home.builtWith')}</Text>
|
|
213
|
+
</View>
|
|
214
|
+
</AnimationView>
|
|
215
|
+
</ScrollView>
|
|
216
|
+
</FullScreenContainer>
|
|
217
|
+
);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
export default HomeScreen;
|
|
221
|
+
|
|
222
|
+
const getStyles = ({ colors }: ThemeType) =>
|
|
223
|
+
StyleSheet.create({
|
|
224
|
+
container: {
|
|
225
|
+
flex: 1,
|
|
226
|
+
backgroundColor: colors.backgroundColor,
|
|
227
|
+
},
|
|
228
|
+
scrollContent: {
|
|
229
|
+
padding: 20,
|
|
230
|
+
paddingBottom: 40,
|
|
231
|
+
},
|
|
232
|
+
header: {
|
|
233
|
+
alignItems: 'center',
|
|
234
|
+
marginBottom: 24,
|
|
235
|
+
paddingTop: 20,
|
|
236
|
+
},
|
|
237
|
+
logo: {
|
|
238
|
+
height: mobileScreenHeight * 0.15,
|
|
239
|
+
width: mobileScreenWidth * 0.5,
|
|
240
|
+
resizeMode: 'contain',
|
|
241
|
+
marginBottom: 16,
|
|
242
|
+
},
|
|
243
|
+
welcomeText: {
|
|
244
|
+
fontSize: 24,
|
|
245
|
+
fontWeight: '700',
|
|
246
|
+
color: colors.textColor,
|
|
247
|
+
textAlign: 'center',
|
|
248
|
+
marginBottom: 8,
|
|
249
|
+
},
|
|
250
|
+
subtitle: {
|
|
251
|
+
fontSize: 14,
|
|
252
|
+
color: colors.textColor + 'CC',
|
|
253
|
+
textAlign: 'center',
|
|
254
|
+
},
|
|
255
|
+
cardText: {
|
|
256
|
+
fontSize: 14,
|
|
257
|
+
color: colors.textColor,
|
|
258
|
+
lineHeight: 20,
|
|
259
|
+
marginBottom: 8,
|
|
260
|
+
},
|
|
261
|
+
codeBlock: {
|
|
262
|
+
backgroundColor: colors.textColor + '10',
|
|
263
|
+
padding: 12,
|
|
264
|
+
borderRadius: 8,
|
|
265
|
+
marginBottom: 8,
|
|
266
|
+
borderLeftWidth: 3,
|
|
267
|
+
borderLeftColor: colors.primary,
|
|
268
|
+
},
|
|
269
|
+
codeText: {
|
|
270
|
+
fontFamily: 'monospace',
|
|
271
|
+
fontSize: 13,
|
|
272
|
+
color: colors.textColor,
|
|
273
|
+
},
|
|
274
|
+
highlight: {
|
|
275
|
+
color: colors.primary,
|
|
276
|
+
fontWeight: '600',
|
|
277
|
+
fontFamily: 'monospace',
|
|
278
|
+
},
|
|
279
|
+
footer: {
|
|
280
|
+
alignItems: 'center',
|
|
281
|
+
marginTop: 24,
|
|
282
|
+
paddingTop: 24,
|
|
283
|
+
borderTopWidth: 1,
|
|
284
|
+
borderTopColor: colors.textColor + '20',
|
|
285
|
+
},
|
|
286
|
+
footerText: {
|
|
287
|
+
fontSize: 18,
|
|
288
|
+
fontWeight: '600',
|
|
289
|
+
color: colors.primary,
|
|
290
|
+
marginBottom: 4,
|
|
291
|
+
},
|
|
292
|
+
footerSubtext: {
|
|
293
|
+
fontSize: 13,
|
|
294
|
+
color: colors.textColor + 'CC',
|
|
295
|
+
},
|
|
296
|
+
});
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
TouchableOpacity,
|
|
6
|
+
StyleSheet,
|
|
7
|
+
ScrollView,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
import { useFormik } from 'formik';
|
|
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 { resetAndNavigate } from '../utils/navigationUtils';
|
|
17
|
+
import Routes from '../navigation/routes';
|
|
18
|
+
import { LoginSchema } from '../utils/validationSchemas';
|
|
19
|
+
import { userMockData } from '../mock';
|
|
20
|
+
import Toast from 'react-native-toast-message';
|
|
21
|
+
import { useAuth } from '../context/AuthContext';
|
|
22
|
+
|
|
23
|
+
const LoginScreen: FC = () => {
|
|
24
|
+
const { t } = useTranslation();
|
|
25
|
+
const theme = useTheme();
|
|
26
|
+
const { updateUser } = useAuth();
|
|
27
|
+
const styles = getStyles(theme);
|
|
28
|
+
|
|
29
|
+
const formik = useFormik({
|
|
30
|
+
initialValues: {
|
|
31
|
+
email: '',
|
|
32
|
+
password: '',
|
|
33
|
+
},
|
|
34
|
+
validationSchema: LoginSchema,
|
|
35
|
+
onSubmit: values => {
|
|
36
|
+
if (
|
|
37
|
+
values.email === userMockData.email &&
|
|
38
|
+
values.password === userMockData.password
|
|
39
|
+
) {
|
|
40
|
+
Toast.show({
|
|
41
|
+
type: 'success',
|
|
42
|
+
text1: t('auth.loginSuccessful'),
|
|
43
|
+
});
|
|
44
|
+
updateUser(userMockData);
|
|
45
|
+
resetAndNavigate(Routes.AppStack);
|
|
46
|
+
} else {
|
|
47
|
+
Toast.show({
|
|
48
|
+
type: 'error',
|
|
49
|
+
text1: t('auth.invalidCredentials'),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<FullScreenContainer
|
|
57
|
+
isKeyboardAvoidingView
|
|
58
|
+
style={styles.container}
|
|
59
|
+
barStyle="light-content"
|
|
60
|
+
>
|
|
61
|
+
<ScrollView
|
|
62
|
+
contentContainerStyle={styles.scrollContent}
|
|
63
|
+
showsVerticalScrollIndicator={false}
|
|
64
|
+
keyboardShouldPersistTaps="handled"
|
|
65
|
+
>
|
|
66
|
+
<AnimationView animType="FadeIn" duration={800}>
|
|
67
|
+
<View style={styles.header}>
|
|
68
|
+
<Text style={styles.title}>{t('auth.welcomeBack')}</Text>
|
|
69
|
+
<Text style={styles.subtitle}>{t('auth.signInToContinue')}</Text>
|
|
70
|
+
</View>
|
|
71
|
+
</AnimationView>
|
|
72
|
+
|
|
73
|
+
<AnimationView delay={200} animType="FadeIn" duration={800}>
|
|
74
|
+
<View style={styles.formContainer}>
|
|
75
|
+
{/* Email Input */}
|
|
76
|
+
<TextInput
|
|
77
|
+
label={t('auth.email')}
|
|
78
|
+
placeholder={t('auth.enterEmail')}
|
|
79
|
+
value={formik.values.email}
|
|
80
|
+
onChangeText={formik.handleChange('email')}
|
|
81
|
+
onBlur={formik.handleBlur('email')}
|
|
82
|
+
error={formik.errors.email}
|
|
83
|
+
touched={formik.touched.email}
|
|
84
|
+
keyboardType="email-address"
|
|
85
|
+
autoCapitalize="none"
|
|
86
|
+
autoCorrect={false}
|
|
87
|
+
/>
|
|
88
|
+
|
|
89
|
+
{/* Password Input */}
|
|
90
|
+
<TextInput
|
|
91
|
+
label={t('auth.password')}
|
|
92
|
+
placeholder={t('auth.enterPassword')}
|
|
93
|
+
value={formik.values.password}
|
|
94
|
+
onChangeText={formik.handleChange('password')}
|
|
95
|
+
onBlur={formik.handleBlur('password')}
|
|
96
|
+
error={formik.errors.password}
|
|
97
|
+
touched={formik.touched.password}
|
|
98
|
+
secureTextEntry
|
|
99
|
+
autoCapitalize="none"
|
|
100
|
+
autoCorrect={false}
|
|
101
|
+
/>
|
|
102
|
+
|
|
103
|
+
{/* Forgot Password */}
|
|
104
|
+
<TouchableOpacity style={styles.forgotPassword}>
|
|
105
|
+
<Text style={styles.forgotPasswordText}>
|
|
106
|
+
{t('auth.forgotPassword')}
|
|
107
|
+
</Text>
|
|
108
|
+
</TouchableOpacity>
|
|
109
|
+
|
|
110
|
+
{/* Login Button */}
|
|
111
|
+
<TouchableOpacity
|
|
112
|
+
style={styles.loginButton}
|
|
113
|
+
onPress={() => formik.handleSubmit()}
|
|
114
|
+
>
|
|
115
|
+
<Text style={styles.loginButtonText}>{t('auth.login')}</Text>
|
|
116
|
+
</TouchableOpacity>
|
|
117
|
+
|
|
118
|
+
{/* Sign Up Link */}
|
|
119
|
+
<View style={styles.signupContainer}>
|
|
120
|
+
<Text style={styles.signupText}>
|
|
121
|
+
{t('auth.dontHaveAccount')}{' '}
|
|
122
|
+
</Text>
|
|
123
|
+
<TouchableOpacity>
|
|
124
|
+
<Text style={styles.signupLink}>{t('auth.signUp')}</Text>
|
|
125
|
+
</TouchableOpacity>
|
|
126
|
+
</View>
|
|
127
|
+
</View>
|
|
128
|
+
</AnimationView>
|
|
129
|
+
</ScrollView>
|
|
130
|
+
</FullScreenContainer>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export default LoginScreen;
|
|
135
|
+
|
|
136
|
+
const getStyles = ({ colors }: ThemeType) =>
|
|
137
|
+
StyleSheet.create({
|
|
138
|
+
container: {
|
|
139
|
+
flex: 1,
|
|
140
|
+
backgroundColor: colors.backgroundColor,
|
|
141
|
+
},
|
|
142
|
+
scrollContent: {
|
|
143
|
+
flexGrow: 1,
|
|
144
|
+
padding: 20,
|
|
145
|
+
justifyContent: 'center',
|
|
146
|
+
},
|
|
147
|
+
header: {
|
|
148
|
+
marginBottom: 40,
|
|
149
|
+
alignItems: 'center',
|
|
150
|
+
},
|
|
151
|
+
title: {
|
|
152
|
+
fontSize: 32,
|
|
153
|
+
fontWeight: '700',
|
|
154
|
+
color: colors.textColor,
|
|
155
|
+
marginBottom: 8,
|
|
156
|
+
},
|
|
157
|
+
subtitle: {
|
|
158
|
+
fontSize: 16,
|
|
159
|
+
color: colors.textColor + 'CC',
|
|
160
|
+
},
|
|
161
|
+
formContainer: {
|
|
162
|
+
width: '100%',
|
|
163
|
+
},
|
|
164
|
+
forgotPassword: {
|
|
165
|
+
alignSelf: 'flex-end',
|
|
166
|
+
marginBottom: 24,
|
|
167
|
+
},
|
|
168
|
+
forgotPasswordText: {
|
|
169
|
+
color: colors.primary,
|
|
170
|
+
fontSize: 14,
|
|
171
|
+
fontWeight: '600',
|
|
172
|
+
},
|
|
173
|
+
loginButton: {
|
|
174
|
+
backgroundColor: colors.primary,
|
|
175
|
+
borderRadius: 12,
|
|
176
|
+
padding: 16,
|
|
177
|
+
alignItems: 'center',
|
|
178
|
+
marginBottom: 20,
|
|
179
|
+
},
|
|
180
|
+
loginButtonText: {
|
|
181
|
+
color: colors.white,
|
|
182
|
+
fontSize: 16,
|
|
183
|
+
fontWeight: '700',
|
|
184
|
+
},
|
|
185
|
+
signupContainer: {
|
|
186
|
+
flexDirection: 'row',
|
|
187
|
+
justifyContent: 'center',
|
|
188
|
+
alignItems: 'center',
|
|
189
|
+
},
|
|
190
|
+
signupText: {
|
|
191
|
+
color: colors.textColor + 'CC',
|
|
192
|
+
fontSize: 14,
|
|
193
|
+
},
|
|
194
|
+
signupLink: {
|
|
195
|
+
color: colors.primary,
|
|
196
|
+
fontSize: 14,
|
|
197
|
+
fontWeight: '600',
|
|
198
|
+
},
|
|
199
|
+
});
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import { View, Text, TouchableOpacity, StyleSheet, Alert } 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 { useAuth } from '../context/AuthContext';
|
|
9
|
+
import InfoCard from '../components/InfoCard';
|
|
10
|
+
import { navigate } from '../utils/navigationUtils';
|
|
11
|
+
import Routes from '../navigation/routes';
|
|
12
|
+
|
|
13
|
+
const ProfileScreen: FC = () => {
|
|
14
|
+
const { t } = useTranslation();
|
|
15
|
+
const theme = useTheme();
|
|
16
|
+
const styles = getStyles(theme);
|
|
17
|
+
const { user, handleLogout } = useAuth();
|
|
18
|
+
|
|
19
|
+
const confirmLogout = () => {
|
|
20
|
+
Alert.alert(
|
|
21
|
+
t('profile.logoutConfirmTitle'),
|
|
22
|
+
t('profile.logoutConfirmMessage'),
|
|
23
|
+
[
|
|
24
|
+
{
|
|
25
|
+
text: t('common.cancel'),
|
|
26
|
+
style: 'cancel',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
text: t('common.logout'),
|
|
30
|
+
onPress: handleLogout,
|
|
31
|
+
style: 'destructive',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
{ cancelable: true },
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<FullScreenContainer style={styles.container} barStyle="light-content">
|
|
40
|
+
<View style={styles.content}>
|
|
41
|
+
<AnimationView animType="FadeIn" duration={800}>
|
|
42
|
+
<View style={styles.header}>
|
|
43
|
+
<View style={styles.avatarContainer}>
|
|
44
|
+
<Text style={styles.avatarText}>
|
|
45
|
+
{user?.name?.charAt(0).toUpperCase() || 'U'}
|
|
46
|
+
</Text>
|
|
47
|
+
</View>
|
|
48
|
+
<Text style={styles.name}>{user?.name || 'User'}</Text>
|
|
49
|
+
<Text style={styles.email}>
|
|
50
|
+
{user?.email || 'user@example.com'}
|
|
51
|
+
</Text>
|
|
52
|
+
</View>
|
|
53
|
+
</AnimationView>
|
|
54
|
+
|
|
55
|
+
<AnimationView delay={300} animType="FadeIn" duration={800}>
|
|
56
|
+
<InfoCard title={t('profile.accountInformation')} icon="👤">
|
|
57
|
+
<View style={styles.infoRow}>
|
|
58
|
+
<Text style={styles.infoLabel}>{t('profile.name')}:</Text>
|
|
59
|
+
<Text style={styles.infoValue}>{user?.name || 'N/A'}</Text>
|
|
60
|
+
</View>
|
|
61
|
+
<View style={styles.infoRow}>
|
|
62
|
+
<Text style={styles.infoLabel}>{t('profile.email')}:</Text>
|
|
63
|
+
<Text style={styles.infoValue}>{user?.email || 'N/A'}</Text>
|
|
64
|
+
</View>
|
|
65
|
+
</InfoCard>
|
|
66
|
+
</AnimationView>
|
|
67
|
+
|
|
68
|
+
<AnimationView delay={450} animType="FadeIn" duration={800}>
|
|
69
|
+
<TouchableOpacity
|
|
70
|
+
style={styles.settingsButton}
|
|
71
|
+
onPress={() => navigate(Routes.SettingsScreen)}
|
|
72
|
+
>
|
|
73
|
+
<Text style={styles.settingsButtonText}>
|
|
74
|
+
⚙️ {t('settings.settings')}
|
|
75
|
+
</Text>
|
|
76
|
+
</TouchableOpacity>
|
|
77
|
+
</AnimationView>
|
|
78
|
+
|
|
79
|
+
<AnimationView delay={600} animType="FadeIn" duration={800}>
|
|
80
|
+
<TouchableOpacity style={styles.logoutButton} onPress={confirmLogout}>
|
|
81
|
+
<Text style={styles.logoutButtonText}>{t('common.logout')}</Text>
|
|
82
|
+
</TouchableOpacity>
|
|
83
|
+
</AnimationView>
|
|
84
|
+
</View>
|
|
85
|
+
</FullScreenContainer>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export default ProfileScreen;
|
|
90
|
+
|
|
91
|
+
const getStyles = ({ colors }: ThemeType) =>
|
|
92
|
+
StyleSheet.create({
|
|
93
|
+
container: {
|
|
94
|
+
flex: 1,
|
|
95
|
+
backgroundColor: colors.backgroundColor,
|
|
96
|
+
},
|
|
97
|
+
content: {
|
|
98
|
+
flex: 1,
|
|
99
|
+
padding: 20,
|
|
100
|
+
},
|
|
101
|
+
header: {
|
|
102
|
+
alignItems: 'center',
|
|
103
|
+
marginBottom: 32,
|
|
104
|
+
marginTop: 40,
|
|
105
|
+
},
|
|
106
|
+
avatarContainer: {
|
|
107
|
+
width: 100,
|
|
108
|
+
height: 100,
|
|
109
|
+
borderRadius: 50,
|
|
110
|
+
backgroundColor: colors.primary,
|
|
111
|
+
justifyContent: 'center',
|
|
112
|
+
alignItems: 'center',
|
|
113
|
+
marginBottom: 16,
|
|
114
|
+
},
|
|
115
|
+
avatarText: {
|
|
116
|
+
fontSize: 40,
|
|
117
|
+
fontWeight: '700',
|
|
118
|
+
color: colors.white,
|
|
119
|
+
},
|
|
120
|
+
name: {
|
|
121
|
+
fontSize: 24,
|
|
122
|
+
fontWeight: '700',
|
|
123
|
+
color: colors.textColor,
|
|
124
|
+
marginBottom: 4,
|
|
125
|
+
},
|
|
126
|
+
email: {
|
|
127
|
+
fontSize: 14,
|
|
128
|
+
color: colors.textColor + 'CC',
|
|
129
|
+
},
|
|
130
|
+
infoRow: {
|
|
131
|
+
flexDirection: 'row',
|
|
132
|
+
justifyContent: 'space-between',
|
|
133
|
+
alignItems: 'center',
|
|
134
|
+
paddingVertical: 8,
|
|
135
|
+
},
|
|
136
|
+
infoLabel: {
|
|
137
|
+
fontSize: 14,
|
|
138
|
+
fontWeight: '600',
|
|
139
|
+
color: colors.textColor,
|
|
140
|
+
},
|
|
141
|
+
infoValue: {
|
|
142
|
+
fontSize: 14,
|
|
143
|
+
color: colors.textColor + 'CC',
|
|
144
|
+
},
|
|
145
|
+
logoutButton: {
|
|
146
|
+
backgroundColor: colors.primary,
|
|
147
|
+
borderRadius: 12,
|
|
148
|
+
padding: 16,
|
|
149
|
+
alignItems: 'center',
|
|
150
|
+
marginTop: 24,
|
|
151
|
+
},
|
|
152
|
+
logoutButtonText: {
|
|
153
|
+
color: colors.white,
|
|
154
|
+
fontSize: 16,
|
|
155
|
+
fontWeight: '700',
|
|
156
|
+
},
|
|
157
|
+
settingsButton: {
|
|
158
|
+
backgroundColor: colors.backgroundColor,
|
|
159
|
+
borderRadius: 12,
|
|
160
|
+
padding: 16,
|
|
161
|
+
alignItems: 'center',
|
|
162
|
+
marginTop: 32,
|
|
163
|
+
borderWidth: 1,
|
|
164
|
+
borderColor: colors.primary,
|
|
165
|
+
},
|
|
166
|
+
settingsButtonText: {
|
|
167
|
+
color: colors.primary,
|
|
168
|
+
fontSize: 16,
|
|
169
|
+
fontWeight: '700',
|
|
170
|
+
},
|
|
171
|
+
});
|