import { useState } from 'react'; import { ActivityIndicator, Alert, LayoutAnimation, Platform, ScrollView, Text, TouchableOpacity, UIManager, View, } from 'react-native'; import { useBottomTabBarHeight } from 'react-native-bottom-tabs'; import { useTranslation } from 'react-i18next'; import { Ionicons } from '@expo/vector-icons'; import { AppHeader } from '../../components/AppHeader'; import { MailAccountCard } from '../../components/mail/MailAccountCard'; import { MailEmptyState } from '../../components/mail/MailEmptyState'; import { MailActivityLogBody } from '../../components/mail/MailActivityLog'; import { MailBlockedByDayChart } from '../../components/mail/MailBlockedByDayChart'; import { MailDistributionChart } from '../../components/mail/MailDistributionChart'; import { ConnectMailSheet } from '../../components/mail/ConnectMailSheet'; import { EditMailTitleSheet } from '../../components/mail/EditMailTitleSheet'; import { SuccessAlert } from '../../components/SuccessAlert'; import { useMailStatus } from '../../hooks/useMailStatus'; import { useMailDisconnect } from '../../hooks/useMailDisconnect'; import { useMailStats } from '../../hooks/useMailStats'; import { useUserPlan } from '../../hooks/useUserPlan'; import { useColors } from '../../lib/theme'; import { useMailConnectDraft } from '../../stores/mailConnectDraft'; if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) { UIManager.setLayoutAnimationEnabledExperimental(true); } const PLAN_LABEL: Record = { free: 'Free', pro: 'Pro', legend: 'Legend' }; function MailOverLimitBanner({ usedCount, maxAccounts, planLabel, pausedEmails, colors, }: { usedCount: number; maxAccounts: number; planLabel: string; pausedEmails: string[]; colors: import('../../lib/theme').ColorScheme; }) { const { t } = useTranslation(); const over = usedCount - maxAccounts; if (over <= 0) return null; return ( {t('plan_limit.mail_banner_title')} {t(over === 1 ? 'plan_limit.mail_banner_body_one' : 'plan_limit.mail_banner_body_other', { used: usedCount, plan: planLabel, max: maxAccounts, over, })} {pausedEmails.length > 0 && ( {pausedEmails.join(', ')} )} ); } function MoreInfosSection({ expanded, onToggle, blockedByDay, providers, colors, }: { expanded: boolean; onToggle: () => void; blockedByDay: import('../../hooks/useMailStats').BlockedByDayEntry[]; providers: string[]; colors: import('../../lib/theme').ColorScheme; }) { const { t } = useTranslation(); const [activityExpanded, setActivityExpanded] = useState(false); function handleToggle() { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); onToggle(); } function handleActivityToggle() { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); setActivityExpanded((p) => !p); } return ( {t('mail.more_infos_title')} {expanded && ( {/* Bar-Chart direkt sichtbar */} {/* Nested: Kürzlich blockiert — default collapsed */} {t('mail.activity_log_title')} {t('mail.activity_log_subtitle')} {activityExpanded && ( )} )} ); } export default function MailScreen() { const { t } = useTranslation(); const tabBarHeight = useBottomTabBarHeight(); const colors = useColors(); const { plan } = useUserPlan(); const { accounts, totalBlocked, maxAccounts, loading, refresh } = useMailStatus(plan); const { disconnect, disconnecting } = useMailDisconnect(); const hasAccounts = accounts.length > 0; const { blockedByDay, blockedByConnection, refresh: refreshStats } = useMailStats(hasAccounts); // Globaler Refresh-Handler für alle reactive-Trigger (Scan-Success, // Interval-Change, Connect/Disconnect): refresht beide Datenquellen // parallel — useMailStatus (accounts, connect-errors, heartbeat) UND // useMailStats (blockedByDay, blockedByConnection für Charts + Counter). const refreshAll = () => { refresh(); refreshStats(); }; const [sheetVisible, setSheetVisible] = useState(false); const [successVisible, setSuccessVisible] = useState(false); const [disconnectingId, setDisconnectingId] = useState(null); const [expandedAccount, setExpandedAccount] = useState(null); const [moreInfosExpanded, setMoreInfosExpanded] = useState(false); const [oauthTitleSheetConnectionId, setOauthTitleSheetConnectionId] = useState(null); const { pendingOAuthConnectionId, setPendingOAuthConnectionId } = useMailConnectDraft(); const pausedAccounts = accounts.filter((a) => a.paused === true); const overLimit = maxAccounts !== Infinity && accounts.length > maxAccounts; const limitReached = maxAccounts !== Infinity && accounts.length >= maxAccounts; const distinctProviders = [ ...new Set(accounts.map((a) => a.provider.toLowerCase())), ]; // Show distribution chart only when ≥2 accounts have data const showDistributionHero = blockedByConnection.length >= 2; function handleAddPress() { if (limitReached) { Alert.alert(t('mail.upgrade_alert_title'), t('mail.upgrade_alert_desc')); return; } setSheetVisible(true); } async function handleDisconnect(id: string) { setDisconnectingId(id); await disconnect(id); setDisconnectingId(null); if (expandedAccount === id) setExpandedAccount(null); refreshAll(); } function handleConnectSuccess() { refreshAll(); if (pendingOAuthConnectionId) { setOauthTitleSheetConnectionId(pendingOAuthConnectionId); setPendingOAuthConnectionId(null); } else { setSuccessVisible(true); } } function toggleAccount(id: string) { setExpandedAccount((prev) => (prev === id ? null : id)); } if (loading) { return ( ); } return ( {/* Over-limit banner */} {overLimit && pausedAccounts.length > 0 && ( a.email)} colors={colors} /> )} {/* 1. HERO — Half-Donut with integrated title row */} {hasAccounts && showDistributionHero && ( )} {/* Fallback stats row when donut is not shown (0-1 accounts with data) */} {hasAccounts && !showDistributionHero && ( {totalBlocked.toLocaleString()} {t('mail.stats_account_summary', { count: accounts.length })} {plan === 'legend' ? t('mail.live') : t('mail.scheduled')} )} {/* 2. COLLAPSIBLE "MEHR INFOS" — Bar-Chart + nested Kürzlich blockiert */} {hasAccounts && ( setMoreInfosExpanded((p) => !p)} blockedByDay={blockedByDay} providers={distinctProviders} colors={colors} /> )} {/* 3. ACCOUNT LIST */} {hasAccounts && ( {t('mail.section_accounts')} {maxAccounts === Infinity ? t('mail.section_accounts_count_unlimited', { used: accounts.length }) : t('mail.section_accounts_count', { used: accounts.length, max: maxAccounts, })} {t('mail.add_account')} )} {accounts.length === 0 ? ( ) : ( {accounts.map((account) => { const connStat = blockedByConnection.find((c) => c.connectionId === account.id); return ( toggleAccount(account.id)} onDisconnect={handleDisconnect} onIntervalChanged={refreshAll} onEditSuccess={handleConnectSuccess} disconnecting={disconnectingId === account.id && disconnecting} blockedLast30d={connStat?.count} onScanSuccess={refreshAll} /> ); })} )} setSheetVisible(false)} onSuccess={handleConnectSuccess} /> {oauthTitleSheetConnectionId && ( { setOauthTitleSheetConnectionId(null); setSuccessVisible(true); }} onSuccess={() => { setOauthTitleSheetConnectionId(null); setSuccessVisible(true); refreshAll(); }} /> )} setSuccessVisible(false)} /> ); }