import { useState } from 'react'; import { ActivityIndicator, ScrollView, Text, TouchableOpacity, View } from 'react-native'; import { Image } from 'expo-image'; import { Ionicons } from '@expo/vector-icons'; import { useTranslation } from 'react-i18next'; import { FormSheet } from '../FormSheet'; import { useColors } from '../../lib/theme'; import type { CustomDomain } from '../../hooks/useCustomDomains'; type Props = { visible: boolean; newDomainId: string; candidates: CustomDomain[]; onClose: () => void; onSwap: (newDomainId: string, evictedDomainId: string) => Promise<{ ok: boolean; error?: string }>; }; function isVipEligible(d: CustomDomain): boolean { if (d.type !== 'web') return false; if (d.status === 'rejected') return false; const now = Date.now(); if (d.vipDeferUntil && new Date(d.vipDeferUntil).getTime() > now) return false; if (d.vipEvictAt && new Date(d.vipEvictAt).getTime() < now) return false; return true; } export function VipSwapSheet({ visible, newDomainId, candidates, onClose, onSwap }: Props) { const { t } = useTranslation(); const colors = useColors(); const [selectedId, setSelectedId] = useState(null); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); const eligible = candidates.filter(isVipEligible); function close() { setSelectedId(null); setError(null); onClose(); } async function handleSwap(evictedId: string) { if (submitting) return; setSubmitting(true); setError(null); const result = await onSwap(newDomainId, evictedId); setSubmitting(false); if (result.ok) { close(); return; } setError(t('blocker.vip_swap_error')); } return ( {t('blocker.vip_swap_desc')} {t('blocker.vip_swap_pick')} {eligible.length === 0 ? ( {t('blocker.vip_swap_no_candidates')} ) : ( {eligible.map((d) => ( setSelectedId(selectedId === d.id ? null : d.id)} onConfirm={() => handleSwap(d.id)} colors={colors} /> ))} )} {error && ( {error} )} ); } function SwapCandidateTile({ domain, selected, submitting, onSelect, onConfirm, colors, }: { domain: CustomDomain; selected: boolean; submitting: boolean; onSelect: () => void; onConfirm: () => void; colors: ReturnType; }) { const { t } = useTranslation(); const [imgError, setImgError] = useState(false); const stripped = domain.domain.replace(/^www\./, ''); return ( {!imgError ? ( setImgError(true)} /> ) : ( {stripped.slice(0, 2).toUpperCase()} )} {stripped} {selected && ( {submitting ? ( ) : ( {t('blocker.vip_swap_cta')} )} )} ); }