import React, { useState, useEffect, useMemo } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, ScrollView, Image, Alert, TextInput, Keyboard, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { Ionicons } from '@expo/vector-icons'; import * as ImagePicker from 'expo-image-picker'; import { useRouter } from 'expo-router'; import { useApp } from '../../context/AppContext'; import { useColors } from '../../constants/Colors'; import { ThemeBackdrop } from '../../components/ThemeBackdrop'; import { Language } from '../../types'; const DAY_MS = 24 * 60 * 60 * 1000; const getDaysUntilWatering = (lastWatered: string, intervalDays: number): number => { const lastWateredTs = new Date(lastWatered).getTime(); if (Number.isNaN(lastWateredTs)) return 0; const dueTs = lastWateredTs + (intervalDays * DAY_MS); const remainingMs = dueTs - Date.now(); if (remainingMs <= 0) return 0; return Math.ceil(remainingMs / DAY_MS); }; const getProfileCopy = (language: Language) => { if (language === 'de') { return { overviewLabel: 'Überblick', statPlants: 'Pflanzen', statDueToday: 'Heute fällig', statReminders: 'Erinnerungen an', account: 'Account', changePhoto: 'Foto ändern', removePhoto: 'Foto entfernen', nameLabel: 'Name', namePlaceholder: 'Dein Name', saveName: 'Name speichern', photoErrorTitle: 'Fehler', photoErrorMessage: 'Profilfoto konnte nicht geladen werden.', nameErrorTitle: 'Name fehlt', nameErrorMessage: 'Bitte gib einen Namen ein.', menuSettings: 'Einstellungen', menuBilling: 'Abo & Credits', menuData: 'Daten & Datenschutz', logout: 'Abmelden', logoutConfirmTitle: 'Abmelden?', logoutConfirmMessage: 'Möchtest du dich wirklich abmelden?', logoutConfirmBtn: 'Abmelden', }; } if (language === 'es') { return { overviewLabel: 'Resumen', statPlants: 'Plantas', statDueToday: 'Vencen hoy', statReminders: 'Recordatorios', account: 'Cuenta', changePhoto: 'Cambiar foto', removePhoto: 'Eliminar foto', nameLabel: 'Nombre', namePlaceholder: 'Tu nombre', saveName: 'Guardar nombre', photoErrorTitle: 'Error', photoErrorMessage: 'No se pudo cargar la foto.', nameErrorTitle: 'Falta nombre', nameErrorMessage: 'Por favor ingresa un nombre.', menuSettings: 'Ajustes', menuBilling: 'Suscripción y Créditos', menuData: 'Datos y Privacidad', logout: 'Cerrar sesión', logoutConfirmTitle: '¿Cerrar sesión?', logoutConfirmMessage: '¿Realmente quieres cerrar sesión?', logoutConfirmBtn: 'Cerrar sesión', }; } return { overviewLabel: 'Overview', statPlants: 'Plants', statDueToday: 'Due today', statReminders: 'Reminders on', account: 'Account', changePhoto: 'Change photo', removePhoto: 'Remove photo', nameLabel: 'Name', namePlaceholder: 'Your name', saveName: 'Save name', photoErrorTitle: 'Error', photoErrorMessage: 'Could not load profile photo.', nameErrorTitle: 'Name missing', nameErrorMessage: 'Please enter a name.', menuSettings: 'Preferences', menuBilling: 'Billing & Credits', menuData: 'Data & Privacy', logout: 'Sign Out', logoutConfirmTitle: 'Sign out?', logoutConfirmMessage: 'Do you really want to sign out?', logoutConfirmBtn: 'Sign Out', }; }; export default function ProfileScreen() { const { plants, language, t, isDarkMode, colorPalette, profileImageUri, setProfileImage, profileName, setProfileName, signOut, } = useApp(); const router = useRouter(); const colors = useColors(isDarkMode, colorPalette); const [isUpdatingImage, setIsUpdatingImage] = useState(false); const [isSavingName, setIsSavingName] = useState(false); const [draftName, setDraftName] = useState(profileName); const copy = useMemo(() => getProfileCopy(language), [language]); useEffect(() => { setDraftName(profileName); }, [profileName]); const normalizedDraftName = draftName.trim(); const canSaveName = normalizedDraftName.length > 0 && normalizedDraftName !== profileName; const dueTodayCount = useMemo( () => plants.filter(plant => getDaysUntilWatering(plant.lastWatered, plant.careInfo.waterIntervalDays) === 0).length, [plants] ); const remindersEnabledCount = useMemo( () => plants.filter(plant => Boolean(plant.notificationsEnabled)).length, [plants] ); const handlePickProfileImage = async () => { if (isUpdatingImage) return; setIsUpdatingImage(true); try { const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], quality: 0.85, base64: true, }); if (!result.canceled && result.assets[0]) { const asset = result.assets[0]; const imageUri = asset.base64 ? `data:image/jpeg;base64,${asset.base64}` : asset.uri; await setProfileImage(imageUri); } } catch (error) { console.error('Failed to pick profile image', error); Alert.alert(copy.photoErrorTitle, copy.photoErrorMessage); } finally { setIsUpdatingImage(false); } }; const handleRemovePhoto = async () => { await setProfileImage(null); }; const handleSaveName = async () => { if (!normalizedDraftName) { Alert.alert(copy.nameErrorTitle, copy.nameErrorMessage); return; } if (!canSaveName) { Keyboard.dismiss(); return; } setIsSavingName(true); try { await setProfileName(normalizedDraftName); Keyboard.dismiss(); } finally { setIsSavingName(false); } }; const menuItems = [ { label: copy.menuSettings, icon: 'settings-outline', route: '/profile/preferences' as any }, { label: copy.menuBilling, icon: 'card-outline', route: '/profile/billing' as any }, { label: copy.menuData, icon: 'shield-checkmark-outline', route: '/profile/data' as any }, ]; return ( {t.tabProfile} {copy.overviewLabel} {[ { label: copy.statPlants, value: plants.length.toString() }, { label: copy.statDueToday, value: dueTodayCount.toString() }, { label: copy.statReminders, value: remindersEnabledCount.toString() }, ].map((item) => ( {item.value} {item.label} ))} {copy.account} {profileImageUri ? ( ) : ( )} {profileName} {plants.length} {copy.statPlants} {isUpdatingImage ? '...' : copy.changePhoto} {profileImageUri ? ( {copy.removePhoto} ) : null} {copy.nameLabel} {isSavingName ? '...' : copy.saveName} {menuItems.map((item, idx) => ( router.push(item.route)} activeOpacity={0.7} > {item.label} ))} {/* Logout */} { Alert.alert(copy.logoutConfirmTitle, copy.logoutConfirmMessage, [ { text: t.cancel, style: 'cancel' }, { text: copy.logoutConfirmBtn, style: 'destructive', onPress: async () => { await signOut(); router.replace('/auth/login'); }, }, ]); }} > {copy.logout} ); } const styles = StyleSheet.create({ container: { flex: 1, paddingHorizontal: 20, }, scrollContent: { paddingBottom: 20, }, title: { marginTop: 14, marginBottom: 14, fontSize: 28, fontWeight: '700', }, card: { borderWidth: 1, borderRadius: 18, padding: 14, marginBottom: 12, gap: 10, }, accountCard: { marginBottom: 14, }, logoutBtn: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 8, borderRadius: 14, borderWidth: 1, paddingVertical: 14, marginBottom: 12, }, logoutText: { fontSize: 15, fontWeight: '600', }, cardTitle: { fontSize: 15, fontWeight: '700', }, statsRow: { flexDirection: 'row', gap: 8, }, statCard: { flex: 1, borderWidth: 1, borderRadius: 12, paddingVertical: 12, paddingHorizontal: 8, alignItems: 'center', justifyContent: 'center', gap: 2, }, statValue: { fontSize: 22, lineHeight: 24, fontWeight: '700', }, statLabel: { fontSize: 11, fontWeight: '600', textAlign: 'center', }, accountRow: { flexDirection: 'row', alignItems: 'center', gap: 12, }, accountMeta: { flex: 1, gap: 3, }, currentName: { fontSize: 18, fontWeight: '700', }, plantsCount: { fontSize: 13, fontWeight: '600', }, avatarFrame: { width: 74, height: 74, borderRadius: 22, alignItems: 'center', justifyContent: 'center', overflow: 'hidden', }, avatarImage: { width: '100%', height: '100%', }, photoButtons: { flexDirection: 'row', gap: 8, }, photoActionBtn: { borderRadius: 10, paddingVertical: 10, paddingHorizontal: 12, }, photoSecondaryBtn: { borderWidth: 1, }, photoActionText: { fontSize: 12, fontWeight: '700', }, photoSecondaryText: { fontSize: 12, fontWeight: '700', }, fieldLabel: { marginTop: 2, fontSize: 12, fontWeight: '600', }, nameRow: { flexDirection: 'row', gap: 8, alignItems: 'center', }, nameInput: { flex: 1, borderWidth: 1, borderRadius: 12, paddingHorizontal: 12, paddingVertical: 10, fontSize: 14, fontWeight: '500', }, saveNameBtn: { borderWidth: 1, borderRadius: 12, paddingHorizontal: 12, paddingVertical: 10, }, saveNameText: { fontSize: 12, fontWeight: '700', }, menuItem: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 16, paddingHorizontal: 14, }, menuItemLeft: { flexDirection: 'row', alignItems: 'center', gap: 12, }, menuItemText: { fontSize: 16, fontWeight: '500', } });