morethanadiagnosis-hub/mobile/app/(tabs)/profile.tsx
Claude eb04163b3b
feat: implement authentication system for mobile app
- 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
2025-11-18 19:32:16 +00:00

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>
);
}