import { useState } from 'react'; import { ActivityIndicator, Linking, ScrollView, Text, TouchableOpacity, View, } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { useTranslation } from 'react-i18next'; import { useMailConnect, detectProvider, type MailProvider } from '../../hooks/useMailConnect'; import { humanizeMailError } from '../../lib/mailErrors'; import { useColors } from '../../lib/theme'; import { FormSheet } from '../FormSheet'; import { SheetFieldStack } from '../SheetFieldStack'; 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 zum Verbinden eines Postfachs. * * Zwei Ansichten im selben Sheet (kein Navigations-Header): * 1. Provider-Grid (6 Tiles) — Schließen via Swipe/Backdrop * 2. Formular: Email + App-Passwort als SheetFieldStack, * dann Datenschutz-Hinweis + Connect-Button */ export function ConnectMailSheet({ visible, onClose, onSuccess }: Props) { const { t } = useTranslation(); const colors = useColors(); 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); const [fieldsComplete, setFieldsComplete] = useState(false); function handleClose() { setView('grid'); setSelectedProvider(null); setEmail(''); setPassword(''); setPasswordVisible(false); setFormError(null); setFieldsComplete(false); onClose(); } function handleProviderSelect(provider: ProviderConfig) { setSelectedProvider(provider); setEmail(''); setPassword(''); setFormError(null); setFieldsComplete(false); setView('form'); } async function handleConnect() { setFormError(null); const result = await connect({ email: email.trim(), password }); if (result.ok) { handleClose(); onSuccess(); } else { setFormError(t(humanizeMailError(result.error))); } } const sheetTitle = view === 'form' && selectedProvider ? t(selectedProvider.labelKey) : t('mail.connect_sheet_title'); return ( {view === 'grid' ? ( ) : ( { setEmail(v); setFormError(null); }, keyboardType: 'email-address', autoCapitalize: 'none', autoCorrect: false, validate: (v) => v.trim().length === 0 ? t('mail.form_fields_required') : undefined, }, { key: 'password', label: t('mail.form_password_label'), placeholder: t('mail.form_password_placeholder'), value: password, onChangeText: (v) => { setPassword(v); setFormError(null); }, secureTextEntry: !passwordVisible, autoCapitalize: 'none', autoCorrect: false, validate: (v) => v.trim().length === 0 ? t('mail.form_fields_required') : undefined, suffix: ( setPasswordVisible((p) => !p)} hitSlop={8} > ), }, ]} intro={ {/* App-Password-Guide — provider-spezifisch, nicht für 'other' */} {selectedProvider && selectedProvider.id !== 'other' && ( {t('mail.app_password_required_title')} {t(selectedProvider.guideKey)} {selectedProvider.guideUrl.length > 0 && ( Linking.openURL(selectedProvider.guideUrl)} > {t('mail.app_password_open_link')} → )} )} {/* Datenschutz-Zusicherung — immer sichtbar */} {t('mail.form_privacy_note')} } onComplete={() => setFieldsComplete(true)} > {/* Fehler */} {(formError ?? (connectError ? t(humanizeMailError(connectError)) : null)) && ( {formError ?? t(humanizeMailError(connectError))} )} {/* Connect-Button */} {connecting ? ( ) : ( {t('mail.form_connect_btn')} )} )} ); } // --------------------------------------------------------------------------- // 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)} activeOpacity={0.7} style={{ width: '47%' }} > {t(p.labelKey)} ))} ); }