import { useState } from 'react'; import { ActivityIndicator, Linking, Pressable, ScrollView, Text, TextInput, View, } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Ionicons } from '@expo/vector-icons'; import { useTranslation } from 'react-i18next'; import { useMailConnect, detectProvider, type MailProvider } from '../../hooks/useMailConnect'; import { useColors } from '../../lib/theme'; import { KeyboardAwareSheet } from '../KeyboardAwareSheet'; const COLLAPSED_HEIGHT = 600; type Props = { visible: boolean; onClose: () => void; onSuccess: () => void; }; type ProviderConfig = { id: MailProvider; labelKey: string; icon: React.ComponentProps['name']; color: string; guideKey: string; guideUrl: string; }; const PROVIDERS: ProviderConfig[] = [ { id: 'gmail', labelKey: 'mail.provider_gmail', icon: 'mail', color: '#EA4335', guideKey: 'mail.app_password_guide_gmail', guideUrl: 'https://myaccount.google.com/apppasswords', }, { id: 'icloud', labelKey: 'mail.provider_icloud', icon: 'cloud', color: '#007AFF', guideKey: 'mail.app_password_guide_icloud', guideUrl: 'https://appleid.apple.com/account/manage', }, { id: 'outlook', labelKey: 'mail.provider_outlook', icon: 'mail-open', color: '#0078D4', guideKey: 'mail.app_password_guide_outlook', guideUrl: 'https://account.microsoft.com/security', }, { id: 'yahoo', labelKey: 'mail.provider_yahoo', icon: 'at', color: '#7C3AED', guideKey: 'mail.app_password_guide_yahoo', guideUrl: 'https://login.yahoo.com/account/security', }, { id: 'gmx', labelKey: 'mail.provider_gmx', icon: 'mail-unread', color: '#E87A22', guideKey: 'mail.app_password_guide_gmx', guideUrl: 'https://www.gmx.net/mail/security', }, { id: 'other', labelKey: 'mail.provider_other', icon: 'server', color: '#737373', guideKey: 'mail.app_password_guide_other', guideUrl: '', }, ]; /** * Bottom-Sheet (65% Screen-Höhe) zum Verbinden eines Postfachs. * * Zwei Ansichten im selben Sheet: * 1. Provider-Grid (6 Tiles) * 2. Formular-View: Email + App-Passwort + Guide-Link (nach Provider-Tap) */ export function ConnectMailSheet({ visible, onClose, onSuccess }: Props) { const { t } = useTranslation(); const colors = useColors(); const insets = useSafeAreaInsets(); const { connect, connecting, error: connectError } = useMailConnect(); const [view, setView] = useState<'grid' | 'form'>('grid'); const [selectedProvider, setSelectedProvider] = useState(null); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [passwordVisible, setPasswordVisible] = useState(false); const [formError, setFormError] = useState(null); function handleClose() { setView('grid'); setSelectedProvider(null); setEmail(''); setPassword(''); setPasswordVisible(false); setFormError(null); onClose(); } function handleProviderSelect(provider: ProviderConfig) { setSelectedProvider(provider); setView('form'); setFormError(null); } function handleBack() { setView('grid'); setSelectedProvider(null); setFormError(null); } async function handleConnect() { if (!email.trim() || !password.trim()) { setFormError(t('mail.form_fields_required')); return; } setFormError(null); const body: Parameters[0] = { email: email.trim(), password }; // Für "other" Provider: User muss imapHost selbst eingeben — aktuell nicht // unterstützt in dieser Sheet-Version. Custom-IMAP bleibt TODO für Phase 11. // Provider-Detection passiert server-seitig via Email-Domain. const result = await connect(body); if (result.ok) { handleClose(); onSuccess(); } else { setFormError(result.error ?? t('mail.connect_failed')); } } // Wenn User Email tippt → Provider-Icon in Echtzeit updaten const detectedProvider = email.includes('@') ? detectProvider(email) : null; const currentProvider = selectedProvider ?? null; const header = ( {view === 'form' ? ( {t('common.back')} ) : ( {t('common.cancel')} )} {view === 'form' && currentProvider ? t(currentProvider.labelKey) : t('mail.connect_sheet_title')} ); return ( {view === 'grid' ? ( ) : ( { setEmail(v); setFormError(null); }} password={password} onPasswordChange={(v) => { setPassword(v); setFormError(null); }} passwordVisible={passwordVisible} onTogglePasswordVisible={() => setPasswordVisible((p) => !p)} error={formError ?? connectError} connecting={connecting} onConnect={handleConnect} insets={insets} t={t} /> )} ); } // --------------------------------------------------------------------------- // Sub-View: Provider-Grid // --------------------------------------------------------------------------- function ProviderGrid({ providers, onSelect, t, }: { providers: ProviderConfig[]; onSelect: (p: ProviderConfig) => void; t: (key: string) => string; }) { const colors = useColors(); return ( {t('mail.connect_sheet_subtitle')} {providers.map((p) => ( onSelect(p)} style={({ pressed }) => ({ width: '47%', opacity: pressed ? 0.7 : 1, })} > {t(p.labelKey)} ))} ); } // --------------------------------------------------------------------------- // Sub-View: Formular (Email + App-Passwort) // --------------------------------------------------------------------------- type FormViewProps = { provider: ProviderConfig | null; detectedProvider: MailProvider | null; email: string; onEmailChange: (v: string) => void; password: string; onPasswordChange: (v: string) => void; passwordVisible: boolean; onTogglePasswordVisible: () => void; error: string | null; connecting: boolean; onConnect: () => void; insets: ReturnType; t: (key: string) => string; }; function FormView({ provider, email, onEmailChange, password, onPasswordChange, passwordVisible, onTogglePasswordVisible, error, connecting, onConnect, insets, t, }: FormViewProps) { const colors = useColors(); const canConnect = email.trim().length > 0 && password.trim().length > 0 && !connecting; return ( {/* App-Password-Guide-Hinweis */} {provider && provider.id !== 'other' && ( {t('mail.app_password_required_title')} {t(provider.guideKey)} {provider.guideUrl.length > 0 && ( Linking.openURL(provider.guideUrl)}> {t('mail.app_password_open_link')} → )} )} {/* Email-Input */} {t('mail.form_email_label')} {/* Passwort-Input */} {t('mail.form_password_label')} {/* Datenschutz-Hinweis */} {t('mail.form_privacy_note')} {/* Error */} {error && ( {error} )} {/* Connect-Button */} ({ opacity: pressed ? 0.85 : 1, marginTop: 4, marginBottom: insets.bottom > 0 ? 8 : 12, })} > {connecting ? ( ) : ( {t('mail.form_connect_btn')} )} ); }