import { useState } from 'react'; import { LayoutAnimation, Platform, ScrollView, TouchableOpacity, Text, UIManager, View, } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { useTranslation } from 'react-i18next'; import { useMailResults, type MailBlockedItem } from '../../hooks/useMailResults'; import { useColors } from '../../lib/theme'; if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) { UIManager.setLayoutAnimationEnabledExperimental(true); } type Props = { expanded: boolean; onToggle: () => void; providers?: string[]; }; function formatDate(iso: string, t: (k: string) => string): string | null { const ts = new Date(iso).getTime(); if (!Number.isFinite(ts)) return null; const diff = Date.now() - ts; const mins = Math.floor(diff / 60_000); if (mins < 2) return t('mail.account_just_now'); if (mins < 60) return `${mins} min`; const hours = Math.floor(mins / 60); if (hours < 24) return `vor ${hours}h`; return `vor ${Math.floor(hours / 24)}d`; } function domainFromEmail(email: string): string { return email.split('@')[1] ?? email; } function providerDisplayName(provider: string): string { const map: Record = { gmail: 'Gmail', icloud: 'iCloud', outlook: 'Outlook', yahoo: 'Yahoo', gmx: 'GMX', other: 'Andere', }; return map[provider.toLowerCase()] ?? provider; } export function MailActivityLog({ expanded, onToggle, providers = [] }: Props) { const { t } = useTranslation(); const colors = useColors(); function handleToggle() { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); onToggle(); } return ( {t('mail.activity_log_title')} {t('mail.activity_log_subtitle')} {expanded && ( )} ); } /** * Only the expandable body — used standalone by MoreInfosSection as nested collapsible. */ export function MailActivityLogBody({ providers = [], colors, }: { providers?: string[]; colors: ReturnType; }) { const { t } = useTranslation(); const [activeProvider, setActiveProvider] = useState('all'); const { results, total, loading, refresh } = useMailResults(true, activeProvider); const filterOptions = ['all', ...providers]; return ( {/* Provider filter chips */} {filterOptions.length > 1 && ( {filterOptions.map((p) => { const active = activeProvider === p; return ( setActiveProvider(p)} style={{ paddingHorizontal: 12, paddingVertical: 5, borderRadius: 999, backgroundColor: active ? '#007AFF' : colors.surfaceElevated, borderWidth: active ? 0 : 1, borderColor: colors.border, }} > {p === 'all' ? t('mail.filter.all') : providerDisplayName(p)} ); })} )} {loading && results.length === 0 ? ( {t('mail.loading')} ) : results.length === 0 ? ( {t('mail.activity_log_empty')} ) : ( <> {results.slice(0, 10).map((item) => ( ))} {total > 10 ? t('mail.activity_log_more', { count: total - 10 }) : t('mail.activity_log_count', { count: total })} )} ); } function ActivityItem({ item, t, colors, }: { item: MailBlockedItem; t: (k: string, opts?: any) => string; colors: ReturnType; }) { const providerLabel = item.connection?.providerLabel ?? ( item.senderEmail ? domainFromEmail(item.senderEmail) : null ); // createdAt = wann WIR die Mail geblockt haben. receivedAt = wann der // Sender sie ursprünglich rausgeschickt hat — bei alten Casino-Mails die // wir gerade erst gescant haben, ist das oft Wochen/Monate her und // verwirrt den User in der "Kürzlich blockiert"-Liste. const timeLabel = formatDate(item.createdAt, t); const subLine = [timeLabel, providerLabel].filter(Boolean).join(' · '); return ( {item.subject || t('mail.activity_no_subject')} {subLine.length > 0 && ( {subLine} )} ); }