Enhance login and profile screens with auto-login feature, improved UI, and logout functionality

This commit is contained in:
2025-07-28 00:12:32 +02:00
parent a4fa09589e
commit 60fdb02c9d
2 changed files with 202 additions and 38 deletions

View File

@@ -1,9 +1,10 @@
import { MaterialIcons } from '@expo/vector-icons';
import axios from 'axios'; import axios from 'axios';
import { useRouter } from 'expo-router'; import { useRouter } from 'expo-router';
import * as SecureStore from 'expo-secure-store'; import * as SecureStore from 'expo-secure-store';
import { StatusBar } from 'expo-status-bar'; import { StatusBar } from 'expo-status-bar';
import React, { useState } from "react"; import React, { useEffect, useState } from "react";
import { ActivityIndicator, Alert, StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native"; import { ActivityIndicator, Alert, Platform, StyleSheet, Text, TextInput, ToastAndroid, TouchableOpacity, View } from "react-native";
const PRIMARY = '#A24BFA'; const PRIMARY = '#A24BFA';
const BG = '#0c0a0a'; const BG = '#0c0a0a';
@@ -12,18 +13,36 @@ export default function Index() {
const [username, setUsername] = useState(""); const [username, setUsername] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [autoLogin, setAutoLogin] = useState(false);
const router = useRouter(); const router = useRouter();
async function handleLogin() { useEffect(() => {
(async () => {
const savedEmail = await SecureStore.getItemAsync('email');
const savedPassword = await SecureStore.getItemAsync('password');
if (savedEmail && savedPassword) {
setUsername(savedEmail);
setPassword(savedPassword);
setAutoLogin(true);
setTimeout(() => {
handleLogin(savedEmail, savedPassword, true);
}, 1000);
}
})();
}, []);
async function handleLogin(emailOverride?: string, passwordOverride?: string, isAuto?: boolean) {
setLoading(true); setLoading(true);
console.log('Login attempt:', username); const user = emailOverride ?? username;
const pass = passwordOverride ?? password;
console.log('Login attempt:', user);
try { try {
const response = await axios.post( const response = await axios.post(
"https://mymenu.mcdonalds.hu/api/AccountApi/Login", "https://mymenu.mcdonalds.hu/api/AccountApi/Login",
{ {
Data: { Data: {
UserName: username, UserName: user,
Password: password Password: pass
} }
}, },
{ {
@@ -41,16 +60,25 @@ export default function Index() {
const fullName = response.data.Data.FullName; const fullName = response.data.Data.FullName;
await SecureStore.setItemAsync('cookie', cookie || ''); await SecureStore.setItemAsync('cookie', cookie || '');
await SecureStore.setItemAsync('userId', String(userId)); await SecureStore.setItemAsync('userId', String(userId));
await SecureStore.setItemAsync('email', username); await SecureStore.setItemAsync('email', user);
await SecureStore.setItemAsync('password', password); await SecureStore.setItemAsync('password', pass);
await SecureStore.setItemAsync('fullName', fullName || ''); await SecureStore.setItemAsync('fullName', fullName || '');
console.log('Saved to SecureStore:', { cookie, userId, username, password, fullName }); console.log('Saved to SecureStore:', { cookie, userId, user, pass, fullName });
if (isAuto) {
if (Platform.OS === 'android') {
ToastAndroid.show('Sikeres automatikus bejelentkezés', ToastAndroid.SHORT);
} else {
// iOS: custom toast helyett Alert
Alert.alert('Sikeres automatikus bejelentkezés');
}
}
router.replace('/profile'); router.replace('/profile');
} catch (e) { } catch (e) {
console.log('Login error:', e); console.log('Login error:', e);
Alert.alert('Hiba', 'Hibás felhasználónév vagy jelszó, vagy hálózati hiba.'); Alert.alert('Hiba', 'Hibás felhasználónév vagy jelszó, vagy hálózati hiba.');
} finally { } finally {
setLoading(false); setLoading(false);
setAutoLogin(false);
} }
} }
@@ -62,6 +90,8 @@ export default function Index() {
<Text style={styles.subtitle}>Jelentkezz be a mymenu fiókodba</Text> <Text style={styles.subtitle}>Jelentkezz be a mymenu fiókodba</Text>
<View style={{ height: 24 }} /> <View style={{ height: 24 }} />
<Text style={styles.label}>Felhasználónév</Text> <Text style={styles.label}>Felhasználónév</Text>
<View style={styles.inputRow}>
<MaterialIcons name="email" size={22} color="#bdbdbd" style={{ marginRight: 8 }} />
<TextInput <TextInput
style={styles.input} style={styles.input}
placeholder="valaki@gmail.com" placeholder="valaki@gmail.com"
@@ -70,8 +100,11 @@ export default function Index() {
onChangeText={setUsername} onChangeText={setUsername}
autoCapitalize="none" autoCapitalize="none"
/> />
</View>
<View style={{ height: 16 }} /> <View style={{ height: 16 }} />
<Text style={styles.label}>Jelszó</Text> <Text style={styles.label}>Jelszó</Text>
<View style={styles.inputRow}>
<MaterialIcons name="lock" size={22} color="#bdbdbd" style={{ marginRight: 8 }} />
<TextInput <TextInput
style={styles.input} style={styles.input}
placeholder="••••••••" placeholder="••••••••"
@@ -80,8 +113,9 @@ export default function Index() {
onChangeText={setPassword} onChangeText={setPassword}
secureTextEntry secureTextEntry
/> />
</View>
<View style={{ height: 24 }} /> <View style={{ height: 24 }} />
<TouchableOpacity style={styles.button} onPress={handleLogin} disabled={loading}> <TouchableOpacity style={styles.button} onPress={() => handleLogin()} disabled={loading}>
{loading ? ( {loading ? (
<ActivityIndicator color="#fff" /> <ActivityIndicator color="#fff" />
) : ( ) : (
@@ -89,6 +123,12 @@ export default function Index() {
)} )}
</TouchableOpacity> </TouchableOpacity>
</View> </View>
{(loading || autoLogin) && (
<View style={styles.loadingOverlay}>
<ActivityIndicator size="large" color={PRIMARY} />
<Text style={styles.loadingText}>{autoLogin ? 'Bejelentkezés...' : 'Betöltés...'}</Text>
</View>
)}
</View> </View>
); );
} }
@@ -127,22 +167,31 @@ const styles = StyleSheet.create({
color: '#bdbdbd', color: '#bdbdbd',
fontSize: 16, fontSize: 16,
textAlign: 'center', textAlign: 'center',
marginBottom: 8, marginBottom: 24,
}, },
label: { label: {
color: '#bdbdbd', color: '#bdbdbd',
fontSize: 14, fontSize: 14,
marginBottom: 4, marginBottom: 8,
}, },
input: { inputRow: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: 'rgba(20,18,24,1)', backgroundColor: 'rgba(20,18,24,1)',
borderColor: PRIMARY, borderColor: PRIMARY,
borderWidth: 1, borderWidth: 1,
borderRadius: 12, borderRadius: 12,
marginBottom: 16,
paddingHorizontal: 8,
},
input: {
flex: 1,
backgroundColor: 'transparent',
color: '#fff', color: '#fff',
paddingHorizontal: 16, paddingHorizontal: 8,
paddingVertical: 12, paddingVertical: 12,
fontSize: 16, fontSize: 16,
borderWidth: 0,
}, },
button: { button: {
backgroundColor: PRIMARY, backgroundColor: PRIMARY,
@@ -161,4 +210,21 @@ const styles = StyleSheet.create({
fontWeight: 'bold', fontWeight: 'bold',
fontSize: 18, fontSize: 18,
}, },
loadingOverlay: {
position: 'absolute',
left: 0,
top: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(12,10,10,0.85)',
justifyContent: 'center',
alignItems: 'center',
zIndex: 10,
},
loadingText: {
color: PRIMARY,
fontSize: 18,
marginTop: 16,
fontWeight: 'bold',
},
}); });

View File

@@ -1,14 +1,23 @@
import { Ionicons, MaterialCommunityIcons, MaterialIcons } from '@expo/vector-icons';
import { useRouter } from 'expo-router';
import * as SecureStore from 'expo-secure-store'; import * as SecureStore from 'expo-secure-store';
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { StyleSheet, Text, View } from "react-native"; import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
const PRIMARY = '#A24BFA'; const PRIMARY = '#A24BFA';
const BG = '#0c0a0a'; const BG = '#0c0a0a';
const NAV_ITEMS = [
{ key: 'profile', label: 'Profilom', icon: (color: string) => <MaterialIcons name="person" size={28} color={color} /> },
{ key: 'schedule', label: 'Beosztás', icon: (color: string) => <MaterialCommunityIcons name="calendar-month" size={28} color={color} /> },
{ key: 'requests', label: 'Kérelmek', icon: (color: string) => <Ionicons name="mail" size={28} color={color} /> },
];
export default function Profile() { export default function Profile() {
const [fullName, setFullName] = useState(''); const [fullName, setFullName] = useState('');
const [email, setEmail] = useState(''); const [email, setEmail] = useState('');
const [userId, setUserId] = useState(''); const [userId, setUserId] = useState('');
const [activeTab, setActiveTab] = useState('profile');
const router = useRouter();
useEffect(() => { useEffect(() => {
(async () => { (async () => {
@@ -21,9 +30,18 @@ export default function Profile() {
})(); })();
}, []); }, []);
async function handleLogout() {
await SecureStore.deleteItemAsync('cookie');
await SecureStore.deleteItemAsync('userId');
await SecureStore.deleteItemAsync('email');
await SecureStore.deleteItemAsync('password');
await SecureStore.deleteItemAsync('fullName');
router.replace('/');
}
function renderContent() {
if (activeTab === 'profile') {
return ( return (
<View style={styles.container}>
<Text style={styles.title}>Profil</Text>
<View style={styles.card}> <View style={styles.card}>
<Text style={styles.label}>Név:</Text> <Text style={styles.label}>Név:</Text>
<Text style={styles.value}>{fullName}</Text> <Text style={styles.value}>{fullName}</Text>
@@ -31,6 +49,41 @@ export default function Profile() {
<Text style={styles.value}>{email}</Text> <Text style={styles.value}>{email}</Text>
<Text style={styles.label}>UserID:</Text> <Text style={styles.label}>UserID:</Text>
<Text style={styles.value}>{userId}</Text> <Text style={styles.value}>{userId}</Text>
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
<Text style={styles.logoutText}>Kijelentkezés</Text>
</TouchableOpacity>
</View>
);
} else if (activeTab === 'schedule') {
return (
<View style={styles.card}>
<Text style={styles.value}>Beosztás funkció hamarosan</Text>
</View>
);
} else if (activeTab === 'requests') {
return (
<View style={styles.card}>
<Text style={styles.value}>Kérelmek funkció hamarosan</Text>
</View>
);
}
}
return (
<View style={styles.container}>
<Text style={styles.title}>Profil</Text>
{renderContent()}
<View style={styles.navBar}>
{NAV_ITEMS.map(item => (
<TouchableOpacity
key={item.key}
style={styles.navItem}
onPress={() => setActiveTab(item.key)}
>
{item.icon(activeTab === item.key ? PRIMARY : '#bdbdbd')}
<Text style={[styles.navLabel, { color: activeTab === item.key ? PRIMARY : '#bdbdbd' }]}>{item.label}</Text>
</TouchableOpacity>
))}
</View> </View>
</View> </View>
); );
@@ -42,6 +95,7 @@ const styles = StyleSheet.create({
backgroundColor: BG, backgroundColor: BG,
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
paddingBottom: 64,
}, },
title: { title: {
color: '#fff', color: '#fff',
@@ -49,6 +103,7 @@ const styles = StyleSheet.create({
fontSize: 28, fontSize: 28,
textAlign: 'center', textAlign: 'center',
marginBottom: 24, marginBottom: 24,
marginTop: 32,
}, },
card: { card: {
backgroundColor: 'rgba(24, 20, 28, 0.95)', backgroundColor: 'rgba(24, 20, 28, 0.95)',
@@ -61,6 +116,7 @@ const styles = StyleSheet.create({
shadowRadius: 24, shadowRadius: 24,
shadowOffset: { width: 0, height: 8 }, shadowOffset: { width: 0, height: 8 },
elevation: 8, elevation: 8,
marginBottom: 32,
}, },
label: { label: {
color: '#bdbdbd', color: '#bdbdbd',
@@ -73,4 +129,46 @@ const styles = StyleSheet.create({
fontSize: 18, fontSize: 18,
marginBottom: 8, marginBottom: 8,
}, },
navBar: {
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center',
backgroundColor: 'rgba(24, 20, 28, 0.98)',
borderTopWidth: 1,
borderTopColor: '#222',
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
height: 64,
paddingHorizontal: 16,
},
navItem: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
navLabel: {
fontSize: 13,
marginTop: 2,
fontWeight: 'bold',
},
logoutButton: {
backgroundColor: PRIMARY,
borderRadius: 12,
paddingVertical: 16,
alignItems: 'center',
marginTop: 32,
shadowColor: PRIMARY,
shadowOpacity: 0.3,
shadowRadius: 8,
shadowOffset: { width: 0, height: 2 },
elevation: 2,
},
logoutText: {
color: '#fff',
fontWeight: 'bold',
fontSize: 18,
letterSpacing: 1,
},
}); });