import React, { useState, useEffect, useMemo } from 'react';
import ReactDOM from 'react-dom/client';
import {
LayoutDashboard, MessageSquare, Users, Kanban, CheckSquare, Settings,
ShieldAlert, LogOut, Bell, Search, Plus, Filter, MoreVertical, Send,
ArrowRight, CheckCircle2, XCircle, Clock, AlertCircle, TrendingUp,
Building2, UserPlus, Trash2, Edit3, Save, X, ChevronRight, UserCheck
} from 'lucide-react';
import {
BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer,
AreaChart, Area, PieChart, Pie, Cell
} from 'recharts';
// --- TYPES ---
type UserRole = 'DEVELOPER' | 'DIRECTOR' | 'MANAGER' | 'CONSULTANT';
interface User { id: string; companyId: string; name: string; email: string; role: UserRole; teamId?: string; active: boolean; }
interface Contact { id: string; companyId: string; name: string; phone: string; email: string; type: string; allowAI: boolean; companyName?: string; assignedUserId?: string; status: string; extension?: string; stageId: string; }
interface Stage { id: string; name: string; order: number; noReplyTimeout: number; routingMode: string; isMandatory?: boolean; }
interface Company { id: string; name: string; active: boolean; userLimit: number; memoryLimitGb: number; }
// --- CONSTANTS ---
const COLORS = { primary: '#ff7a59', secondary: '#2d3e50', success: '#00a4bd', warning: '#f5c26b' };
// --- SHARED COMPONENTS ---
const Badge = ({ children, color = 'gray' }: any) => {
const colors: any = {
orange: 'bg-orange-50 text-orange-600 border-orange-100',
blue: 'bg-blue-50 text-blue-600 border-blue-100',
green: 'bg-green-50 text-green-600 border-green-100',
gray: 'bg-gray-50 text-gray-600 border-gray-100',
red: 'bg-red-50 text-red-600 border-red-100'
};
return {children};
};
const Modal = ({ title, isOpen, onClose, children }: any) => {
if (!isOpen) return null;
return (
);
};
// --- PAGES ---
// 1. DASHBOARD
const DashboardPage = () => {
const data = [
{ name: 'Seg', v: 40 }, { name: 'Ter', v: 55 }, { name: 'Qua', v: 45 },
{ name: 'Qui', v: 70 }, { name: 'Sex', v: 60 }, { name: 'Sab', v: 30 }, { name: 'Dom', v: 20 }
];
return (
Visão Geral
Performance e KPIs da operação.
{[
{ label: 'Conversas Ativas', val: '154', icon:
, color: 'text-orange-500' },
{ label: 'Novos Leads', val: '24', icon: , color: 'text-blue-500' },
{ label: 'Tempo Médio', val: '3m 12s', icon: , color: 'text-green-500' },
{ label: 'Taxa Resposta', val: '94%', icon: , color: 'text-purple-500' },
].map((s, i) => (
{s.icon}
+12%
{s.label}
{s.val}
))}
Ranking Performance
{['Bruno Silva', 'Alice Souza', 'Daniel Bueno'].map((name, i) => (
))}
);
};
// 2. KANBAN
interface KanbanProps {
stages: Stage[];
contacts: Contact[];
onMove: (contactId: string, newStageId: string) => void;
onEdit: (contact: Contact) => void;
}
const KanbanPage = ({ stages, contacts, onMove, onEdit }: KanbanProps) => {
const [draggedId, setDraggedId] = useState(null);
const handleDragStart = (e: React.DragEvent, id: string) => {
setDraggedId(id);
e.dataTransfer.setData('contactId', id);
e.dataTransfer.effectAllowed = 'move';
};
const handleDragOver = (e: React.DragEvent) => {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
};
const handleDrop = (e: React.DragEvent, stageId: string) => {
e.preventDefault();
const contactId = e.dataTransfer.getData('contactId');
if (contactId) {
onMove(contactId, stageId);
}
setDraggedId(null);
};
return (
Pipeline de Atendimento
Arraste os cards para mudar o status.
{(stages || []).sort((a, b) => a.order - b.order).map(stage => (
handleDrop(e, stage.id)}
className="kanban-column flex flex-col bg-slate-100/50 rounded-[2.5rem] p-4 border border-slate-200/50"
>
{stage.name}
{contacts.filter(c => c.stageId === stage.id).length}
{contacts
.filter(c => c.stageId === stage.id)
.map((c) => (
handleDragStart(e, c.id)}
onClick={() => onEdit(c)}
className={`bg-white p-5 rounded-3xl border border-slate-200 shadow-sm hover:border-orange-500/40 cursor-grab active:cursor-grabbing transition-all hover:shadow-lg group relative ${draggedId === c.id ? 'opacity-40 grayscale' : ''}`}
>
{c.type || 'Geral'}
{c.name}
{c.companyName || 'S/ Empresa'}
))}
{contacts.filter(c => c.stageId === stage.id).length === 0 && (
Vazio
)}
))}
);
};
// 3. CONTACTS
const ContactsPage = ({ contacts, onEdit }: { contacts: Contact[], onEdit: (c?: Contact) => void }) => {
const [searchTerm, setSearchTerm] = useState('');
const filtered = contacts.filter(c => c.name.toLowerCase().includes(searchTerm.toLowerCase()));
return (
Base de Contatos
Controle total dos seus leads.
| Contato |
Empresa |
Etapa |
IA |
|
{filtered.map(c => (
|
|
{c.companyName || '-'}
|
{c.stageId.toUpperCase()}
|
|
|
))}
);
};
// 4. SETTINGS
const SettingsPage = ({ stages }: { stages: Stage[] }) => {
const [activeTab, setActiveTab] = useState<'pipeline' | 'teams' | 'fields' | 'webhooks'>('pipeline');
return (
Configurações
Ajustes e personalização da plataforma.
{['pipeline', 'teams', 'fields', 'webhooks'].map(tab => (
))}
{activeTab === 'pipeline' && (
Etapas do Funil
{stages.map(stage => (
{stage.order}
{stage.name}
{stage.routingMode}
{stage.isMandatory && Obrigatória}
))}
)}
);
};
// 5. SUPER ADMIN
const SuperAdminPage = ({ companies }: { companies: Company[] }) => {
return (
Painel SaaS Adm
Controle central de empresas e usuários.
Empresas Ativas
| Empresa |
Usuários |
Status |
|
{companies.map(co => (
|
{co.name}
Plano Premium
|
{co.userLimit} |
{co.active ? 'Ativo' : 'Suspenso'}
|
|
))}
Convidar Adm
Acesso exclusivo para desenvolvedores de sistema.
);
};
// --- APP ROOT ---
const App = () => {
const [user, setUser] = useState(null);
const [tab, setTab] = useState('dashboard');
const [isModalOpen, setIsModalOpen] = useState(false);
const [editingContact, setEditingContact] = useState(null);
const [data, setData] = useState({
users: [],
contacts: [
{ id: 'c1', name: 'João Silva', phone: '11 99999-0001', companyName: 'Logística S.A', allowAI: true, status: 'IN_PROGRESS', type: 'Venda', stageId: 's1', email: 'joao@log.com' },
{ id: 'c2', name: 'Maria Souza', phone: '11 98888-0002', companyName: 'Tech Inovação', allowAI: false, status: 'NO_REPLY', type: 'Suporte', stageId: 's2', email: 'maria@tech.com' },
{ id: 'c3', name: 'Daniel Bueno', phone: '11 97777-0003', companyName: 'Studio DB', allowAI: true, status: 'IN_PROGRESS', type: 'Venda', stageId: 's1', email: 'daniel@studio.com' }
],
stages: [
{ id: 's1', name: 'Novo Contato', order: 1, routingMode: 'CAROUSEL' },
{ id: 's2', name: 'Em Atendimento', order: 2, routingMode: 'DEMAND' },
{ id: 's3', name: 'Aguardando Cliente', order: 3, routingMode: 'PORTFOLIO' },
{ id: 's4', name: 'Finalizado', order: 4, routingMode: 'MANAGER' }
],
companies: [
{ id: 'co-1', name: 'LOX Tech Solutions', active: true, userLimit: 50, memoryLimitGb: 10 },
{ id: 'co-2', name: 'Braun Energia', active: true, userLimit: 5, memoryLimitGb: 2 }
]
});
const handleLogin = (email: string, pass: string) => {
if (email === 'daniel.bueno.studio@gmail.com' && pass === '123456') {
setUser({ id: 'u-1', companyId: 'co-1', name: 'Daniel Bueno', email, role: 'DEVELOPER', active: true });
} else {
alert("Credenciais de teste: daniel.bueno.studio@gmail.com / 123456");
}
};
const moveContact = (contactId: string, newStageId: string) => {
setData(prev => ({
...prev,
contacts: prev.contacts.map(c => c.id === contactId ? { ...c, stageId: newStageId } : c)
}));
};
const openEdit = (contact?: Contact) => {
setEditingContact(contact || { id: '', companyId: '', name: '', phone: '', email: '', type: 'Venda', allowAI: false, status: 'IN_PROGRESS', stageId: 's1' });
setIsModalOpen(true);
};
const saveContact = (e: React.FormEvent) => {
e.preventDefault();
if (!editingContact) return;
if (editingContact.id) {
setData(prev => ({
...prev,
contacts: prev.contacts.map(c => c.id === editingContact.id ? editingContact : c)
}));
} else {
const newId = 'c' + (data.contacts.length + 1);
setData(prev => ({
...prev,
contacts: [...prev.contacts, { ...editingContact, id: newId }]
}));
}
setIsModalOpen(false);
};
if (!user) {
// Reusing the inline login style for simplicity since we're in one file
return (
L
LOX Atendimentos
CRM & Gestão de Atendimento
Acesso de Desenvolvedor • Versão 1.2
);
}
const menu = [
{ id: 'dashboard', label: 'Início', icon: , roles: ['DEVELOPER', 'DIRECTOR', 'MANAGER', 'CONSULTANT'] },
{ id: 'kanban', label: 'CRM Kanban', icon: , roles: ['DEVELOPER', 'DIRECTOR', 'MANAGER', 'CONSULTANT'] },
{ id: 'contacts', label: 'Contatos', icon: , roles: ['DEVELOPER', 'DIRECTOR', 'MANAGER', 'CONSULTANT'] },
{ id: 'settings', label: 'Ajustes', icon: , roles: ['DEVELOPER', 'DIRECTOR'] },
{ id: 'admin', label: 'SaaS Adm', icon: , roles: ['DEVELOPER'] },
];
const visibleMenu = menu.filter(m => m.roles.includes(user.role));
return (
{tab === 'dashboard' && }
{tab === 'kanban' && }
{tab === 'contacts' && }
{tab === 'settings' && }
{tab === 'admin' && }
setIsModalOpen(false)}>
);
};
// --- INITIALIZE ---
const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render();