'use client'; import { useEffect, useState, useCallback } from 'react'; import { formatPhone, relativeTime } from '@/lib/utils'; import type { ContactFilterParams } from '@/app/contacts/page'; interface Contact { id: string; phone: string; name: string | null; email: string | null; status: string; tags: string; message_count: number; last_contact: string; first_contact: string; bot_name: string | null; assigned_bot_id: string | null; fields_json: string; } interface ContactsTableProps { filters: ContactFilterParams; refreshKey: number; selectedContactId: string | null; onSelect: (id: string) => void; } const STATUS_CONFIG: Record = { hot: { label: 'Hot Lead', dot: 'bg-red-500', badgeClass: 'badge-hot' }, warm: { label: 'Warm', dot: 'bg-orange-500', badgeClass: 'badge-warm' }, cold: { label: 'Cold', dot: 'bg-slate-400', badgeClass: 'badge-cold' }, new: { label: 'New', dot: 'bg-blue-500', badgeClass: 'badge-new' }, active: { label: 'Active', dot: 'bg-green-500', badgeClass: 'badge-active' }, closed: { label: 'Closed', dot: 'bg-gray-500', badgeClass: 'badge-closed' }, }; export function ContactsTable({ filters, refreshKey, selectedContactId, onSelect }: ContactsTableProps) { const [contacts, setContacts] = useState([]); const [loading, setLoading] = useState(true); const [page, setPage] = useState(0); const limit = 50; const fetchContacts = useCallback(async () => { setLoading(true); try { const params = new URLSearchParams(); if (filters.search) params.set('search', filters.search); if (filters.status) params.set('status', filters.status); if (filters.bot) params.set('bot', filters.bot); params.set('limit', String(limit)); params.set('offset', String(page * limit)); const res = await fetch(`/api/contacts?${params.toString()}`); if (res.ok) { const data = await res.json(); setContacts(data.contacts); } } catch (err) { console.error('Failed to fetch contacts:', err); } finally { setLoading(false); } }, [filters, page, refreshKey]); useEffect(() => { fetchContacts(); }, [fetchContacts]); // Reset page when filters change useEffect(() => { setPage(0); }, [filters]); const parseTags = (tagsStr: string): string[] => { try { const parsed = JSON.parse(tagsStr); return Array.isArray(parsed) ? parsed : []; } catch { return []; } }; const getStatus = (status: string) => STATUS_CONFIG[status] || STATUS_CONFIG.new; return (
{/* Table */}
{loading ? ( ) : contacts.length === 0 ? ( ) : ( contacts.map((contact) => { const status = getStatus(contact.status); const tags = parseTags(contact.tags); const isSelected = contact.id === selectedContactId; return ( onSelect(contact.id)} className="cursor-pointer transition-colors duration-150" style={{ borderLeft: isSelected ? '3px solid var(--accent-cyan)' : '3px solid transparent', background: isSelected ? 'rgba(34, 211, 238, 0.05)' : undefined, }} onMouseEnter={(e) => { if (!isSelected) e.currentTarget.style.background = '#2d3748'; }} onMouseLeave={(e) => { e.currentTarget.style.background = isSelected ? 'rgba(34, 211, 238, 0.05)' : ''; }} > {/* Name */} {/* Phone */} {/* Assigned Bot */} {/* Status */} {/* Messages */} {/* Last Contact */} {/* Tags */} ); }) )}
Name Phone Number Assigned Bot Status Messages Last Contact Tags
Loading contacts...

No contacts found

Try adjusting your filters

{contact.name || 'Unknown'} {formatPhone(contact.phone)} {contact.bot_name || ( Unassigned )}
{status.label}
{contact.message_count} {contact.last_contact ? relativeTime(contact.last_contact) : '—'}
{tags.slice(0, 3).map((tag, i) => ( {tag} ))} {tags.length > 3 && ( +{tags.length - 3} )}
{/* Pagination */} {!loading && contacts.length > 0 && (
Showing {page * limit + 1}–{page * limit + contacts.length}
Page {page + 1}
)}
); }