import React, { useState, useEffect } from 'react'; import axios from 'axios'; interface BounceRecord { id: number; email: string; bounce_type: 'hard' | 'soft' | 'complaint' | 'unsubscribe'; bounce_reason: string | null; bounce_date: string; is_active: boolean; smtp2go_message_id: string | null; } interface BounceStats { total_bounces: number; active_bounces: number; bounce_types: { hard: number; soft: number; complaint: number; unsubscribe: number; }; } const BounceManagement: React.FC = () => { const [bounces, setBounces] = useState([]); const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); const [searchEmail, setSearchEmail] = useState(''); const [filteredBounces, setFilteredBounces] = useState([]); useEffect(() => { fetchBounces(); fetchStats(); }, []); useEffect(() => { if (searchEmail.trim() === '') { setFilteredBounces(bounces); } else { setFilteredBounces( bounces.filter(bounce => bounce.email.toLowerCase().includes(searchEmail.toLowerCase()) ) ); } }, [bounces, searchEmail]); const fetchBounces = async () => { try { const token = localStorage.getItem('token'); const response = await axios.get('/api/v1/email/bounces', { headers: { Authorization: `Bearer ${token}` } }); setBounces(response.data.bounces); } catch (error) { console.error('Error fetching bounces:', error); } }; const fetchStats = async () => { try { const token = localStorage.getItem('token'); const response = await axios.get('/api/v1/email/bounces/stats', { headers: { Authorization: `Bearer ${token}` } }); setStats(response.data); } catch (error) { console.error('Error fetching bounce stats:', error); } finally { setLoading(false); } }; const handleDeactivateBounce = async (bounceId: number) => { if (!window.confirm('Are you sure you want to deactivate this bounce record?')) { return; } try { const token = localStorage.getItem('token'); await axios.delete(`/api/v1/email/bounces/${bounceId}`, { headers: { Authorization: `Bearer ${token}` } }); fetchBounces(); // Refresh the list fetchStats(); // Refresh stats } catch (error) { console.error('Error deactivating bounce:', error); alert('Failed to deactivate bounce record'); } }; const handleCleanupOldBounces = async () => { if (!window.confirm('Are you sure you want to cleanup old soft bounces? This will deactivate soft bounces older than 365 days.')) { return; } try { const token = localStorage.getItem('token'); const response = await axios.post('/api/v1/email/bounces/cleanup', {}, { headers: { Authorization: `Bearer ${token}` } }); alert(response.data.message); fetchBounces(); // Refresh the list fetchStats(); // Refresh stats } catch (error) { console.error('Error cleaning up bounces:', error); alert('Failed to cleanup old bounces'); } }; const getBounceTypeColor = (type: string) => { switch (type) { case 'hard': return '#dc3545'; case 'soft': return '#ffc107'; case 'complaint': return '#fd7e14'; case 'unsubscribe': return '#6c757d'; default: return '#6c757d'; } }; const formatDate = (dateString: string) => { return new Date(dateString).toLocaleString(); }; if (loading) { return (
Loading bounce data...
); } return (
{/* Statistics Cards */} {stats && (

Total Bounces

{stats.total_bounces}

Active Bounces

{stats.active_bounces}

Hard Bounces

{stats.bounce_types.hard}

Soft Bounces

{stats.bounce_types.soft}
)} {/* Controls */}
setSearchEmail(e.target.value)} placeholder="Enter email address..." style={{ padding: '8px 12px', border: '1px solid #ced4da', borderRadius: '4px', minWidth: '250px' }} />
{/* Bounce Records Table */}

Bounce Records

{filteredBounces.length === 0 ? ( ) : ( filteredBounces.map((bounce) => ( )) )}
Email Type Reason Date Status Actions
{searchEmail ? 'No bounces found matching your search.' : 'No bounce records found.'}
{bounce.email}
{bounce.smtp2go_message_id && (
ID: {bounce.smtp2go_message_id}
)}
{bounce.bounce_type}
{bounce.bounce_reason || 'No reason provided'}
{formatDate(bounce.bounce_date)} {bounce.is_active ? 'Active' : 'Resolved'} {bounce.is_active && ( )}
); }; export default BounceManagement;