"use client"; import { Fragment, useEffect, useState } from 'react'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { Menu, Listbox, Transition } from '@headlessui/react'; import CreateAgencyModal from '@/components/agencies/CreateAgencyModal'; import ConfirmDialog from '@/components/layout/ConfirmDialog'; import Pagination from '@/components/layout/Pagination'; import { useToast } from '@/components/layout/ToastContext'; import { BuildingOfficeIcon, TrashIcon, EyeIcon, PencilIcon, EllipsisVerticalIcon, MagnifyingGlassIcon, FunnelIcon, CalendarIcon, CheckIcon, ChevronUpDownIcon, PlusIcon, XMarkIcon, UserGroupIcon, ChartBarIcon, FolderIcon, LifebuoyIcon, CreditCardIcon, DocumentTextIcon, ArchiveBoxIcon, ShareIcon } from '@heroicons/react/24/outline'; interface Agency { id: string; name: string; subdomain: string; domain: string; email: string; phone: string; cnpj: string; is_active: boolean; created_at: string; logo_url?: string; plan_name?: string; solutions?: Array<{ id: string; name: string; slug: string }>; } // Mapeamento de ícones para cada solução const SOLUTION_ICONS: Record> = { 'crm': UserGroupIcon, 'erp': ChartBarIcon, 'projetos': FolderIcon, 'helpdesk': LifebuoyIcon, 'pagamentos': CreditCardIcon, 'contratos': DocumentTextIcon, 'documentos': ArchiveBoxIcon, 'social': ShareIcon, }; const STATUS_OPTIONS = [ { id: 'all', name: 'Todos os Status' }, { id: 'active', name: 'Ativas' }, { id: 'inactive', name: 'Inativas' }, ]; const DATE_PRESETS = [ { id: 'all', name: 'Todo o período' }, { id: '7d', name: 'Últimos 7 dias' }, { id: '15d', name: 'Últimos 15 dias' }, { id: '30d', name: 'Últimos 30 dias' }, { id: 'custom', name: 'Personalizado' }, ]; export default function AgenciesPage() { const toast = useToast(); const router = useRouter(); const [agencies, setAgencies] = useState([]); const [loading, setLoading] = useState(true); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); // Confirmação e seleção múltipla const [confirmOpen, setConfirmOpen] = useState(false); const [agencyToDelete, setAgencyToDelete] = useState(null); const [selectedIds, setSelectedIds] = useState>(new Set()); // Paginação const [currentPage, setCurrentPage] = useState(1); const itemsPerPage = 10; // Filtros const [searchTerm, setSearchTerm] = useState(''); const [selectedStatus, setSelectedStatus] = useState(STATUS_OPTIONS[0]); const [selectedDatePreset, setSelectedDatePreset] = useState(DATE_PRESETS[0]); const [startDate, setStartDate] = useState(''); const [endDate, setEndDate] = useState(''); useEffect(() => { fetchAgencies(); }, []); const fetchAgencies = async () => { try { const response = await fetch('/api/admin/agencies', { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}`, }, }); if (response.ok) { const data = await response.json(); setAgencies(data); } } catch (error) { console.error('Error fetching agencies:', error); } finally { setLoading(false); } }; const handleDeleteClick = (id: string) => { setAgencyToDelete(id); setConfirmOpen(true); }; const handleConfirmDelete = async () => { if (!agencyToDelete) return; try { const response = await fetch(`/api/admin/agencies/${agencyToDelete}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}`, }, }); if (response.ok) { setAgencies(agencies.filter(a => a.id !== agencyToDelete)); selectedIds.delete(agencyToDelete); setSelectedIds(new Set(selectedIds)); toast.success('Agência excluída', 'A agência foi excluída com sucesso.'); } else { toast.error('Erro ao excluir', 'Não foi possível excluir a agência.'); } } catch (error) { console.error('Error deleting agency:', error); toast.error('Erro ao excluir', 'Ocorreu um erro ao excluir a agência.'); } }; const handleDeleteSelected = () => { if (selectedIds.size === 0) return; setAgencyToDelete('multiple'); setConfirmOpen(true); }; const handleConfirmDeleteMultiple = async () => { const idsToDelete = Array.from(selectedIds); let successCount = 0; for (const id of idsToDelete) { try { const response = await fetch(`/api/admin/agencies/${id}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}`, }, }); if (response.ok) successCount++; } catch (error) { console.error('Error deleting agency:', error); } } setAgencies(agencies.filter(a => !selectedIds.has(a.id))); setSelectedIds(new Set()); toast.success(`${successCount} agência(s) excluída(s)`, 'As agências selecionadas foram excluídas.'); }; const toggleActive = async (id: string, currentStatus: boolean) => { try { const response = await fetch(`/api/admin/agencies/${id}`, { method: 'PATCH', headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ is_active: !currentStatus }), }); if (response.ok) { setAgencies(agencies.map(a => a.id === id ? { ...a, is_active: !currentStatus } : a )); } } catch (error) { console.error('Error toggling agency status:', error); } }; const clearFilters = () => { setSearchTerm(''); setSelectedStatus(STATUS_OPTIONS[0]); setSelectedDatePreset(DATE_PRESETS[0]); setStartDate(''); setEndDate(''); }; // Lógica de Filtragem const filteredAgencies = agencies.filter((agency) => { // Texto const searchLower = searchTerm.toLowerCase(); const matchesSearch = (agency.name?.toLowerCase() || '').includes(searchLower) || (agency.email?.toLowerCase() || '').includes(searchLower) || (agency.subdomain?.toLowerCase() || '').includes(searchLower); // Status const matchesStatus = selectedStatus.id === 'all' ? true : selectedStatus.id === 'active' ? agency.is_active : !agency.is_active; // Data let matchesDate = true; const agencyDate = new Date(agency.created_at); const now = new Date(); if (selectedDatePreset.id === 'custom') { if (startDate) { const start = new Date(startDate); start.setHours(0, 0, 0, 0); if (agencyDate < start) matchesDate = false; } if (endDate) { const end = new Date(endDate); end.setHours(23, 59, 59, 999); if (agencyDate > end) matchesDate = false; } } else if (selectedDatePreset.id !== 'all') { const diffTime = Math.abs(now.getTime() - agencyDate.getTime()); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); if (selectedDatePreset.id === '7d') matchesDate = diffDays <= 7; if (selectedDatePreset.id === '15d') matchesDate = diffDays <= 15; if (selectedDatePreset.id === '30d') matchesDate = diffDays <= 30; } return matchesSearch && matchesStatus && matchesDate; }); // Paginação const totalItems = filteredAgencies.length; const totalPages = Math.ceil(totalItems / itemsPerPage); const paginatedAgencies = filteredAgencies.slice( (currentPage - 1) * itemsPerPage, currentPage * itemsPerPage ); // Seleção múltipla const toggleSelectAll = () => { if (selectedIds.size === paginatedAgencies.length) { setSelectedIds(new Set()); } else { setSelectedIds(new Set(paginatedAgencies.map(a => a.id))); } }; const toggleSelect = (id: string) => { const newSelected = new Set(selectedIds); if (newSelected.has(id)) { newSelected.delete(id); } else { newSelected.add(id); } setSelectedIds(newSelected); }; return (
{/* Header */}

