add profile details and features
This commit is contained in:
parent
3b571ede07
commit
2b5446555b
@ -1,18 +1,266 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { View, Text, useColorScheme } from 'react-native';
|
import { View, Text, TouchableOpacity, useColorScheme, ScrollView, Alert, Image, ActivityIndicator, Modal } from 'react-native';
|
||||||
|
import { Ionicons } from '@expo/vector-icons';
|
||||||
|
import { useNavigation } from '@react-navigation/native';
|
||||||
|
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||||
|
import { RootStackParamList } from '../navigation/AppNavigator';
|
||||||
import { getThemeStyles, commonStyles } from '../theme/styles';
|
import { getThemeStyles, commonStyles } from '../theme/styles';
|
||||||
|
import { useAuthStore } from '../store/useAuthStore';
|
||||||
|
import { authService } from '../services/api';
|
||||||
|
import { COLORS } from '../theme/colors';
|
||||||
|
import appConfig from '../../app.json';
|
||||||
|
|
||||||
export default function ProfileScreen() {
|
export default function ProfileScreen() {
|
||||||
|
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>();
|
||||||
|
const { user, logout } = useAuthStore();
|
||||||
|
const [isResending, setIsResending] = useState(false);
|
||||||
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||||
const colorScheme = useColorScheme();
|
const colorScheme = useColorScheme();
|
||||||
const isDark = colorScheme === 'dark';
|
const isDark = colorScheme === 'dark';
|
||||||
const themeStyles = getThemeStyles(isDark);
|
const themeStyles = getThemeStyles(isDark);
|
||||||
|
const themeColors = isDark ? COLORS.DARK : COLORS.LIGHT;
|
||||||
|
|
||||||
|
if (!user) return null;
|
||||||
|
|
||||||
|
const displayName =
|
||||||
|
(user.user?.first_name && user.user?.last_name) ? `${user.user.first_name} ${user.user.last_name}` :
|
||||||
|
user.user?.username ? user.user.username :
|
||||||
|
user.user?.email ? user.user.email.split('@')[0] :
|
||||||
|
'User Name';
|
||||||
|
|
||||||
|
const handleResendVerification = async () => {
|
||||||
|
setIsResending(true);
|
||||||
|
const result = await authService.resendVerificationEmail();
|
||||||
|
setIsResending(false);
|
||||||
|
|
||||||
|
if (result.ok) {
|
||||||
|
Alert.alert('Email Sent', 'Please check your email (or server logs) for the verification link.');
|
||||||
|
} else {
|
||||||
|
Alert.alert('Error', result.message || 'Failed to resend verification email');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteAccount = () => {
|
||||||
|
Alert.alert(
|
||||||
|
'Delete Account',
|
||||||
|
'Are you sure you want to permanently delete your account? This action cannot be undone.',
|
||||||
|
[
|
||||||
|
{ text: 'Cancel', style: 'cancel' },
|
||||||
|
{
|
||||||
|
text: 'Delete',
|
||||||
|
style: 'destructive',
|
||||||
|
onPress: async () => {
|
||||||
|
const result = await authService.deleteAccount();
|
||||||
|
if (result.ok) {
|
||||||
|
logout();
|
||||||
|
Alert.alert('Success', 'Your account has been deleted.');
|
||||||
|
} else {
|
||||||
|
Alert.alert('Error', 'Failed to delete account.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const MenuItem = ({ icon, label, onPress, isDestructive = false }: { icon: string, label: string, onPress: () => void, isDestructive?: boolean }) => (
|
||||||
|
<TouchableOpacity
|
||||||
|
style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingVertical: 16,
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: isDark ? '#2d3748' : '#edf2f7',
|
||||||
|
}}
|
||||||
|
onPress={onPress}
|
||||||
|
>
|
||||||
|
<View style={{
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
borderRadius: 18,
|
||||||
|
backgroundColor: isDestructive ? '#fff5f5' : (isDark ? '#2d3748' : '#ebf8ff'),
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginRight: 16
|
||||||
|
}}>
|
||||||
|
<Ionicons
|
||||||
|
name={icon as any}
|
||||||
|
size={20}
|
||||||
|
color={isDestructive ? '#e53e3e' : themeColors.brand}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<Text style={{
|
||||||
|
flex: 1,
|
||||||
|
fontSize: 16,
|
||||||
|
color: isDestructive ? '#e53e3e' : themeColors.text,
|
||||||
|
fontWeight: '500'
|
||||||
|
}}>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
<Ionicons name="chevron-forward" size={20} color={isDark ? '#718096' : '#cbd5e0'} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={themeStyles.container}>
|
<ScrollView
|
||||||
<View style={commonStyles.centered}>
|
style={themeStyles.container}
|
||||||
<Text style={themeStyles.headerTitle}>Profile Screen</Text>
|
contentContainerStyle={{ paddingBottom: 40 }}
|
||||||
<Text style={themeStyles.subtitle}>User profile details will go here.</Text>
|
showsVerticalScrollIndicator={false}
|
||||||
|
>
|
||||||
|
{!user.user?.email_verified_at && (
|
||||||
|
<TouchableOpacity
|
||||||
|
style={{
|
||||||
|
backgroundColor: '#fffaf0',
|
||||||
|
padding: 12,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: '#feebc8'
|
||||||
|
}}
|
||||||
|
onPress={handleResendVerification}
|
||||||
|
disabled={isResending}
|
||||||
|
>
|
||||||
|
<View style={{ flexDirection: 'row', alignItems: 'center', flex: 1 }}>
|
||||||
|
<Ionicons name="warning-outline" size={20} color="#ed8936" />
|
||||||
|
<Text style={{ marginLeft: 10, color: '#c05621', fontSize: 14, flex: 1 }}>
|
||||||
|
Your email is not verified. Tap to resend link.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
{isResending ? (
|
||||||
|
<ActivityIndicator size="small" color="#c05621" />
|
||||||
|
) : (
|
||||||
|
<Ionicons name="arrow-forward" size={18} color="#c05621" />
|
||||||
|
)}
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Header Profile Section */}
|
||||||
|
<View style={{ alignItems: 'center', paddingTop: 40, paddingBottom: 30 }}>
|
||||||
|
<View style={{
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
borderRadius: 50,
|
||||||
|
backgroundColor: 'white',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginBottom: 16,
|
||||||
|
shadowColor: themeColors.brand,
|
||||||
|
shadowOffset: { width: 0, height: 4 },
|
||||||
|
shadowOpacity: 0.3,
|
||||||
|
shadowRadius: 8,
|
||||||
|
elevation: 6,
|
||||||
|
overflow: 'hidden', // Ensure image clips to circle
|
||||||
|
}}>
|
||||||
|
{user.user?.avatar ? (
|
||||||
|
<TouchableOpacity onPress={() => setIsModalVisible(true)} style={{ width: '100%', height: '100%' }}>
|
||||||
|
<Image
|
||||||
|
source={{ uri: user.user.avatar }}
|
||||||
|
style={{ width: '100%', height: '100%' }}
|
||||||
|
resizeMode="contain"
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
) : (
|
||||||
|
<Text style={{ fontSize: 40, fontWeight: 'bold', color: 'white' }}>
|
||||||
|
{displayName.charAt(0).toUpperCase()}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<Text style={{ fontSize: 24, fontWeight: 'bold', color: themeColors.text, marginBottom: 4 }}>
|
||||||
|
{displayName}
|
||||||
|
</Text>
|
||||||
|
<Text style={{ fontSize: 16, color: themeColors.subtitle }}>
|
||||||
|
{user.user?.email}
|
||||||
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
|
||||||
|
{/* Settings Section */}
|
||||||
|
<View style={{
|
||||||
|
backgroundColor: themeColors.card,
|
||||||
|
marginHorizontal: 20,
|
||||||
|
borderRadius: 16,
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
marginBottom: 20,
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: { width: 0, height: 2 },
|
||||||
|
shadowOpacity: 0.05,
|
||||||
|
shadowRadius: 4,
|
||||||
|
elevation: 2
|
||||||
|
}}>
|
||||||
|
<MenuItem icon="person-outline" label="Edit Profile" onPress={() => navigation.navigate('EditProfile')} />
|
||||||
|
<MenuItem icon="notifications-outline" label="Notifications" onPress={() => {}} />
|
||||||
|
<MenuItem icon="key-outline" label="API Token" onPress={() => Alert.alert('Your Token', user.token)} />
|
||||||
|
<MenuItem icon="help-circle-outline" label="Help & Support" onPress={() => {}} />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Danger Zone */}
|
||||||
|
<View style={{
|
||||||
|
backgroundColor: themeColors.card,
|
||||||
|
marginHorizontal: 20,
|
||||||
|
borderRadius: 16,
|
||||||
|
paddingHorizontal: 20,
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: { width: 0, height: 2 },
|
||||||
|
shadowOpacity: 0.05,
|
||||||
|
shadowRadius: 4,
|
||||||
|
elevation: 2
|
||||||
|
}}>
|
||||||
|
<MenuItem icon="log-out-outline" label="Sign Out" onPress={logout} />
|
||||||
|
<MenuItem icon="trash-outline" label="Delete Account" onPress={handleDeleteAccount} isDestructive />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text style={{
|
||||||
|
textAlign: 'center',
|
||||||
|
marginTop: 30,
|
||||||
|
color: themeColors.subtitle,
|
||||||
|
fontSize: 12
|
||||||
|
}}>
|
||||||
|
Version {appConfig.expo.version}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
visible={isModalVisible}
|
||||||
|
transparent={true}
|
||||||
|
animationType="fade"
|
||||||
|
onRequestClose={() => setIsModalVisible(false)}
|
||||||
|
>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.90)',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
activeOpacity={1}
|
||||||
|
onPress={() => setIsModalVisible(false)}
|
||||||
|
>
|
||||||
|
{user.user?.avatar && (
|
||||||
|
<View style={{
|
||||||
|
width: 300,
|
||||||
|
height: 300,
|
||||||
|
borderRadius: 150, // Circular container
|
||||||
|
backgroundColor: 'black',
|
||||||
|
overflow: 'hidden',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
borderWidth: 0.5,
|
||||||
|
borderColor: 'white'
|
||||||
|
}}>
|
||||||
|
<Image
|
||||||
|
source={{ uri: user.user.avatar }}
|
||||||
|
style={{ width: '100%', height: '100%' }}
|
||||||
|
resizeMode="contain"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
<TouchableOpacity
|
||||||
|
style={{ position: 'absolute', top: 50, right: 20, padding: 10 }}
|
||||||
|
onPress={() => setIsModalVisible(false)}
|
||||||
|
>
|
||||||
|
<Ionicons name="close" size={30} color="white" />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Modal>
|
||||||
|
</ScrollView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user