import { useState } from 'react'; import { ActivityIndicator, LayoutAnimation, Platform, Pressable, Text, UIManager, View, } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { useTranslation } from 'react-i18next'; import { ConfirmAlert } from '../ConfirmAlert'; import { EditMailAccountSheet } from './EditMailAccountSheet'; import { useMailInterval } from '../../hooks/useMailInterval'; import type { MailAccount } from '../../hooks/useMailStatus'; if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) { UIManager.setLayoutAnimationEnabledExperimental(true); } type Props = { account: MailAccount; plan: 'free' | 'pro' | 'legend'; expanded: boolean; onToggle: () => void; onDisconnect: (id: string) => Promise; onIntervalChanged: () => void; onEditSuccess: () => void; disconnecting?: boolean; }; function resolveProviderIcon(provider: string): { icon: React.ComponentProps['name']; color: string; } { const p = provider.toLowerCase(); if (p.includes('gmail') || p.includes('google')) return { icon: 'mail', color: '#EA4335' }; if (p.includes('icloud') || p.includes('apple')) return { icon: 'cloud', color: '#007AFF' }; if (p.includes('outlook') || p.includes('hotmail') || p.includes('microsoft')) return { icon: 'mail-open', color: '#0078D4' }; if (p.includes('yahoo')) return { icon: 'at', color: '#7C3AED' }; if (p.includes('gmx') || p.includes('web.de')) return { icon: 'mail-unread', color: '#E87A22' }; return { icon: 'server', color: '#737373' }; } function formatRelativeTime(iso: string | null, t: (k: string) => string): string { if (!iso) return t('mail.account_never_scanned'); const diff = Date.now() - new Date(iso).getTime(); 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 `${hours}h`; return `${Math.floor(hours / 24)}d`; } const INTERVAL_OPTIONS_BY_PLAN: Record<'free' | 'pro' | 'legend', number[]> = { free: [4], pro: [1, 4, 8], legend: [1, 4, 8], }; // Solid styles outside of render — no gap, no callback layout. const HEADER_ROW = { flexDirection: 'row' as const, alignItems: 'center' as const, paddingHorizontal: 14, paddingVertical: 14, }; const ACTION_BTN_BASE = { flex: 1, flexDirection: 'row' as const, alignItems: 'center' as const, justifyContent: 'center' as const, paddingVertical: 12, borderRadius: 10, }; export function MailAccountCard({ account, plan, expanded, onToggle, onDisconnect, onIntervalChanged, onEditSuccess, disconnecting, }: Props) { const { t } = useTranslation(); const [confirmVisible, setConfirmVisible] = useState(false); const [editVisible, setEditVisible] = useState(false); const { setInterval, updating } = useMailInterval(); const { icon, color } = resolveProviderIcon(account.provider); const isLegend = plan === 'legend'; const intervalOptions = INTERVAL_OPTIONS_BY_PLAN[plan]; function handleToggle() { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); onToggle(); } async function handleSetInterval(value: number) { const res = await setInterval(account.id, value); if (res.ok) onIntervalChanged(); } return ( <> {/* ── Header ── */} {account.email} {account.isActive ? isLegend ? t('mail.live') : t('mail.account_active') : t('mail.account_inactive')} · {formatRelativeTime(account.lastScannedAt, t)} {/* ── Body ── */} {expanded && ( {/* Big stat: Blocked */} {t('mail.account_stat_blocked')} {account.totalBlocked.toLocaleString()} {t('mail.account_of_scanned', { scanned: account.totalScanned.toLocaleString(), })} {/* Scan Mode */} {isLegend ? ( {t('mail.realtime_desc')} ) : ( {t('mail.scan_interval_label')} {intervalOptions.map((opt, idx) => { const active = account.scanInterval === opt; const disabled = plan === 'free' || updating === account.id; return ( handleSetInterval(opt)} style={{ flex: 1, paddingVertical: 9, borderRadius: 10, alignItems: 'center', backgroundColor: active ? '#007AFF' : '#f5f5f5', marginLeft: idx === 0 ? 0 : 6, opacity: disabled && !active ? 0.5 : 1, }} > {opt}h ); })} {plan === 'free' && ( {t('mail.free_scan_interval_hint')} )} )} {/* Action Row */} setEditVisible(true)} style={{ ...ACTION_BTN_BASE, backgroundColor: '#f5f5f5', marginRight: 6 }} > {t('mail.account_change_password')} setConfirmVisible(true)} disabled={disconnecting} style={{ ...ACTION_BTN_BASE, backgroundColor: '#fef2f2', marginLeft: 6, opacity: disconnecting ? 0.6 : 1, }} > {disconnecting ? ( ) : ( <> {t('mail.disconnect')} )} )} { setConfirmVisible(false); await onDisconnect(account.id); }} onCancel={() => setConfirmVisible(false)} /> setEditVisible(false)} onSuccess={onEditSuccess} /> ); }