Skip to content

Commit 46377ff

Browse files
committed
add Login and SignUp screen
1 parent 47c5068 commit 46377ff

1 file changed

Lines changed: 118 additions & 0 deletions

File tree

mobile/src/screens/LoginScreen.js

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import React, { useState } from 'react';
2+
import { View, Text, TextInput, TouchableOpacity, StyleSheet, Alert, KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
3+
import { SafeAreaView } from 'react-native-safe-area-context';
4+
import { User } from 'lucide-react-native';
5+
import { colors } from '../theme/colors';
6+
import { useApp } from '../context/AppContext';
7+
8+
export default function LoginScreen({ navigation }) {
9+
const [isSignUp, setIsSignUp] = useState(false);
10+
const [form, setForm] = useState({ name: '', email: '', password: '', confirm: '' });
11+
const { login } = useApp();
12+
13+
const handleAuth = async () => {
14+
if (!form.email || !form.password) { Alert.alert('Error', 'Please fill all fields'); return; }
15+
if (isSignUp) {
16+
if (!form.name) { Alert.alert('Error', 'Please enter your name'); return; }
17+
if (form.password !== form.confirm) { Alert.alert('Error', 'Passwords do not match'); return; }
18+
if (form.password.length < 6) { Alert.alert('Error', 'Password must be at least 6 characters'); return; }
19+
const user = {
20+
name: form.name,
21+
email: form.email,
22+
picture: null,
23+
};
24+
await login(user);
25+
navigation.goBack();
26+
} else {
27+
const { AsyncStorage } = require('@react-native-async-storage/async-storage');
28+
const saved = await AsyncStorage.getItem('zappify_user');
29+
if (saved) {
30+
const u = JSON.parse(saved);
31+
if (u.email === form.email) {
32+
await login(u);
33+
navigation.goBack();
34+
} else {
35+
Alert.alert('Error', 'Account not found. Please sign up first.');
36+
}
37+
} else {
38+
Alert.alert('Error', 'Account not found. Please sign up first.');
39+
}
40+
}
41+
};
42+
43+
return (
44+
<SafeAreaView style={styles.safe}>
45+
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined} style={{ flex: 1 }}>
46+
<ScrollView contentContainerStyle={styles.container} keyboardShouldPersistTaps="handled">
47+
<View style={styles.iconWrap}>
48+
<User size={40} color={colors.brand} />
49+
</View>
50+
<Text style={styles.heading}>{isSignUp ? 'Create Account' : 'Welcome Back'}</Text>
51+
<Text style={styles.sub}>{isSignUp ? 'Join Zappify today' : 'Login to your Zappify account'}</Text>
52+
53+
{isSignUp && (
54+
<TextInput
55+
style={styles.input}
56+
placeholder="Full Name"
57+
placeholderTextColor={colors.gray}
58+
value={form.name}
59+
onChangeText={v => setForm({ ...form, name: v })}
60+
/>
61+
)}
62+
<TextInput
63+
style={styles.input}
64+
placeholder="Email Address"
65+
placeholderTextColor={colors.gray}
66+
value={form.email}
67+
onChangeText={v => setForm({ ...form, email: v })}
68+
keyboardType="email-address"
69+
autoCapitalize="none"
70+
/>
71+
<TextInput
72+
style={styles.input}
73+
placeholder="Password"
74+
placeholderTextColor={colors.gray}
75+
value={form.password}
76+
onChangeText={v => setForm({ ...form, password: v })}
77+
secureTextEntry
78+
/>
79+
{isSignUp && (
80+
<TextInput
81+
style={styles.input}
82+
placeholder="Confirm Password"
83+
placeholderTextColor={colors.gray}
84+
value={form.confirm}
85+
onChangeText={v => setForm({ ...form, confirm: v })}
86+
secureTextEntry
87+
/>
88+
)}
89+
90+
<TouchableOpacity style={styles.authBtn} onPress={handleAuth}>
91+
<Text style={styles.authBtnTxt}>{isSignUp ? 'CREATE ACCOUNT' : 'SIGN IN'}</Text>
92+
</TouchableOpacity>
93+
94+
<TouchableOpacity style={styles.switchBtn} onPress={() => setIsSignUp(!isSignUp)}>
95+
<Text style={styles.switchTxt}>
96+
{isSignUp ? 'Already have an account? ' : "Don't have an account? "}
97+
<Text style={styles.switchLink}>{isSignUp ? 'Sign In' : 'Sign Up'}</Text>
98+
</Text>
99+
</TouchableOpacity>
100+
</ScrollView>
101+
</KeyboardAvoidingView>
102+
</SafeAreaView>
103+
);
104+
}
105+
106+
const styles = StyleSheet.create({
107+
safe: { flex: 1, backgroundColor: colors.white },
108+
container: { padding: 28, alignItems: 'center' },
109+
iconWrap: { width: 80, height: 80, borderRadius: 40, backgroundColor: colors.brandLight, alignItems: 'center', justifyContent: 'center', marginBottom: 20, marginTop: 20 },
110+
heading: { fontSize: 26, fontWeight: '800', color: colors.dark, marginBottom: 6 },
111+
sub: { fontSize: 14, color: colors.gray, marginBottom: 28 },
112+
input: { width: '100%', borderWidth: 1.5, borderColor: colors.border, borderRadius: 12, paddingHorizontal: 16, paddingVertical: 14, fontSize: 15, color: colors.dark, marginBottom: 14 },
113+
authBtn: { width: '100%', backgroundColor: colors.brand, borderRadius: 12, paddingVertical: 16, alignItems: 'center', marginTop: 4 },
114+
authBtnTxt: { color: colors.white, fontWeight: '800', fontSize: 15, letterSpacing: 1 },
115+
switchBtn: { marginTop: 20 },
116+
switchTxt: { fontSize: 14, color: colors.gray },
117+
switchLink: { color: colors.brand, fontWeight: '700' },
118+
});

0 commit comments

Comments
 (0)