From 50d3d69dbd4fc3fac650117b8d9ef777b4f0e65b Mon Sep 17 00:00:00 2001 From: gibbyb Date: Mon, 10 Mar 2025 16:24:26 -0500 Subject: [PATCH] Get started on stack navigation for settings page --- app/(tabs)/settings.tsx | 46 --------- app/(tabs)/settings/_layout.tsx | 39 +++++++ app/(tabs)/settings/index.tsx | 91 +++++++++++++++++ app/(tabs)/settings/profile.tsx | 173 ++++++++++++++++++++++++++++++++ package-lock.json | 22 ++++ package.json | 3 +- 6 files changed, 327 insertions(+), 47 deletions(-) delete mode 100644 app/(tabs)/settings.tsx create mode 100644 app/(tabs)/settings/_layout.tsx create mode 100644 app/(tabs)/settings/index.tsx create mode 100644 app/(tabs)/settings/profile.tsx diff --git a/app/(tabs)/settings.tsx b/app/(tabs)/settings.tsx deleted file mode 100644 index d3da691..0000000 --- a/app/(tabs)/settings.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { StyleSheet, Image, Platform } from 'react-native'; -import ParallaxScrollView from '@/components/default/ParallaxScrollView'; -import { ThemedText, ThemedView } from '@/components/theme'; -import { IconSymbol } from '@/components/ui/IconSymbol'; -import Logout_Button from '@/components/auth/Logout_Button'; - -const TabTwoScreen = () => { - return ( - - } - headerTitle={ - - Settings - - } - > - - - ); -}; -export default TabTwoScreen; - -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', - }, - titleContainer: { - flexDirection: 'row', - gap: 8, - }, -}); diff --git a/app/(tabs)/settings/_layout.tsx b/app/(tabs)/settings/_layout.tsx new file mode 100644 index 0000000..c828882 --- /dev/null +++ b/app/(tabs)/settings/_layout.tsx @@ -0,0 +1,39 @@ +import { Stack } from 'expo-router'; +import { useColorScheme } from '@/hooks/useColorScheme'; +import { Colors } from '@/constants/Colors'; + +export default function SettingsLayout() { + const scheme = useColorScheme() ?? 'dark'; + + return ( + + + + {/* Add more screens as needed */} + + ); +} diff --git a/app/(tabs)/settings/index.tsx b/app/(tabs)/settings/index.tsx new file mode 100644 index 0000000..1f7dd11 --- /dev/null +++ b/app/(tabs)/settings/index.tsx @@ -0,0 +1,91 @@ +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'; +import Logout_Button from '@/components/auth/Logout_Button'; + +const SettingsScreen = () => { + const router = useRouter(); + + return ( + + } + headerTitle={ + + Settings + + } + > + + router.push('/settings/profile')} + > + + + Profile + Name, photo, email + + + + + + + + + + + ); +}; + +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: 16, + 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/profile.tsx b/app/(tabs)/settings/profile.tsx new file mode 100644 index 0000000..dee08eb --- /dev/null +++ b/app/(tabs)/settings/profile.tsx @@ -0,0 +1,173 @@ +import React, { useState, useEffect } from 'react'; +import { StyleSheet, TouchableOpacity, Image, Alert, ActivityIndicator } from 'react-native'; +import * as ImagePicker from 'expo-image-picker'; +import { supabase } from '@/lib/supabase'; +import { ThemedView, ThemedText, ThemedTextInput } from '@/components/theme'; +import { IconSymbol } from '@/components/ui/IconSymbol'; + +export default function ProfileScreen() { + const [loading, setLoading] = useState(false); + const [fullName, setFullName] = useState(''); + const [email, setEmail] = useState(''); + const [avatar, setAvatar] = useState(null); + + useEffect(() => { + fetchUserProfile(); + }, []); + + const fetchUserProfile = async () => { + setLoading(true); + try { + const { data: { user } } = await supabase.auth.getUser(); + + if (user) { + const { data, error } = await supabase + .from('profiles') + .select('*') + .eq('id', user.id) + .single(); + + if (data) { + setFullName(data.full_name || ''); + setEmail(data.email || ''); + setAvatar(data.avatar_url || null); + } + } + } catch (error) { + console.error('Error fetching profile:', error); + } finally { + setLoading(false); + } + }; + + const updateProfile = async () => { + setLoading(true); + try { + const { data: { user } } = await supabase.auth.getUser(); + + if (!user) throw new Error('User not found'); + + const updates = { + id: user.id, + full_name: fullName, + email, + 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 updating profile', error.message); + } finally { + setLoading(false); + } + }; + + // Add image picking functionality here (similar to previous example) + + return ( + + + {avatar ? ( + + ) : ( + + + + )} + Change Photo + + + + Full Name + + + Email + + + + + {loading ? ( + + ) : ( + Save Changes + )} + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + padding: 16, + }, + avatarContainer: { + alignItems: 'center', + marginTop: 20, + marginBottom: 30, + }, + avatar: { + width: 120, + height: 120, + borderRadius: 60, + }, + avatarPlaceholder: { + width: 120, + height: 120, + borderRadius: 60, + backgroundColor: '#E1E1E1', + justifyContent: 'center', + alignItems: 'center', + }, + changePhotoText: { + marginTop: 8, + color: '#007AFF', + fontSize: 16, + }, + formSection: { + marginBottom: 30, + }, + label: { + marginBottom: 8, + fontSize: 16, + }, + input: { + fontSize: 16, + paddingVertical: 12, + paddingHorizontal: 10, + borderRadius: 8, + marginBottom: 20, + }, + saveButton: { + backgroundColor: '#007AFF', + paddingVertical: 14, + borderRadius: 8, + alignItems: 'center', + }, + saveButtonText: { + color: '#fff', + fontSize: 16, + }, +}); diff --git a/package-lock.json b/package-lock.json index 9730a1b..a3cd810 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "expo-font": "~13.0.3", "expo-haptics": "~14.0.1", "expo-image": "~2.0.6", + "expo-image-picker": "~16.0.6", "expo-insights": "~0.8.2", "expo-linking": "~7.0.5", "expo-location": "~18.0.7", @@ -8457,6 +8458,27 @@ } } }, + "node_modules/expo-image-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-5.0.0.tgz", + "integrity": "sha512-Eg+5FHtyzv3Jjw9dHwu2pWy4xjf8fu3V0Asyy42kO+t/FbvW/vjUixpTjPtgKQLQh+2/9Nk4JjFDV6FwCnF2ZA==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-image-picker": { + "version": "16.0.6", + "resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-16.0.6.tgz", + "integrity": "sha512-HN4xZirFjsFDIsWFb12AZh19fRzuvZjj2ll17cGr19VNRP06S/VPQU3Tdccn5vwUzQhOBlLu704CnNm278boiQ==", + "license": "MIT", + "dependencies": { + "expo-image-loader": "~5.0.0" + }, + "peerDependencies": { + "expo": "*" + } + }, "node_modules/expo-insights": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/expo-insights/-/expo-insights-0.8.2.tgz", diff --git a/package.json b/package.json index 9454b3b..d7b3762 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,8 @@ "react-native-svg": "15.8.0", "react-native-svg-transformer": "^1.5.0", "react-native-web": "~0.19.13", - "react-native-webview": "13.12.5" + "react-native-webview": "13.12.5", + "expo-image-picker": "~16.0.6" }, "devDependencies": { "@babel/core": "^7.25.2",