diff --git a/app/(tabs)/settings/_index.tsx b/app/(tabs)/settings/_index.tsx
new file mode 100644
index 0000000..d12e21a
--- /dev/null
+++ b/app/(tabs)/settings/_index.tsx
@@ -0,0 +1,89 @@
+import { StyleSheet, TouchableOpacity } from 'react-native';
+import { useRouter } from 'expo-router';
+import ParallaxScrollView from '@/components/default/ParallaxScrollView';
+import { ThemedText, ThemedTextButton, ThemedView } from '@/components/theme';
+import { IconSymbol } from '@/components/ui/IconSymbol';
+
+const SettingsScreen = () => {
+ const router = useRouter();
+
+ return (
+
+ }
+ headerTitle={
+
+ Settings
+
+ }
+ >
+
+ router.push('/settings/profile')}
+ >
+
+
+ Profile Settings
+ Update profile information or sign out.
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default SettingsScreen;
+
+const styles = StyleSheet.create({
+ headerImage: {
+ color: '#808080',
+ bottom: 6,
+ left: 38,
+ position: 'absolute',
+ },
+ headerTitle: {
+ position: 'absolute',
+ bottom: 20,
+ left: 16,
+ right: 0,
+ textAlign: 'center',
+ fontSize: 48,
+ lineHeight: 64,
+ fontWeight: 'bold',
+ },
+ section: {
+ marginVertical: 8,
+ borderRadius: 10,
+ overflow: 'hidden',
+ },
+ settingItem: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ padding: 16,
+ backgroundColor: 'rgba(200, 200, 200, 0.1)',
+ marginBottom: 1,
+ },
+ icon: {
+ marginRight: 16,
+ },
+ settingContent: {
+ backgroundColor: 'transparent',
+ flex: 1,
+ },
+ settingTitle: {
+ fontSize: 17,
+ fontWeight: '500',
+ },
+ settingSubtitle: {
+ fontSize: 14,
+ opacity: 0.6,
+ marginTop: 4,
+ },
+});
diff --git a/app/(tabs)/settings/index.tsx b/app/(tabs)/settings/index.tsx
index d12e21a..b0e1a92 100644
--- a/app/(tabs)/settings/index.tsx
+++ b/app/(tabs)/settings/index.tsx
@@ -1,11 +1,114 @@
-import { StyleSheet, TouchableOpacity } from 'react-native';
-import { useRouter } from 'expo-router';
+import React, { useState, useEffect } from 'react';
+import {
+ StyleSheet,
+ Alert,
+ ActivityIndicator,
+ SafeAreaView,
+ 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';
import ParallaxScrollView from '@/components/default/ParallaxScrollView';
-import { ThemedText, ThemedTextButton, ThemedView } from '@/components/theme';
import { IconSymbol } from '@/components/ui/IconSymbol';
const SettingsScreen = () => {
- const router = useRouter();
+ 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 (
+
+
+
+ );
+ }
return (
{
}
>
-
- router.push('/settings/profile')}
- >
-
-
- Profile Settings
- Update profile information or sign out.
+
+
+
+ {profile.provider && (
+
+ Signed in with {profile.provider.charAt(0).toUpperCase() + profile.provider.slice(1)}
+
+ )}
+
+
+ Name
+ setProfile(prev => ({ ...prev, full_name: text }))}
+ placeholder="Enter your full name"
+ style={styles.input}
+ editable={!updating}
+ autoCapitalize='words'
+ textContentType='name'
+ maxLength={50}
+ onSubmitEditing={updateProfile}
+ />
-
-
-
-
-
-
+
+
+
+
+
);
};
-
export default SettingsScreen;
const styles = StyleSheet.create({
@@ -58,32 +190,51 @@ const styles = StyleSheet.create({
lineHeight: 64,
fontWeight: 'bold',
},
- section: {
- marginVertical: 8,
- borderRadius: 10,
- overflow: 'hidden',
+ scrollContainer: {
+ flexGrow: 1,
},
- settingItem: {
- flexDirection: 'row',
- alignItems: 'center',
- padding: 16,
- backgroundColor: 'rgba(200, 200, 200, 0.1)',
- marginBottom: 1,
- },
- icon: {
- marginRight: 16,
- },
- settingContent: {
- backgroundColor: 'transparent',
+ container: {
flex: 1,
+ padding: 16,
+ alignItems: 'center',
},
- settingTitle: {
- fontSize: 17,
+ loadingContainer: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ formSection: {
+ marginBottom: 20,
+ },
+ label: {
+ marginBottom: 8,
+ fontSize: 16,
fontWeight: '500',
},
- settingSubtitle: {
- fontSize: 14,
- opacity: 0.6,
- marginTop: 4,
+ input: {
+ fontSize: 16,
+ paddingVertical: 12,
+ paddingHorizontal: 10,
+ borderRadius: 8,
+ marginBottom: 20,
+ width: '100%',
},
+ disabledInput: {
+ opacity: 0.7,
+ },
+ saveButton: {
+ borderRadius: 8,
+ alignItems: 'center',
+ marginBottom: 10,
+ },
+ logoutButton: {
+ marginTop: 30,
+ borderRadius: 8,
+ alignItems: 'center',
+ },
+ providerText: {
+ marginBottom: 20,
+ fontSize: 14,
+ opacity: 0.7,
+ }
});
diff --git a/app/(tabs)/settings/profile.tsx b/app/(tabs)/settings/profile.tsx
index 8c25eb7..1e1ccab 100644
--- a/app/(tabs)/settings/profile.tsx
+++ b/app/(tabs)/settings/profile.tsx
@@ -1,5 +1,11 @@
import React, { useState, useEffect } from 'react';
-import { StyleSheet, Alert, ActivityIndicator, ScrollView } from 'react-native';
+import {
+ StyleSheet,
+ Alert,
+ ActivityIndicator,
+ SafeAreaView,
+ ScrollView,
+} from 'react-native';
import { supabase } from '@/lib/supabase';
import { ThemedView, ThemedText, ThemedTextButton, ThemedTextInput } from '@/components/theme';
import ProfileAvatar from '@/components/auth/Profile_Avatar';
@@ -103,7 +109,10 @@ const ProfileScreen = () => {
}
return (
-
+
{
Signed in with {profile.provider.charAt(0).toUpperCase() + profile.provider.slice(1)}
)}
-
-
- Name
- setProfile(prev => ({ ...prev, full_name: text }))}
- placeholder="Enter your full name"
- style={styles.input}
- editable={!updating}
- />
-
+
+
+ Name
+ setProfile(prev => ({ ...prev, full_name: text }))}
+ placeholder="Enter your full name"
+ style={styles.input}
+ editable={!updating}
+ autoCapitalize='words'
+ textContentType='name'
+ maxLength={50}
+ returnKeyType='done'
+ />
+
+