import React, { useState, useEffect } from 'react'; import { View, Text, StyleSheet, ScrollView, TextInput, TouchableOpacity, Alert, KeyboardAvoidingView, Platform, Image, ActivityIndicator, } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { SafeAreaView } from 'react-native-safe-area-context'; import { router } from 'expo-router'; import * as ImagePicker from 'expo-image-picker'; import { useAuth } from '@/contexts/AuthContext'; import { api } from '@/services/api'; import { PageHeader } from '@/components/PageHeader'; import { AppColors, BorderRadius, FontSizes, Spacing, FontWeights, Shadows, } from '@/constants/theme'; export default function EditProfileScreen() { const { user, updateUser } = useAuth(); const [displayName, setDisplayName] = useState(''); const [phone, setPhone] = useState(''); const [isLoading, setIsLoading] = useState(true); const [isSaving, setIsSaving] = useState(false); const [avatarUri, setAvatarUri] = useState(null); // Load profile from API useEffect(() => { const loadProfile = async () => { try { const response = await api.getProfile(); if (response.ok && response.data) { // /auth/me returns { user: {...}, beneficiaries: [...] } const userData = response.data.user || response.data; const { firstName, lastName, phone: userPhone } = userData; // Combine first and last name for display const fullName = [firstName, lastName].filter(Boolean).join(' '); setDisplayName(fullName || ''); setPhone(userPhone || ''); } } catch (err) { console.error('Failed to load profile:', err); } finally { setIsLoading(false); } }; loadProfile(); }, []); const handleSave = async () => { if (!displayName.trim()) { Alert.alert('Error', 'Display name is required'); return; } setIsSaving(true); try { // Parse display name into first and last name const nameParts = displayName.trim().split(' '); const firstName = nameParts[0] || ''; const lastName = nameParts.slice(1).join(' ') || ''; console.log('[EditProfile] Saving:', { firstName, lastName, phone }); // Save to server API const response = await api.updateProfile({ firstName, lastName, phone: phone || undefined, }); console.log('[EditProfile] Response:', response); if (response.ok) { // Update user in AuthContext (will refetch from API) if (updateUser) { updateUser({ user_name: displayName.trim(), firstName, lastName, phone, }); } Alert.alert( 'Profile Updated', 'Your profile has been updated successfully.', [{ text: 'OK', onPress: () => router.back() }] ); } else { Alert.alert('Error', response.error?.message || 'Failed to save profile'); } } catch (error) { console.error('Failed to save profile:', error); Alert.alert('Error', 'Failed to save profile. Please try again.'); } setIsSaving(false); }; const handleChangePhoto = async () => { const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(); if (status !== 'granted') { Alert.alert('Permission needed', 'Please allow access to your photo library to change avatar.'); return; } const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], allowsEditing: true, aspect: [1, 1], quality: 0.5, }); if (!result.canceled && result.assets[0]) { const uri = result.assets[0].uri; setAvatarUri(uri); // TODO: Upload avatar to server when endpoint is available } }; const userInitial = displayName?.charAt(0).toUpperCase() || user?.email?.charAt(0).toUpperCase() || 'U'; if (isLoading) { return ( Loading profile... ); } return ( {/* Avatar Section */} {avatarUri ? ( ) : ( {userInitial} )} Tap to change photo {/* Form */} Display Name * Email Address {user?.email || 'Not set'} Email cannot be changed Phone Number For emergency contact and SMS alerts {/* Save Button */} {isSaving ? ( Saving... ) : ( <> Save Changes )} ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: AppColors.background, }, keyboardView: { flex: 1, }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, loadingText: { marginTop: Spacing.md, fontSize: FontSizes.base, color: AppColors.textSecondary, }, avatarSection: { alignItems: 'center', paddingVertical: Spacing.xl, backgroundColor: AppColors.surface, marginBottom: Spacing.md, }, avatarWrapper: { position: 'relative', }, avatarContainer: { width: 100, height: 100, borderRadius: 50, backgroundColor: AppColors.primary, justifyContent: 'center', alignItems: 'center', }, avatarImage: { width: 100, height: 100, borderRadius: 50, }, avatarText: { fontSize: 40, fontWeight: FontWeights.bold, color: AppColors.white, }, changePhotoButton: { position: 'absolute', bottom: 0, right: 0, width: 32, height: 32, borderRadius: 16, backgroundColor: AppColors.primary, justifyContent: 'center', alignItems: 'center', borderWidth: 3, borderColor: AppColors.surface, }, changePhotoText: { marginTop: Spacing.sm, fontSize: FontSizes.sm, color: AppColors.textMuted, }, form: { padding: Spacing.lg, }, inputGroup: { marginBottom: Spacing.lg, }, label: { fontSize: FontSizes.sm, fontWeight: FontWeights.medium, color: AppColors.textSecondary, marginBottom: Spacing.xs, marginLeft: Spacing.xs, }, inputContainer: { flexDirection: 'row', alignItems: 'center', backgroundColor: AppColors.surface, borderRadius: BorderRadius.lg, paddingHorizontal: Spacing.md, paddingVertical: Spacing.md, borderWidth: 1.5, borderColor: AppColors.borderLight, gap: Spacing.sm, ...Shadows.xs, }, input: { flex: 1, fontSize: FontSizes.base, color: AppColors.textPrimary, }, disabledInput: { backgroundColor: AppColors.surfaceSecondary, borderColor: AppColors.border, }, disabledText: { flex: 1, fontSize: FontSizes.base, color: AppColors.textSecondary, }, lockBadge: { width: 24, height: 24, borderRadius: 12, backgroundColor: AppColors.border, justifyContent: 'center', alignItems: 'center', }, hint: { fontSize: FontSizes.xs, color: AppColors.textMuted, marginTop: Spacing.xs, marginLeft: Spacing.xs, }, footer: { padding: Spacing.lg, backgroundColor: AppColors.surface, borderTopWidth: 1, borderTopColor: AppColors.border, }, saveButton: { flexDirection: 'row', backgroundColor: AppColors.primary, borderRadius: BorderRadius.lg, paddingVertical: Spacing.md, alignItems: 'center', justifyContent: 'center', gap: Spacing.xs, ...Shadows.primary, }, saveButtonDisabled: { opacity: 0.6, }, saveButtonText: { fontSize: FontSizes.base, fontWeight: FontWeights.semibold, color: AppColors.white, }, });