'use client'; import { useState, useRef, useEffect } from 'react'; import { Loader2, CheckCircle, AlertCircle } from 'lucide-react'; import { useTranslations } from 'next-intl'; import { isValidUnsubscribeUrl, parseMailtoUrl } from '@/lib/validation'; import { ConfirmDialog } from '@/components/ui/confirm-dialog'; import { useIsDesktop } from '@/hooks/use-media-query'; interface UnsubscribeBannerProps { listUnsubscribe: { http?: string; mailto?: string; preferred?: 'http' | 'mailto'; }; senderEmail: string; // Sends the unsubscribe message through the app's own account. This is a // webmail client - handing a mailto: URL to the OS mail handler goes // nowhere for most users. onSendMailtoUnsubscribe: (fields: { to: string[]; subject?: string; body?: string }) => Promise; onDismiss: () => void; } export function UnsubscribeBanner({ listUnsubscribe, senderEmail: _senderEmail, onSendMailtoUnsubscribe, onDismiss }: UnsubscribeBannerProps) { const t = useTranslations(); const [showConfirm, setShowConfirm] = useState(false); const [processing, setProcessing] = useState(false); const [success, setSuccess] = useState(false); const [error, setError] = useState(false); const popoverRef = useRef(null); const isDesktop = useIsDesktop(); const unsubMethod = listUnsubscribe.preferred; const unsubUrl = unsubMethod === 'http' ? listUnsubscribe.http : listUnsubscribe.mailto; useEffect(() => { if (!showConfirm) return; const handleClickOutside = (e: MouseEvent) => { if (popoverRef.current && !popoverRef.current.contains(e.target as Node)) { setShowConfirm(false); } }; // Use setTimeout to avoid the opening click triggering immediate close const timer = setTimeout(() => { document.addEventListener('mousedown', handleClickOutside); }, 0); return () => { clearTimeout(timer); document.removeEventListener('mousedown', handleClickOutside); }; }, [showConfirm]); if (!unsubUrl || !unsubMethod) { return null; } const handleUnsubscribe = async () => { if (!isValidUnsubscribeUrl(unsubUrl)) { setError(true); setProcessing(false); setShowConfirm(false); return; } setProcessing(true); try { if (unsubMethod === 'http') { window.open(unsubUrl, '_blank', 'noopener,noreferrer'); setSuccess(true); setProcessing(false); setShowConfirm(false); setTimeout(onDismiss, 3000); } else { // Send the unsubscribe message ourselves and only report success // once the server accepted it. The previous hidden-link click handed // the mailto: to the OS mail handler and claimed success even though // nothing was ever sent. const fields = parseMailtoUrl(unsubUrl); if (!fields) { setError(true); setProcessing(false); setShowConfirm(false); return; } await onSendMailtoUnsubscribe(fields); setSuccess(true); setProcessing(false); setShowConfirm(false); setTimeout(onDismiss, 3000); } } catch (err) { console.error('Unsubscribe error:', err); setError(true); setProcessing(false); setShowConfirm(false); } }; if (success) { return ( {t(unsubMethod === 'http' ? 'email_viewer.unsubscribe_banner.success_http' : 'email_viewer.unsubscribe_banner.success_mailto' )} ); } if (error) { return ( ); } return ( <> ยท {/* Desktop popover */} {showConfirm && isDesktop && (

{t('email_viewer.unsubscribe_banner.confirm_title')}

)}
{/* Mobile/tablet: proper confirm dialog */} {!isDesktop && ( setShowConfirm(false)} onConfirm={() => { setShowConfirm(false); handleUnsubscribe(); }} title={t('email_viewer.unsubscribe_banner.confirm_title')} message={t(unsubMethod === 'http' ? 'email_viewer.unsubscribe_banner.confirm_message_http' : 'email_viewer.unsubscribe_banner.confirm_message_mailto' )} confirmText={t('email_viewer.unsubscribe_banner.confirm_button')} cancelText={t('email_viewer.unsubscribe_banner.cancel')} variant="destructive" /> )} ); }