- Add API integration layer with axios and token management - Create Zustand auth store for state management - Implement login screen with validation - Implement signup screen with password strength indicator - Implement forgot password flow with multi-step UI - Update root layout with auth state protection - Integrate profile screen with auth store - Install AsyncStorage and expo-secure-store dependencies
280 lines
8.8 KiB
TypeScript
280 lines
8.8 KiB
TypeScript
import React from 'react';
|
|
import {
|
|
View,
|
|
ScrollView,
|
|
Text,
|
|
StyleSheet,
|
|
SafeAreaView,
|
|
TouchableOpacity,
|
|
Alert,
|
|
ActivityIndicator,
|
|
} from 'react-native';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { useRouter } from 'expo-router';
|
|
import { useAuthStore } from '../lib/auth-store';
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: '#f5f5f5',
|
|
},
|
|
profileHeader: {
|
|
backgroundColor: '#fff',
|
|
paddingVertical: 24,
|
|
paddingHorizontal: 16,
|
|
alignItems: 'center',
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: '#e0e0e0',
|
|
},
|
|
avatar: {
|
|
width: 80,
|
|
height: 80,
|
|
borderRadius: 40,
|
|
backgroundColor: '#0066cc',
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
marginBottom: 12,
|
|
},
|
|
avatarText: {
|
|
color: '#fff',
|
|
fontSize: 32,
|
|
fontWeight: '700',
|
|
},
|
|
profileName: {
|
|
fontSize: 20,
|
|
fontWeight: '700',
|
|
color: '#000',
|
|
marginBottom: 4,
|
|
},
|
|
profileStatus: {
|
|
fontSize: 14,
|
|
color: '#666',
|
|
},
|
|
section: {
|
|
paddingHorizontal: 16,
|
|
marginTop: 16,
|
|
},
|
|
sectionTitle: {
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
color: '#999',
|
|
textTransform: 'uppercase',
|
|
marginBottom: 8,
|
|
},
|
|
menuItem: {
|
|
backgroundColor: '#fff',
|
|
paddingVertical: 14,
|
|
paddingHorizontal: 16,
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: '#f0f0f0',
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
},
|
|
menuItemFirst: {
|
|
borderTopLeftRadius: 12,
|
|
borderTopRightRadius: 12,
|
|
},
|
|
menuItemLast: {
|
|
borderBottomLeftRadius: 12,
|
|
borderBottomRightRadius: 12,
|
|
borderBottomWidth: 0,
|
|
},
|
|
menuIcon: {
|
|
width: 24,
|
|
height: 24,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
marginRight: 12,
|
|
},
|
|
menuLabel: {
|
|
fontSize: 15,
|
|
color: '#000',
|
|
flex: 1,
|
|
fontWeight: '500',
|
|
},
|
|
menuArrow: {
|
|
color: '#999',
|
|
},
|
|
signOutButton: {
|
|
backgroundColor: '#fff',
|
|
paddingVertical: 12,
|
|
paddingHorizontal: 16,
|
|
marginTop: 8,
|
|
borderRadius: 12,
|
|
alignItems: 'center',
|
|
borderWidth: 1,
|
|
borderColor: '#ff4444',
|
|
},
|
|
signOutText: {
|
|
color: '#ff4444',
|
|
fontSize: 15,
|
|
fontWeight: '600',
|
|
},
|
|
});
|
|
|
|
export default function ProfileScreen() {
|
|
const router = useRouter();
|
|
const { user, isAuthenticated, isLoading, logout } = useAuthStore();
|
|
|
|
const handleSignOut = () => {
|
|
Alert.alert('Sign Out', 'Are you sure you want to sign out?', [
|
|
{ text: 'Cancel', style: 'cancel' },
|
|
{
|
|
text: 'Sign Out',
|
|
style: 'destructive',
|
|
onPress: async () => {
|
|
await logout();
|
|
router.replace('/(auth)/login');
|
|
},
|
|
},
|
|
]);
|
|
};
|
|
|
|
const handleSignIn = () => {
|
|
router.push('/(auth)/login');
|
|
};
|
|
|
|
// Get user initials for avatar
|
|
const getInitials = () => {
|
|
if (!user?.name) return '?';
|
|
const names = user.name.split(' ');
|
|
if (names.length >= 2) {
|
|
return `${names[0][0]}${names[1][0]}`.toUpperCase();
|
|
}
|
|
return names[0][0].toUpperCase();
|
|
};
|
|
|
|
if (!isAuthenticated) {
|
|
return (
|
|
<SafeAreaView style={styles.container}>
|
|
<View style={styles.profileHeader}>
|
|
<View style={styles.avatar}>
|
|
<Ionicons name="person" size={40} color="#fff" />
|
|
</View>
|
|
<Text style={styles.profileName}>Welcome</Text>
|
|
<Text style={styles.profileStatus}>Sign in to access your profile</Text>
|
|
</View>
|
|
|
|
<View style={styles.section}>
|
|
<TouchableOpacity
|
|
style={[styles.menuItem, styles.menuItemFirst, styles.menuItemLast]}
|
|
onPress={handleSignIn}
|
|
>
|
|
<View style={styles.menuIcon}>
|
|
<Ionicons name="log-in" size={20} color="#0066cc" />
|
|
</View>
|
|
<Text style={styles.menuLabel}>Sign In</Text>
|
|
<Ionicons name="chevron-forward" size={20} style={styles.menuArrow} />
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>About</Text>
|
|
<TouchableOpacity style={[styles.menuItem, styles.menuItemFirst]}>
|
|
<View style={styles.menuIcon}>
|
|
<Ionicons name="information-circle" size={20} color="#0066cc" />
|
|
</View>
|
|
<Text style={styles.menuLabel}>About Us</Text>
|
|
<Ionicons name="chevron-forward" size={20} style={styles.menuArrow} />
|
|
</TouchableOpacity>
|
|
<TouchableOpacity style={styles.menuItem}>
|
|
<View style={styles.menuIcon}>
|
|
<Ionicons name="shield-checkmark" size={20} color="#0066cc" />
|
|
</View>
|
|
<Text style={styles.menuLabel}>Privacy Policy</Text>
|
|
<Ionicons name="chevron-forward" size={20} style={styles.menuArrow} />
|
|
</TouchableOpacity>
|
|
<TouchableOpacity style={[styles.menuItem, styles.menuItemLast]}>
|
|
<View style={styles.menuIcon}>
|
|
<Ionicons name="document-text" size={20} color="#0066cc" />
|
|
</View>
|
|
<Text style={styles.menuLabel}>Terms of Service</Text>
|
|
<Ionicons name="chevron-forward" size={20} style={styles.menuArrow} />
|
|
</TouchableOpacity>
|
|
</View>
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<SafeAreaView style={styles.container}>
|
|
<ScrollView showsVerticalScrollIndicator={false}>
|
|
<View style={styles.profileHeader}>
|
|
<View style={styles.avatar}>
|
|
<Text style={styles.avatarText}>{getInitials()}</Text>
|
|
</View>
|
|
<Text style={styles.profileName}>{user?.name || 'User'}</Text>
|
|
<Text style={styles.profileStatus}>{user?.email || 'Active Member'}</Text>
|
|
</View>
|
|
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>Account</Text>
|
|
<TouchableOpacity style={[styles.menuItem, styles.menuItemFirst]}>
|
|
<View style={styles.menuIcon}>
|
|
<Ionicons name="person" size={20} color="#0066cc" />
|
|
</View>
|
|
<Text style={styles.menuLabel}>Edit Profile</Text>
|
|
<Ionicons name="chevron-forward" size={20} style={styles.menuArrow} />
|
|
</TouchableOpacity>
|
|
<TouchableOpacity style={styles.menuItem}>
|
|
<View style={styles.menuIcon}>
|
|
<Ionicons name="notifications" size={20} color="#0066cc" />
|
|
</View>
|
|
<Text style={styles.menuLabel}>Notifications</Text>
|
|
<Ionicons name="chevron-forward" size={20} style={styles.menuArrow} />
|
|
</TouchableOpacity>
|
|
<TouchableOpacity style={[styles.menuItem, styles.menuItemLast]}>
|
|
<View style={styles.menuIcon}>
|
|
<Ionicons name="lock-closed" size={20} color="#0066cc" />
|
|
</View>
|
|
<Text style={styles.menuLabel}>Change Password</Text>
|
|
<Ionicons name="chevron-forward" size={20} style={styles.menuArrow} />
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>Preferences</Text>
|
|
<TouchableOpacity style={[styles.menuItem, styles.menuItemFirst]}>
|
|
<View style={styles.menuIcon}>
|
|
<Ionicons name="moon" size={20} color="#0066cc" />
|
|
</View>
|
|
<Text style={styles.menuLabel}>Dark Mode</Text>
|
|
<Ionicons name="chevron-forward" size={20} style={styles.menuArrow} />
|
|
</TouchableOpacity>
|
|
<TouchableOpacity style={[styles.menuItem, styles.menuItemLast]}>
|
|
<View style={styles.menuIcon}>
|
|
<Ionicons name="language" size={20} color="#0066cc" />
|
|
</View>
|
|
<Text style={styles.menuLabel}>Language</Text>
|
|
<Ionicons name="chevron-forward" size={20} style={styles.menuArrow} />
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
<View style={styles.section}>
|
|
<Text style={styles.sectionTitle}>Help</Text>
|
|
<TouchableOpacity style={[styles.menuItem, styles.menuItemFirst]}>
|
|
<View style={styles.menuIcon}>
|
|
<Ionicons name="help-circle" size={20} color="#0066cc" />
|
|
</View>
|
|
<Text style={styles.menuLabel}>Help & Support</Text>
|
|
<Ionicons name="chevron-forward" size={20} style={styles.menuArrow} />
|
|
</TouchableOpacity>
|
|
<TouchableOpacity style={[styles.menuItem, styles.menuItemLast]}>
|
|
<View style={styles.menuIcon}>
|
|
<Ionicons name="mail" size={20} color="#0066cc" />
|
|
</View>
|
|
<Text style={styles.menuLabel}>Contact Us</Text>
|
|
<Ionicons name="chevron-forward" size={20} style={styles.menuArrow} />
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
<View style={[styles.section, { marginBottom: 40 }]}>
|
|
<TouchableOpacity style={styles.signOutButton} onPress={handleSignOut}>
|
|
<Text style={styles.signOutText}>Sign Out</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</ScrollView>
|
|
</SafeAreaView>
|
|
);
|
|
}
|