Greenlens/app/profile/data.tsx

227 lines
9.1 KiB
TypeScript

import React from 'react';
import { View, Text, TouchableOpacity, ScrollView, StyleSheet, Share, Alert } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { Ionicons } from '@expo/vector-icons';
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 getDataCopy = (language: Language) => {
if (language === 'de') {
return {
title: 'Daten & Datenschutz',
exportData: 'Daten exportieren',
exportHint: 'Teilt deine Sammlung als JSON.',
clearHistory: 'Lexikon-Verlauf loeschen',
clearHistoryHint: 'Entfernt alle letzten Suchbegriffe.',
clearHistoryDoneTitle: 'Verlauf geloescht',
clearHistoryDoneMessage: 'Der Suchverlauf wurde entfernt.',
logout: 'Abmelden',
logoutHint: 'Zurueck zum Onboarding und Profil zuruecksetzen.',
logoutConfirmTitle: 'Abmelden?',
logoutConfirmMessage: 'Du wirst auf den Startbildschirm zurueckgesetzt.',
deleteAccount: 'Konto unwiderruflich löschen',
deleteAccountHint: 'Löscht alle deine Daten, Pflanzen und Abos permanent.',
deleteConfirmTitle: 'Konto wirklich löschen?',
deleteConfirmMessage: 'Achtung: Dieser Schritt kann nicht rückgängig gemacht werden. Alle deine Pflanzen, Scans und Credits gehen sofort verloren.',
deleteActionBtn: 'Ja, dauerhaft löschen',
genericErrorTitle: 'Fehler',
genericErrorMessage: 'Aktion konnte nicht abgeschlossen werden.',
};
}
if (language === 'es') {
return {
title: 'Datos y Privacidad',
exportData: 'Exportar Datos',
exportHint: 'Comparte tu coleccion como JSON.',
clearHistory: 'Borrar historial',
clearHistoryHint: 'Elimina las busquedas recientes.',
clearHistoryDoneTitle: 'Historial borrado',
clearHistoryDoneMessage: 'El historial de busqueda ha sido eliminado.',
logout: 'Cerrar sesion',
logoutHint: 'Volver a la pantalla de inicio y reiniciar perfil.',
logoutConfirmTitle: 'Cerrar sesion?',
logoutConfirmMessage: 'Seras enviado a la pantalla de inicio.',
deleteAccount: 'Eliminar cuenta permanentemente',
deleteAccountHint: 'Elimina todos tus datos, plantas y suscripciones.',
deleteConfirmTitle: '¿Seguro que quieres eliminar tu cuenta?',
deleteConfirmMessage: 'Atención: Este paso no se puede deshacer. Todas tus plantas, escaneos y créditos se perderán inmediatamente.',
deleteActionBtn: 'Sí, eliminar permanentemente',
genericErrorTitle: 'Error',
genericErrorMessage: 'La accion no pudo ser completada.',
};
}
return {
title: 'Data & Privacy',
exportData: 'Export Data',
exportHint: 'Share your collection as JSON.',
clearHistory: 'Clear Search History',
clearHistoryHint: 'Removes recent search queries.',
clearHistoryDoneTitle: 'History Cleared',
clearHistoryDoneMessage: 'Search history has been removed.',
logout: 'Log Out',
logoutHint: 'Return to onboarding and reset profile.',
logoutConfirmTitle: 'Log Out?',
logoutConfirmMessage: 'You will be returned to the start screen.',
deleteAccount: 'Delete Account Permanently',
deleteAccountHint: 'Permanently deletes all your data, plants, and subscriptions.',
deleteConfirmTitle: 'Are you sure?',
deleteConfirmMessage: 'Warning: This cannot be undone. All your plants, scans, and credits will be lost immediately.',
deleteActionBtn: 'Yes, delete permanently',
genericErrorTitle: 'Error',
genericErrorMessage: 'Action could not be completed.',
};
};
export default function DataScreen() {
const router = useRouter();
const { isDarkMode, language, plants, appearanceMode, colorPalette, clearLexiconSearchHistory, signOut } = useApp();
const colors = useColors(isDarkMode, colorPalette);
const copy = getDataCopy(language);
const handleExportData = async () => {
try {
const dataStr = JSON.stringify(plants, null, 2);
await Share.share({
message: dataStr,
title: 'GreenLens_Export.json',
});
} catch {
Alert.alert(copy.genericErrorTitle, copy.genericErrorMessage);
}
};
const handleClearHistory = () => {
clearLexiconSearchHistory();
Alert.alert(copy.clearHistoryDoneTitle, copy.clearHistoryDoneMessage);
};
const handleLogout = () => {
Alert.alert(copy.logoutConfirmTitle, copy.logoutConfirmMessage, [
{ text: 'Cancel', style: 'cancel' },
{
text: copy.logout,
style: 'destructive',
onPress: async () => {
await signOut();
router.replace('/auth/login');
},
},
]);
};
const handleDeleteAccount = () => {
Alert.alert(copy.deleteConfirmTitle, copy.deleteConfirmMessage, [
{ text: 'Cancel', style: 'cancel' },
{
text: copy.deleteActionBtn,
style: 'destructive',
onPress: async () => {
// Future implementation: call backend to wipe user data, cancel active Stripe subscriptions
await signOut();
router.replace('/onboarding');
},
},
]);
};
return (
<View style={{ flex: 1, backgroundColor: colors.background }}>
<ThemeBackdrop colors={colors} />
<SafeAreaView style={styles.safeArea} edges={['top']}>
<View style={styles.header}>
<TouchableOpacity onPress={() => router.back()} style={styles.backButton}>
<Ionicons name="arrow-back" size={24} color={colors.text} />
</TouchableOpacity>
<Text style={[styles.title, { color: colors.text }]}>{copy.title}</Text>
<View style={{ width: 40 }} />
</View>
<ScrollView contentContainerStyle={styles.scrollContent}>
<TouchableOpacity style={[styles.actionRow, { backgroundColor: colors.cardBg, borderColor: colors.border }]} onPress={handleExportData}>
<View style={styles.actionIcon}>
<Ionicons name="download-outline" size={24} color={colors.text} />
</View>
<View style={styles.actionTextContainer}>
<Text style={[styles.actionTitle, { color: colors.text }]}>{copy.exportData}</Text>
<Text style={[styles.actionHint, { color: `${colors.text}80` }]}>{copy.exportHint}</Text>
</View>
</TouchableOpacity>
<TouchableOpacity style={[styles.actionRow, { backgroundColor: colors.cardBg, borderColor: colors.border }]} onPress={handleClearHistory}>
<View style={styles.actionIcon}>
<Ionicons name="time-outline" size={24} color={colors.text} />
</View>
<View style={styles.actionTextContainer}>
<Text style={[styles.actionTitle, { color: colors.text }]}>{copy.clearHistory}</Text>
<Text style={[styles.actionHint, { color: `${colors.text}80` }]}>{copy.clearHistoryHint}</Text>
</View>
</TouchableOpacity>
<TouchableOpacity style={[styles.actionRow, { backgroundColor: colors.cardBg, borderColor: colors.border }]} onPress={handleLogout}>
<View style={styles.actionIcon}>
<Ionicons name="log-out-outline" size={24} color={colors.text} />
</View>
<View style={styles.actionTextContainer}>
<Text style={[styles.actionTitle, { color: colors.text }]}>{copy.logout}</Text>
<Text style={[styles.actionHint, { color: `${colors.text}80` }]}>{copy.logoutHint}</Text>
</View>
</TouchableOpacity>
<View style={{ marginTop: 24 }}>
<TouchableOpacity style={[styles.actionRow, { backgroundColor: '#FF3B3015', borderColor: '#FF3B3050', marginBottom: 0 }]} onPress={handleDeleteAccount}>
<View style={[styles.actionIcon, { backgroundColor: '#FF3B3020' }]}>
<Ionicons name="trash-bin-outline" size={24} color="#FF3B30" />
</View>
<View style={styles.actionTextContainer}>
<Text style={[styles.actionTitle, { color: '#FF3B30' }]}>{copy.deleteAccount}</Text>
<Text style={[styles.actionHint, { color: '#FF3B3080' }]}>{copy.deleteAccountHint}</Text>
</View>
</TouchableOpacity>
</View>
</ScrollView>
</SafeAreaView>
</View>
);
}
const styles = StyleSheet.create({
safeArea: { flex: 1 },
header: { flexDirection: 'row', alignItems: 'center', padding: 16 },
backButton: { width: 40, height: 40, justifyContent: 'center' },
title: { flex: 1, fontSize: 20, fontWeight: '700', textAlign: 'center' },
scrollContent: { padding: 16, gap: 16 },
actionRow: {
flexDirection: 'row',
alignItems: 'center',
padding: 16,
borderRadius: 16,
borderWidth: StyleSheet.hairlineWidth,
marginBottom: 16,
},
actionIcon: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: '#00000010',
justifyContent: 'center',
alignItems: 'center',
marginRight: 16,
},
actionTextContainer: {
flex: 1,
},
actionTitle: {
fontSize: 16,
fontWeight: '600',
marginBottom: 4,
},
actionHint: {
fontSize: 13,
},
});