import { useState, useEffect } from 'react'; import { ActivityIndicator, Image, ScrollView, Text, TextInput, TouchableOpacity, View, } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { useTranslation } from 'react-i18next'; import { isValidDomain, normalizeDomain, type Tier, } from '../../hooks/useCustomDomains'; import { useColors, type ColorScheme } from '../../lib/theme'; import { FormSheet } from '../FormSheet'; type InputKind = 'web' | 'mail'; type Props = { visible: boolean; tier: Tier; initialType?: InputKind; onClose: () => void; onAdd: (pattern: string, kind: InputKind) => Promise<{ ok: boolean; error?: string; alreadyGlobal?: boolean }>; }; export function AddDomainSheet({ visible, tier, initialType, onClose, onAdd }: Props) { const { t } = useTranslation(); const colors = useColors(); const [kind, setKind] = useState(initialType ?? 'web'); const [input, setInput] = useState(''); const [confirmPermanent, setConfirmPermanent] = useState(false); const [adding, setAdding] = useState(false); const [error, setError] = useState(null); useEffect(() => { if (visible) setKind(initialType ?? 'web'); }, [visible, initialType]); const normalizedWeb = kind === 'web' ? normalizeDomain(input) : ''; // For mail input: if the user typed a full address (local@domain.tld), strip // the local-part and keep only the domain. A bare domain without "@" stays as-is. const mailPattern = (() => { if (kind !== 'mail') return ''; const raw = input.trim(); if (!raw) return ''; const atIdx = raw.lastIndexOf('@'); if (atIdx === -1) return raw.toLowerCase(); return raw.slice(atIdx + 1).trim().toLowerCase(); })(); function close() { setInput(''); setConfirmPermanent(false); setError(null); onClose(); } function handleKindChange(next: InputKind) { if (next === kind) return; setKind(next); setInput(''); setError(null); } function isInputValid(): boolean { if (kind === 'web') return isValidDomain(input); return input.trim().length > 0; } async function handleAdd() { if (!isInputValid() || !confirmPermanent || adding) return; setAdding(true); setError(null); const pattern = kind === 'web' ? normalizeDomain(input) : mailPattern; const result = await onAdd(pattern, kind); setAdding(false); if (result.ok) { close(); return; } if (result.alreadyGlobal) { setError(t('blocker.add_sheet_already_global', { domain: normalizedWeb || input.trim() })); } else if (result.error?.includes('WEB_LIMIT_REACHED')) { setError(t('blocker.error_web_limit_reached')); } else if (result.error?.includes('MAIL_LIMIT_REACHED')) { setError(t('blocker.error_mail_limit_reached')); } else { setError(result.error ?? t('blocker.add_sheet_add_failed')); } } const warningText = tier.plan === 'free' ? t('blocker.add_sheet_warning_free') : t('blocker.add_sheet_warning_pro'); const inputLabel = kind === 'web' ? t('blocker.add_web_label') : t('blocker.add_mail_label'); const inputPlaceholder = kind === 'web' ? t('blocker.add_web_placeholder') : t('blocker.add_mail_placeholder'); const helpText = kind === 'web' ? t('blocker.add_web_help') : t('blocker.add_mail_help'); const canSubmit = isInputValid() && confirmPermanent && !adding; return ( {/* 1. Type-Picker Pill */} {/* 2. Input-Field */} {inputLabel} { setInput(v); setError(null); }} placeholder={inputPlaceholder} placeholderTextColor={colors.textMuted} keyboardType={kind === 'web' ? 'url' : 'email-address'} autoCapitalize="none" autoCorrect={false} style={{ backgroundColor: colors.surfaceElevated, borderRadius: 10, padding: 12, fontSize: 14, fontFamily: 'Nunito_400Regular', color: colors.text, borderWidth: 1, borderColor: error ? '#dc2626' : colors.border, }} /> {error && ( {error} )} {/* 3. Help-Text */} {helpText} {/* 4. Preview-Card */} {kind === 'web' ? ( {normalizedWeb || inputPlaceholder} ) : ( {mailPattern || inputPlaceholder} )} {/* 5. Warning-Card */} {warningText} {/* 6. Confirm-Checkbox */} setConfirmPermanent((v) => !v)} activeOpacity={0.7} style={{ flexDirection: 'row', alignItems: 'flex-start', gap: 10, paddingVertical: 4, }} > {confirmPermanent && } {t('blocker.add_sheet_confirm_permanent')} {/* 7. Buttons */} {t('common.cancel')} {adding ? ( ) : ( {t('blocker.add_sheet_cta')} )} ); } // ─── TypePicker ────────────────────────────────────────────────────────────── function TypePicker({ kind, onChange, colors, }: { kind: InputKind; onChange: (k: InputKind) => void; colors: ColorScheme; }) { const { t } = useTranslation(); return ( onChange('web')} colors={colors} /> onChange('mail')} colors={colors} /> ); } function TypePill({ icon, label, active, onPress, colors, }: { icon: 'globe-outline' | 'mail-outline'; label: string; active: boolean; onPress: () => void; colors: ColorScheme; }) { return ( {label} ); }