import React, { useState, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { Building2, Users, MessageSquare, Plus, Search, Edit, Trash2, ChevronDown, ChevronUp, ChevronsUpDown, X, CheckCircle2, Loader2, LogIn } from 'lucide-react'; import { getTenants, createTenant, deleteTenant, updateTenant, impersonateTenant } from '../services/dataService'; import { Tenant } from '../types'; import { DateRangePicker } from '../components/DateRangePicker'; import { KPICard } from '../components/KPICard'; export const SuperAdmin: React.FC = () => { const navigate = useNavigate(); const [dateRange, setDateRange] = useState({ start: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), end: new Date() }); const [selectedTenantId, setSelectedTenantId] = useState('all'); const [searchQuery, setSearchQuery] = useState(''); const [tenants, setTenants] = useState([]); const [loading, setLoading] = useState(true); const [isModalOpen, setIsModalOpen] = useState(false); const [editingTenant, setEditingTenant] = useState(null); const [sortKey, setSortKey] = useState('created_at'); const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('desc'); const loadTenants = async () => { setLoading(true); const data = await getTenants(); setTenants(data); setLoading(false); }; React.useEffect(() => { loadTenants(); }, []); const totalTenants = tenants.length; const totalUsersGlobal = tenants.reduce((acc, t) => acc + (t.user_count || 0), 0); const totalAttendancesGlobal = tenants.reduce((acc, t) => acc + (t.attendance_count || 0), 0); const filteredTenants = useMemo(() => { let data = tenants; if (searchQuery) { const q = searchQuery.toLowerCase(); data = data.filter(t => t.name.toLowerCase().includes(q) || t.admin_email?.toLowerCase().includes(q) || t.slug?.toLowerCase().includes(q) ); } if (selectedTenantId !== 'all') { data = data.filter(t => t.id === selectedTenantId); } return [...data].sort((a, b) => { const aVal = a[sortKey]; const bVal = b[sortKey]; if (aVal === undefined) return 1; if (bVal === undefined) return -1; if (aVal < bVal) return sortDirection === 'asc' ? -1 : 1; if (aVal > bVal) return sortDirection === 'asc' ? 1 : -1; return 0; }); }, [tenants, searchQuery, selectedTenantId, sortKey, sortDirection]); const handleSort = (key: keyof Tenant) => { if (sortKey === key) { setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc'); } else { setSortKey(key); setSortDirection('asc'); } }; const handleEdit = (tenant: Tenant) => { setEditingTenant(tenant); setIsModalOpen(true); }; const handleDelete = async (id: string) => { if (id === 'system') { alert('A organização do sistema não pode ser excluída.'); return; } if (confirm('Tem certeza que deseja excluir esta organização? Esta ação não pode ser desfeita.')) { const success = await deleteTenant(id); if (success) { setTenants(prev => prev.filter(t => t.id !== id)); } else { alert('Erro ao excluir a organização do servidor.'); } } }; const handleImpersonate = async (tenantId: string) => { try { if (tenantId === 'system') { alert('Você já está na organização do sistema.'); return; } await impersonateTenant(tenantId); // Force a full reload to clear any cached context/state in the React app window.location.hash = '#/'; window.location.reload(); } catch (err: any) { alert(err.message || 'Erro ao tentar entrar na organização.'); } }; const [successMessage, setSuccessMessage] = useState(''); const [errorMessage, setErrorMessage] = useState(''); const [isSaving, setIsSaving] = useState(false); const handleSaveTenant = async (e: React.FormEvent) => { e.preventDefault(); setErrorMessage(''); setSuccessMessage(''); setIsSaving(true); const form = e.target as HTMLFormElement; const name = (form.elements.namedItem('name') as HTMLInputElement).value; const slug = (form.elements.namedItem('slug') as HTMLInputElement).value; const admin_email = (form.elements.namedItem('admin_email') as HTMLInputElement).value; const status = (form.elements.namedItem('status') as HTMLSelectElement).value; try { if (editingTenant) { const success = await updateTenant(editingTenant.id, { name, slug, admin_email, status }); if (success) { setSuccessMessage('Organização atualizada com sucesso!'); loadTenants(); setTimeout(() => { setIsModalOpen(false); setSuccessMessage(''); setEditingTenant(null); setIsSaving(false); }, 2000); } else { setErrorMessage('Erro ao atualizar organização.'); setIsSaving(false); } } else { const result = await createTenant({ name, slug, admin_email, status }); if (result.success) { setSuccessMessage(result.message || 'Organização criada com sucesso!'); loadTenants(); setTimeout(() => { setIsModalOpen(false); setSuccessMessage(''); setIsSaving(false); }, 3000); } else { setErrorMessage(result.message || 'Erro ao salvar organização.'); setIsSaving(false); } } } catch (err) { setErrorMessage('Ocorreu um erro inesperado.'); setIsSaving(false); } }; const SortIcon = ({ column }: { column: keyof Tenant }) => { if (sortKey !== column) return ; return sortDirection === 'asc' ? : ; }; const StatusBadge = ({ status }: { status?: string }) => { const styles = { active: 'bg-green-100 text-green-700 border-green-200 dark:bg-green-900/30 dark:text-green-400 dark:border-green-800', inactive: 'bg-zinc-100 text-zinc-700 border-zinc-200 dark:bg-dark-input dark:text-dark-muted dark:border-dark-border', trial: 'bg-purple-100 text-purple-700 border-purple-200 dark:bg-purple-900/30 dark:text-purple-400 dark:border-purple-800', }; const style = styles[status as keyof typeof styles] || styles.inactive; let label = status === 'active' ? 'Ativo' : status === 'inactive' ? 'Inativo' : status === 'trial' ? 'Teste' : 'Desconhecido'; return {label}; }; return (

Painel Super Admin

Gerencie organizações e visualize estatísticas globais.

{/* KPI Cards */}
setSearchQuery(e.target.value)} className="w-full pl-9 pr-4 py-2 bg-zinc-50 dark:bg-dark-bg border border-zinc-200 dark:border-dark-border rounded-lg text-sm text-zinc-900 dark:text-zinc-100 outline-none focus:ring-2 focus:ring-brand-yellow/20 transition-all" />
{filteredTenants.map((tenant) => ( ))}
handleSort('name')}>
Organização
Slug handleSort('status')}>
Status
handleSort('user_count')}>
Usuários
handleSort('attendance_count')}>
Atendimentos
Ações
{tenant.logo_url ? : }
{tenant.name}
{tenant.admin_email}
{tenant.slug} {tenant.user_count} {tenant.attendance_count?.toLocaleString()}
{tenant.id !== 'system' && ( )}
Mostrando {filteredTenants.length} de {tenants.length} organizações
{isModalOpen && (

{editingTenant ? 'Editar Organização' : 'Adicionar Nova Organização'}

{successMessage && (
{successMessage}
)} {errorMessage && (
{errorMessage}
)}
)}
); };