Agências

Gerencie seus parceiros e acompanhe o desempenho.

{selectedIds.size > 0 && ( )}
{/* Toolbar de Filtros */}
{/* Busca */}
setSearchTerm(e.target.value)} />
{/* Filtro de Status */}
{selectedStatus.name} {STATUS_OPTIONS.map((status, statusIdx) => ( `relative cursor-default select-none py-2 pl-10 pr-4 ${active ? 'bg-zinc-100 dark:bg-zinc-700 text-zinc-900 dark:text-white' : 'text-zinc-900 dark:text-zinc-100' }` } value={status} > {({ selected }) => ( <> {status.name} {selected ? ( ) : null} )} ))}
{/* Filtro de Data Unificado */} {selectedDatePreset.id === 'custom' ? (startDate && endDate ? `${new Date(startDate).toLocaleDateString()} - ${new Date(endDate).toLocaleDateString()}` : 'Selecionar período') : selectedDatePreset.name}
{DATE_PRESETS.filter(p => p.id !== 'custom').map((preset) => ( {({ active }) => ( )} ))}
Personalizado
{ setStartDate(e.target.value); setSelectedDatePreset(DATE_PRESETS.find(p => p.id === 'custom')!); }} className="block w-full px-2 py-1 text-xs border border-zinc-200 dark:border-zinc-700 rounded bg-zinc-50 dark:bg-zinc-800 text-zinc-900 dark:text-zinc-100 focus:outline-none focus:border-[var(--brand-color)]" />
{ setEndDate(e.target.value); setSelectedDatePreset(DATE_PRESETS.find(p => p.id === 'custom')!); }} className="block w-full px-2 py-1 text-xs border border-zinc-200 dark:border-zinc-700 rounded bg-zinc-50 dark:bg-zinc-800 text-zinc-900 dark:text-zinc-100 focus:outline-none focus:border-[var(--brand-color)]" />
{/* Botão Limpar */} {(searchTerm || selectedStatus.id !== 'all' || selectedDatePreset.id !== 'all') && ( )}
{/* Tabela */} {loading ? (
) : filteredAgencies.length === 0 ? (

Nenhuma agência encontrada

Não encontramos resultados para os filtros selecionados. Tente limpar a busca ou alterar os filtros.

) : (
{paginatedAgencies.map((agency) => ( { // Não navegar se clicar no checkbox, botões ou links if ( (e.target as HTMLElement).closest('input[type="checkbox"]') || (e.target as HTMLElement).closest('button') || (e.target as HTMLElement).closest('a') ) { return; } router.push(`/superadmin/agencies/${agency.id}`); }} className="group hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors cursor-pointer" > ))}
0} onChange={toggleSelectAll} className="w-4 h-4 rounded border-zinc-300 dark:border-zinc-600" style={{ accentColor: 'var(--brand-color)' }} /> Agência Contato Plano Soluções Status Data Cadastro Ações
e.stopPropagation()}> toggleSelect(agency.id)} className="w-4 h-4 rounded border-zinc-300 dark:border-zinc-600" style={{ accentColor: 'var(--brand-color)' }} />
{agency.logo_url ? ( {agency.name} ) : (
{agency.name?.substring(0, 2).toUpperCase()}
)}
{agency.email} {agency.phone || 'Sem telefone'}
{agency.plan_name ? ( {agency.plan_name} ) : ( Sem plano )} {agency.solutions && agency.solutions.length > 0 ? (
{agency.solutions.slice(0, 3).map((solution) => { const Icon = SOLUTION_ICONS[solution.slug] || FolderIcon; return ( {solution.name} ); })} {agency.solutions.length > 3 && ( +{agency.solutions.length - 3} )}
) : ( Sem soluções )}
e.stopPropagation()}> {new Date(agency.created_at).toLocaleDateString('pt-BR', { day: '2-digit', month: 'short', year: 'numeric' })} e.stopPropagation()}>
{({ active }) => ( Detalhes )} {({ active }) => ( Editar )}
{({ active }) => ( )}
)} setConfirmOpen(false)} onConfirm={agencyToDelete === 'multiple' ? handleConfirmDeleteMultiple : handleConfirmDelete} title={agencyToDelete === 'multiple' ? `Excluir ${selectedIds.size} agências` : 'Excluir agência'} message={agencyToDelete === 'multiple' ? `Tem certeza que deseja excluir ${selectedIds.size} agências? Esta ação não pode ser desfeita.` : 'Tem certeza que deseja excluir esta agência? Esta ação não pode ser desfeita.'} confirmText="Excluir" cancelText="Cancelar" variant="danger" /> setIsCreateModalOpen(false)} onSuccess={fetchAgencies} />
); }