2025-03-17 09:35:27 -05:00

225 lines
5.5 KiB
TypeScript

import React, { useState, useEffect, useRef } from 'react';
import {
StyleSheet,
Alert,
ActivityIndicator,
ScrollView,
} from 'react-native';
import { supabase } from '@/lib/supabase';
import { ThemedView, ThemedText, ThemedTextButton, ThemedTextInput } from '@/components/theme';
import ProfileAvatar from '@/components/auth/Profile_Avatar';
import LogoutButton from '@/components/auth/Logout_Button';
import { useFocusEffect } from '@react-navigation/native';
const ProfileScreen = () => {
const [loading, setLoading] = useState(true);
const [updating, setUpdating] = useState(false);
const [profile, setProfile] = useState({
full_name: '',
email: '',
avatar_url: null,
provider: ''
});
// Fetch profile when screen comes into focus
useFocusEffect(
React.useCallback(() => {
fetchUserProfile();
}, [])
);
const fetchUserProfile = async () => {
setLoading(true);
try {
const { data: { user } } = await supabase.auth.getUser();
if (!user) {
throw new Error('Not authenticated');
}
const { data, error } = await supabase
.from('profiles')
.select('*')
.eq('id', user.id)
.single();
if (error) throw error;
if (data) {
setProfile({
full_name: data.full_name || '',
email: data.email || '',
avatar_url: data.avatar_url,
provider: data.provider || ''
});
}
} catch (error) {
console.error('Error fetching profile:', error);
Alert.alert('Error', 'Failed to load profile information');
} finally {
setLoading(false);
}
};
const updateProfile = async () => {
setUpdating(true);
try {
const { data: { user } } = await supabase.auth.getUser();
if (!user) throw new Error('Not authenticated');
// Validate input
if (!profile.full_name.trim()) {
Alert.alert('Error', 'Please enter your full name');
return;
}
const updates = {
id: user.id,
full_name: profile.full_name.trim(),
updated_at: new Date(),
};
const { error } = await supabase
.from('profiles')
.upsert(updates);
if (error) throw error;
Alert.alert('Success', 'Profile updated successfully!');
} catch (error) {
Alert.alert('Error', error instanceof Error ? error.message : 'Failed to update profile');
} finally {
setUpdating(false);
}
};
const handleAvatarUpload = () => {
// Refresh profile data after avatar upload
fetchUserProfile();
};
if (loading) {
return (
<ThemedView style={styles.loadingContainer}>
<ActivityIndicator size="large" />
</ThemedView>
);
}
return (
<ScrollView
contentContainerStyle={styles.scrollContainer}
keyboardShouldPersistTaps='never'
>
<ThemedView style={styles.container}>
<ThemedView style={styles.avatarContainer}>
<ProfileAvatar
url={profile.avatar_url}
size={120}
onUpload={handleAvatarUpload}
disabled={updating}
/>
</ThemedView>
{profile.provider && (
<ThemedText style={styles.providerText}>
Signed in with {profile.provider.charAt(0).toUpperCase() + profile.provider.slice(1)}
</ThemedText>
)}
<ThemedView style={styles.formSection}>
<ThemedText type='title' style={styles.label}>Name</ThemedText>
<ThemedTextInput
value={profile.full_name}
onChangeText={(text) => setProfile(prev => ({ ...prev, full_name: text }))}
placeholder="Enter your full name"
style={styles.input}
fontSize={20}
height={55}
editable={!updating}
autoCapitalize='words'
textContentType='name'
maxLength={50}
returnKeyType='done'
secureTextEntry={false}
/>
</ThemedView>
<ThemedTextButton
text={updating ? 'Saving...' : 'Save Changes'}
onPress={updateProfile}
disabled={updating || !profile.full_name.trim()}
fontSize={18}
fontWeight='semibold'
width='90%'
style={styles.saveButton}
/>
<LogoutButton
fontSize={18}
fontWeight='semibold'
width='90%'
style={styles.logoutButton}
/>
</ThemedView>
</ScrollView>
);
};
export default ProfileScreen;
const styles = StyleSheet.create({
scrollContainer: {
flexGrow: 1,
},
container: {
flex: 1,
padding: 16,
alignItems: 'center',
},
avatarContainer: {
marginVertical: 20,
},
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
formSection: {
marginBottom: 20,
width: '100%',
alignItems: 'center',
},
label: {
marginBottom: 8,
fontSize: 18,
fontWeight: '500',
alignSelf: 'flex-start',
marginLeft: '5%',
},
input: {
paddingVertical: 12,
paddingHorizontal: 10,
borderRadius: 8,
marginBottom: 20,
},
disabledInput: {
opacity: 0.7,
},
saveButton: {
borderRadius: 8,
marginTop: 20,
marginBottom: 10,
alignItems: 'center',
},
logoutButton: {
marginTop: 10,
borderRadius: 8,
alignItems: 'center',
},
providerText: {
marginBottom: 20,
fontSize: 14,
opacity: 0.7,
}
});