- O login foi realizado, mas um administrador ainda precisa vincular seu usuario a um
- perfil de acesso e a uma area operacional antes de liberar a plataforma.
+ O login foi realizado, mas um administrador ainda precisa vincular seu usuário a um
+ perfil de acesso e uma especialidade operacional antes de liberar a plataforma.
@@ -63,8 +63,8 @@ export function UnassignedHomePage() {
gap: '0.65rem',
}}
>
-
+ {children}
+
+ );
+}
+
+function HourlyLineChart({ values }) {
+ const labels = ['08h', '09h', '10h', '11h', '12h', '13h', '14h', '15h', '16h', '17h', '18h'];
+ const maxValue = Math.max(...values, 1);
+ const points = values
+ .map((value, index) => {
+ const x = (index / (values.length - 1)) * 100;
+ const y = 100 - (value / maxValue) * 78 - 10;
+ return `${x},${y}`;
+ })
+ .join(' ');
+
+ return (
+
+
+
+
+
+ {labels.map((label) => (
+ {label}
+ ))}
+
+
+ );
+}
+
+export function OperationalDashboard({ isDesktop, isMobile }) {
+ const [selectedArea, setSelectedArea] = useState('all');
+ const [assignmentTarget, setAssignmentTarget] = useState(null);
+ const data = operationMockByArea[selectedArea] || operationMockByArea.all;
+
+ const onlineAgents = useMemo(
+ () => data.team.filter((agent) => agent.status === 'online'),
+ [data.team],
+ );
+
+ const sortedQueue = useMemo(
+ () => [...data.queue].sort((a, b) => b.waitingMinutes - a.waitingMinutes),
+ [data.queue],
+ );
+
+ return (
+
+
+
+ Filtro por especialidade
+ setSelectedArea(event.target.value)} style={selectStyle}>
+ {areaOptions.map((area) => (
+ {area.label}
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+ Nome
+ Status
+ Atendimentos abertos
+ Último finalizado há
+
+
+
+ {data.team.map((agent) => (
+
+ {agent.name}
+
+ {statusMeta[agent.status].label}
+
+ {agent.open}
+ {agent.lastClosed}
+
+ ))}
+
+
+
+
+
+
+
+ {sortedQueue.map((item) => (
+
+ {item.channel}
+
+ {item.contact}
+
+ Aguardando há {item.waitingMinutes} min
+
+
+ setAssignmentTarget(item)}
+ style={{
+ border: 'none',
+ borderRadius: 12,
+ padding: '0.65rem 0.8rem',
+ background: 'var(--color-primary)',
+ color: '#fff',
+ fontWeight: 800,
+ }}
+ >
+ Atribuir
+
+
+ ))}
+
+
+
+
+
+
+
+
+ {assignmentTarget ? (
+
+
+
+
Atribuir atendimento
+
+ Selecione um atendente online para {assignmentTarget.contact}.
+
+
+
+ {onlineAgents.length ? onlineAgents.map((agent) => (
+ setAssignmentTarget(null)}
+ style={{
+ border: '1px solid var(--color-border)',
+ borderRadius: 14,
+ padding: '0.8rem 0.9rem',
+ background: '#fff',
+ color: 'var(--color-text)',
+ fontWeight: 800,
+ textAlign: 'left',
+ }}
+ >
+ {agent.name}
+
+ )) : (
+ Nenhum atendente online nesta especialidade.
+ )}
+
+
setAssignmentTarget(null)}
+ style={{
+ border: 'none',
+ borderRadius: 14,
+ padding: '0.8rem 1rem',
+ background: 'rgba(0, 49, 80, 0.08)',
+ color: 'var(--color-primary)',
+ fontWeight: 800,
+ }}
+ >
+ Fechar
+
+
+
+ ) : null}
+
+ );
+}
diff --git a/src/modules/management/pages/AdminPage.jsx b/src/modules/management/pages/AdminPage.jsx
index 8952df1..1317900 100644
--- a/src/modules/management/pages/AdminPage.jsx
+++ b/src/modules/management/pages/AdminPage.jsx
@@ -3,22 +3,25 @@ import { DataPanel } from '../components/DataPanel';
import { ManagementLayout } from '../components/ManagementLayout';
import { ManagementTable } from '../components/ManagementTable';
import { MetricGrid } from '../components/MetricGrid';
+import { OperationalDashboard } from '../components/OperationalDashboard';
import { aiContentRows, areaRows, userRows } from '../services/managementMocks';
+import { AttendantOpsPanel } from '../../home/components/AttendantOpsPanel';
+import { MessagesWorkspace } from '../../home/components/MessagesWorkspace';
+import { useChat } from '../../chat/hooks/useChat';
import {
createAccessArea,
getAccessAreas,
getAccessOptions,
getAccessUsers,
getAdminOverview,
- updateAccessArea,
updateUserAccess,
} from '../services/adminAccessService';
import { useViewport } from '../../../shared/hooks/useViewport';
import { getCurrentUserDisplay } from '../../auth/services/sessionService';
const contentColumns = [
- { key: 'title', label: 'Conteudo' },
- { key: 'area', label: 'Area' },
+ { key: 'title', label: 'Conteúdo' },
+ { key: 'area', label: 'Especialidade' },
{ key: 'status', label: 'Status' },
{ key: 'updatedAt', label: 'Atualizado' },
];
@@ -33,12 +36,19 @@ const selectStyle = {
fontWeight: 600,
};
+const compactSelectStyle = {
+ ...selectStyle,
+ borderRadius: '10px',
+ padding: '0.45rem 0.55rem',
+ fontSize: '0.82rem',
+};
+
const monthlyKpis = [
- { label: 'Total de Atendimentos', value: '1.284', detail: '+12% vs mes anterior' },
- { label: 'Tempo Medio de Atendimento', value: '8m 42s', detail: 'media mensal' },
- { label: 'Taxa de Satisfacao', value: '91%', detail: 'avaliacoes positivas' },
+ { label: 'Total de Atendimentos', value: '1.284', detail: '+12% vs mês anterior' },
+ { label: 'Tempo Médio de Atendimento', value: '8m 42s', detail: 'média mensal' },
+ { label: 'Taxa de Satisfação', value: '91%', detail: 'avaliações positivas' },
{ label: 'Volume por Canal', value: 'W 982 · E 184 · S 118', detail: 'WhatsApp · Email · SMS' },
- { label: 'Atendentes Ativos', value: '14 de 17', detail: 'ativos no mes' },
+ { label: 'Atendentes Ativos', value: '14 de 17', detail: 'ativos no mês' },
];
const dailyAttendance = [28, 34, 42, 39, 51, 47, 58, 62, 55, 69, 73, 66, 71, 88, 79, 84, 91, 86, 94, 101, 97, 108, 112, 104, 118, 123, 116, 129, 134, 141];
@@ -82,8 +92,81 @@ function formatMinutes(minutes) {
return `${Number(minutes)} min`;
}
+function toHomeConversation(contact, messages = []) {
+ return {
+ id: contact.id,
+ name: contact.name,
+ channel: contact.channel || 'WhatsApp',
+ status: contact.status || 'online',
+ lastMessage: contact.preview || messages[messages.length - 1]?.text || '',
+ unread: contact.unread || 0,
+ time: contact.time || 'Agora',
+ lastSeen: contact.lastSeen,
+ messages: messages.map((message) => ({
+ id: message.id,
+ from: message.sender === 'agent' ? 'agent' : 'customer',
+ text: message.text || (message.hasMedia ? '[Mídia]' : ''),
+ timestamp: message.timestamp,
+ })),
+ };
+}
+
+function AdminAttendanceWorkspace({ isWideDesktop, isDesktop, isTablet, isMobile }) {
+ const {
+ contacts,
+ activeContactId,
+ setActiveContactId,
+ messages,
+ sendMessage,
+ isLoadingChats,
+ } = useChat();
+
+ const conversations = contacts.map((contact) =>
+ toHomeConversation(contact, contact.id === activeContactId ? messages : []),
+ );
+
+ const safeConversationId =
+ conversations.find((conversation) => conversation.id === activeContactId)?.id ||
+ conversations[0]?.id;
+
+ return (
+
+
+
+ {isLoadingChats ? (
+
+ Atualizando conversas do WhatsApp...
+
+ ) : null}
+
+ {
+ setActiveContactId(conversationId);
+ await sendMessage(reply, conversationId);
+ }}
+ isWideDesktop={isWideDesktop}
+ isDesktop={isDesktop}
+ isTablet={isTablet}
+ isMobile={isMobile}
+ />
+
+ );
+}
+
export function AdminPage() {
- const { isDesktop, isMobile } = useViewport();
+ const { isWideDesktop, isDesktop, isTablet, isMobile } = useViewport();
const userDisplay = getCurrentUserDisplay();
const [activeAdminSection, setActiveAdminSection] = useState('home');
const [selectedAreaFilter, setSelectedAreaFilter] = useState('all');
@@ -96,9 +179,12 @@ export function AdminPage() {
const [areaRowsState, setAreaRowsState] = useState(areaRows);
const [userSearch, setUserSearch] = useState('');
const [newAreaName, setNewAreaName] = useState('');
- const [newAreaOwnerId, setNewAreaOwnerId] = useState('');
const [isLoadingAccess, setIsLoadingAccess] = useState(true);
const [accessError, setAccessError] = useState('');
+ const [editingUser, setEditingUser] = useState(null);
+ const [editUserProfileId, setEditUserProfileId] = useState('');
+ const [editUserSpecialties, setEditUserSpecialties] = useState([]);
+ const [specialtyToAdd, setSpecialtyToAdd] = useState('');
useEffect(() => {
let isMounted = true;
@@ -140,30 +226,35 @@ export function AdminPage() {
};
}, []);
- async function handleAccessChange(user, field, value) {
- const currentPerfilId = user.perfilPrincipal?.id || null;
- const currentAreaId = user.areaPrincipal?.id || null;
- const nextAccess = {
- perfilId: field === 'perfil' ? Number(value) || null : currentPerfilId,
- areaId: field === 'area' ? Number(value) || null : currentAreaId,
- };
+ function openUserEditor(user) {
+ setEditingUser(user);
+ setEditUserProfileId(user.perfilPrincipal?.id ? String(user.perfilPrincipal.id) : '');
+ setEditUserSpecialties(Array.isArray(user.areas) ? user.areas : []);
+ setSpecialtyToAdd('');
+ }
- setUsers((current) =>
- current.map((item) =>
- item.id === user.id
- ? {
- ...item,
- perfilPrincipal:
- profiles.find((profile) => profile.id === nextAccess.perfilId) || null,
- areaPrincipal: areas.find((area) => area.id === nextAccess.areaId) || null,
- accessStatus: nextAccess.perfilId && nextAccess.areaId ? 'assigned' : 'unassigned',
- }
- : item,
- ),
- );
+ function closeUserEditor() {
+ setEditingUser(null);
+ setEditUserProfileId('');
+ setEditUserSpecialties([]);
+ setSpecialtyToAdd('');
+ }
+ function getProfileName(profileId) {
+ return profiles.find((profile) => profile.id === Number(profileId))?.nome || '';
+ }
+
+ async function saveUserAccess(user, nextProfileId, nextSpecialties) {
try {
- const updatedUser = await updateUserAccess(user.id, nextAccess);
+ const updatedUser = await updateUserAccess(user.id, {
+ perfilIds: nextProfileId ? [Number(nextProfileId)] : [],
+ especialidades: nextSpecialties.map((specialty, index) => ({
+ areaId: Number(specialty.id),
+ funcao: specialty.funcao || 'Agente',
+ principal: index === 0,
+ ativo: true,
+ })),
+ });
if (updatedUser) {
setUsers((current) =>
@@ -172,11 +263,53 @@ export function AdminPage() {
}
setAccessError('');
+ await refreshAreas();
} catch {
- setAccessError('Nao foi possivel salvar a atribuicao. Confira o backend.');
+ setAccessError('Não foi possível salvar a atribuição. Confira o backend.');
}
}
+ function handleEditProfileChange(value) {
+ setEditUserProfileId(value);
+ if (getProfileName(value) === 'Admin') {
+ setEditUserSpecialties([]);
+ setSpecialtyToAdd('');
+ }
+ }
+
+ function addSpecialtyToEdit() {
+ const area = areas.find((item) => item.id === Number(specialtyToAdd));
+ if (!area) return;
+
+ setEditUserSpecialties((current) => {
+ if (current.some((specialty) => specialty.id === area.id)) return current;
+ return [
+ ...current,
+ { id: area.id, nome: area.nome, funcao: 'Agente', principal: current.length === 0 },
+ ];
+ });
+ setSpecialtyToAdd('');
+ }
+
+ function removeSpecialtyFromEdit(areaId) {
+ setEditUserSpecialties((current) => current.filter((specialty) => specialty.id !== areaId));
+ }
+
+ function updateEditSpecialtyRole(areaId, role) {
+ setEditUserSpecialties((current) =>
+ current.map((specialty) =>
+ specialty.id === areaId ? { ...specialty, funcao: role } : specialty,
+ ),
+ );
+ }
+
+ async function submitUserEditor() {
+ if (!editingUser) return;
+ const isAdmin = getProfileName(editUserProfileId) === 'Admin';
+ await saveUserAccess(editingUser, editUserProfileId, isAdmin ? [] : editUserSpecialties);
+ closeUserEditor();
+ }
+
async function refreshAreas() {
const [accessAreas, options] = await Promise.all([getAccessAreas(), getAccessOptions()]);
setAreaRowsState(accessAreas || []);
@@ -190,28 +323,12 @@ export function AdminPage() {
try {
await createAccessArea({
nome,
- responsavelUsuarioId: Number(newAreaOwnerId) || null,
});
setNewAreaName('');
- setNewAreaOwnerId('');
await refreshAreas();
setAccessError('');
} catch {
- setAccessError('Nao foi possivel criar a area.');
- }
- }
-
- async function handleAreaOwnerChange(areaId, userId) {
- try {
- await updateAccessArea(areaId, {
- responsavelUsuarioId: Number(userId) || null,
- });
- await refreshAreas();
- const accessUsers = await getAccessUsers();
- setUsers(accessUsers || []);
- setAccessError('');
- } catch {
- setAccessError('Nao foi possivel atualizar o responsavel da area.');
+ setAccessError('Não foi possível criar a especialidade.');
}
}
@@ -220,18 +337,18 @@ export function AdminPage() {
label: 'Total de Atendimentos',
value: overview ? String(overview.totalAttendances) : '...',
detail: overview?.previousMonthVariation === null || overview?.previousMonthVariation === undefined
- ? 'sem base do mes anterior'
- : `${overview.previousMonthVariation >= 0 ? '+' : ''}${overview.previousMonthVariation}% vs mes anterior`,
+ ? 'sem base do mês anterior'
+ : `${overview.previousMonthVariation >= 0 ? '+' : ''}${overview.previousMonthVariation}% vs mês anterior`,
},
{
label: 'TMA',
value: formatMinutes(overview?.avgHandlingMinutes),
- detail: overview?.avgHandlingMinutes === null ? 'aguardando historico' : 'media mensal',
+ detail: overview?.avgHandlingMinutes === null ? 'aguardando histórico' : 'média mensal',
},
{
label: 'TME',
value: formatMinutes(overview?.avgFirstResponseMinutes),
- detail: 'tempo medio de espera',
+ detail: 'tempo médio de espera',
},
{
label: 'TMR',
@@ -241,7 +358,7 @@ export function AdminPage() {
{
label: 'Atendentes Ativos',
value: overview ? `${overview.activeAttendants} de ${overview.totalActiveUsers}` : '...',
- detail: 'ativos no mes',
+ detail: 'ativos no mês',
},
];
@@ -252,6 +369,10 @@ export function AdminPage() {
.toLowerCase()
.includes(search);
});
+ const availableSpecialtiesToAdd = areas.filter(
+ (area) => !editUserSpecialties.some((specialty) => specialty.id === area.id),
+ );
+ const isEditingAdmin = getProfileName(editUserProfileId) === 'Admin';
const channelDistributionData = overview
? [
@@ -266,56 +387,12 @@ export function AdminPage() {
{
key: 'nome',
label: 'Usuario',
- render: (row) => (
-
- {row.nome}
-
- {row.email || 'Sem email'}
-
-
- ),
+ render: (row) =>
{row.nome} ,
},
{
key: 'perfil',
label: 'Perfil',
- render: (row) =>
- profiles.length ? (
-
handleAccessChange(row, 'perfil', event.target.value)}
- style={selectStyle}
- >
- Sem perfil
- {profiles.map((profile) => (
-
- {profile.nome}
-
- ))}
-
- ) : (
-
{row.perfilPrincipal?.nome || 'Sem perfil'}
- ),
- },
- {
- key: 'area',
- label: 'Area',
- render: (row) =>
- areas.length ? (
-
handleAccessChange(row, 'area', event.target.value)}
- style={selectStyle}
- >
- Sem area
- {areas.map((area) => (
-
- {area.nome}
-
- ))}
-
- ) : (
-
{row.areaPrincipal?.nome || 'Sem area'}
- ),
+ render: (row) =>
{row.perfilPrincipal?.nome || 'Sem perfil'} ,
},
{
key: 'status',
@@ -339,39 +416,70 @@ export function AdminPage() {
);
},
},
+ {
+ key: 'actions',
+ label: 'Ações',
+ render: (row) => (
+
openUserEditor(row)}
+ style={{
+ border: 'none',
+ borderRadius: 14,
+ padding: '0.7rem 0.9rem',
+ background: 'var(--color-primary)',
+ color: '#fff',
+ fontWeight: 800,
+ }}
+ >
+ Editar
+
+ ),
+ },
],
- [areas, profiles],
+ [],
);
const areaColumns = useMemo(
() => [
- { key: 'nome', label: 'Area' },
+ { key: 'nome', label: 'Especialidade' },
{
- key: 'responsavel',
- label: 'Responsavel',
- render: (row) => (
-
handleAreaOwnerChange(row.id, event.target.value)}
- style={selectStyle}
- >
- Sem responsavel
- {users.map((user) => (
-
- {user.nome}
-
- ))}
-
- ),
+ key: 'supervisores',
+ label: 'Supervisores',
+ render: (row) => {
+ const supervisors = Array.isArray(row.supervisores) ? row.supervisores : [];
+
+ return supervisors.length ? (
+
+ {supervisors.map((supervisor) => (
+
+ {supervisor.nome}
+
+ ))}
+
+ ) : (
+
Sem supervisor
+ );
+ },
},
- { key: 'members', label: 'Usuários' },
+ { key: 'members', label: 'Usuarios' },
{
key: 'status',
label: 'Status',
render: (row) => (row.ativo ? 'Ativa' : 'Inativa'),
},
],
- [users],
+ [],
);
const filteredRanking = selectedAreaFilter === 'all'
@@ -380,10 +488,10 @@ export function AdminPage() {
const rankingColumns = [
{ key: 'name', label: 'Nome' },
- { key: 'area', label: 'Area' },
+ { key: 'area', label: 'Especialidade' },
{ key: 'closed', label: 'Atendimentos finalizados' },
- { key: 'avgTime', label: 'Tempo medio' },
- { key: 'satisfaction', label: 'Satisfacao' },
+ { key: 'avgTime', label: 'Tempo médio' },
+ { key: 'satisfaction', label: 'Satisfação' },
];
function sendNotice() {
@@ -454,9 +562,9 @@ export function AdminPage() {
<>
- Filtro por area
+ Filtro por especialidade
setSelectedAreaFilter(event.target.value)} style={selectStyle}>
- Todas as areas
+ Todas as especialidades
{areas.map((area) => (
{area.nome}
))}
@@ -467,10 +575,10 @@ export function AdminPage() {
-
+
{renderLineChart()}
-
+
{renderDonutChart()}
@@ -511,7 +619,7 @@ export function AdminPage() {
setUserSearch(event.target.value)}
- placeholder="Buscar usuario por nome, email, perfil ou area"
+ placeholder="Buscar usuário por nome, email, perfil ou especialidade"
style={selectStyle}
/>
row.id} isMobile={isMobile} />
+
+ {editingUser ? (
+
+
+
+
+
Editar acesso
+
+ {editingUser.nome} · {editingUser.email || 'Sem email'}
+
+
+
+ Fechar
+
+
+
+
+ Perfil global
+ handleEditProfileChange(event.target.value)}
+ style={selectStyle}
+ >
+ Sem perfil
+ {profiles.map((profile) => (
+
+ {profile.nome}
+
+ ))}
+
+
+
+ {isEditingAdmin ? (
+
+ Admin tem acesso global. Especialidades não se aplicam para este perfil.
+
+ ) : (
+
+
+ setSpecialtyToAdd(event.target.value)}
+ style={selectStyle}
+ >
+ Selecionar especialidade
+ {availableSpecialtiesToAdd.map((area) => (
+
+ {area.nome}
+
+ ))}
+
+
+ Adicionar
+
+
+
+
+ {editUserSpecialties.length ? editUserSpecialties.map((specialty) => (
+
+ {specialty.nome}
+ updateEditSpecialtyRole(specialty.id, event.target.value)}
+ style={compactSelectStyle}
+ >
+ Agente
+ Supervisor
+
+ removeSpecialtyFromEdit(specialty.id)}
+ style={{
+ border: 'none',
+ borderRadius: 12,
+ padding: '0.55rem 0.7rem',
+ background: 'rgba(181, 31, 31, 0.1)',
+ color: 'var(--color-secondary)',
+ fontWeight: 800,
+ }}
+ >
+ Remover
+
+
+ )) : (
+
+ Nenhuma especialidade selecionada.
+
+ )}
+
+
+ )}
+
+
+ Salvar acesso
+
+
+
+ ) : null}
-
+
-
+
setNewAreaName(event.target.value)}
- placeholder="Nome da nova area"
+ placeholder="Nome da nova especialidade"
style={selectStyle}
/>
-
setNewAreaOwnerId(event.target.value)} style={selectStyle}>
- Responsavel opcional
- {users.map((user) => (
-
- {user.nome}
-
- ))}
-
- Secao em preparacao.
+ Seção em preparação.
);
@@ -591,7 +863,7 @@ export function AdminPage() {
const sectionContent = {
home: renderMonthlyHome(),
- today: renderPlaceholder('Operação', 'Visão operacional diaria sera consolidada aqui.'),
+ today: ,
'users-access': renderUsersAccess(),
templates: renderPlaceholder('Templates', 'Gestão de templates aprovados pela Meta.'),
knowledge: (
@@ -599,17 +871,41 @@ export function AdminPage() {
row.id} isMobile={isMobile} />
),
- audit: renderPlaceholder('Auditoria', 'Eventos administrativos e alteracoes sensiveis.'),
+ audit: renderPlaceholder('Auditoria', 'Eventos administrativos e alterações sensíveis.'),
channels: renderPlaceholder('Canais', 'Status e configurações dos canais conectados.'),
+ attendance: (
+
+ ),
'mass-message': renderPlaceholder('Disparo em massa', 'Fluxo de disparos por templates aprovados.'),
contacts: renderPlaceholder('Contatos', 'Agenda geral de contatos.'),
settings: renderPlaceholder('Configurações', 'Preferencias e parametros do ambiente.'),
};
+ const pageTitle = activeAdminSection === 'home'
+ ? 'Home do Admin'
+ : activeAdminSection === 'attendance'
+ ? 'Atendimento'
+ : activeAdminSection === 'today'
+ ? 'Operação'
+ : 'Painel administrativo';
+
+ const pageSubtitle = activeAdminSection === 'home'
+ ? 'Visão mensal consolidada por especialidade, canal e atendente.'
+ : activeAdminSection === 'attendance'
+ ? 'Home operacional do atendente dentro do painel administrativo.'
+ : activeAdminSection === 'today'
+ ? 'Indicadores do dia, fila de espera e acompanhamento operacional do time.'
+ : 'Controle operacional e configurações administrativas.';
+
return (
(
-
- {row.priority}
-
- ),
- },
-];
-
-const areaColumns = [
- { key: 'name', label: 'Area' },
- { key: 'owner', label: 'Responsavel' },
- { key: 'members', label: 'Usuarios' },
- { key: 'openTickets', label: 'Abertos' },
- { key: 'status', label: 'Status' },
-];
export function SupervisorPage() {
const { isDesktop, isMobile } = useViewport();
const userDisplay = getCurrentUserDisplay();
- const [templates, setTemplates] = useState([]);
- const [editingTemplate, setEditingTemplate] = useState(null);
- const [editName, setEditName] = useState('');
- const [editContent, setEditContent] = useState('');
- const [saveStatus, setSaveStatus] = useState('');
-
- const fetchTemplates = async () => {
- try {
- const res = await fetch(`${API_BASE_URL}/whatsapp/templates`);
- if (res.ok) {
- const data = await res.json();
- setTemplates(data);
- }
- } catch (err) {
- console.error(err);
- }
- };
-
- useEffect(() => {
- fetchTemplates();
- }, []);
-
- const handleEdit = (tpl) => {
- setEditingTemplate(tpl);
- setEditName(tpl.name);
- setEditContent(tpl.content);
- setSaveStatus('');
- };
-
- const handleSave = async (e) => {
- e.preventDefault();
- if (!editName || !editContent) return;
- try {
- const url = editingTemplate
- ? `${API_BASE_URL}/whatsapp/templates/update/${editingTemplate.id}`
- : `${API_BASE_URL}/whatsapp/templates`;
- const res = await fetch(url, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ name: editName, content: editContent }),
- });
- if (res.ok) {
- setSaveStatus('Salvo com sucesso!');
- setEditingTemplate(null);
- setEditName('');
- setEditContent('');
- fetchTemplates();
- setTimeout(() => setSaveStatus(''), 3000);
- } else {
- setSaveStatus('Erro ao salvar template.');
- }
- } catch (err) {
- console.error(err);
- setSaveStatus('Erro ao salvar template.');
- }
- };
return (
-
-
-
-
- row.id}
- isMobile={isMobile}
- />
-
-
-
- row.id}
- isMobile={isMobile}
- />
-
-
-
-
-
-
-
- {templates.map((tpl) => (
-
-
-
- {tpl.name}
-
-
- ✓ Homologado Meta
-
-
-
- {tpl.content}
-
-
- handleEdit(tpl)}
- style={{
- border: 'none',
- background: 'rgba(0, 49, 80, 0.08)',
- color: 'var(--color-primary)',
- padding: '0.45rem 0.85rem',
- borderRadius: '10px',
- fontSize: '0.82rem',
- fontWeight: 700,
- cursor: 'pointer',
- transition: 'background 0.2s',
- }}
- >
- Editar Modelo
-
-
-
- ))}
-
-
-
-
-
-
+
);
}
diff --git a/src/modules/management/services/managementMocks.js b/src/modules/management/services/managementMocks.js
index 706d71c..8bf517a 100644
--- a/src/modules/management/services/managementMocks.js
+++ b/src/modules/management/services/managementMocks.js
@@ -2,12 +2,12 @@ export const supervisorMetrics = [
{ label: 'Atendimentos abertos', value: '42', detail: '12 aguardando agente' },
{ label: 'SLA em risco', value: '7', detail: 'Financeiro concentra 4 casos' },
{ label: 'Agentes online', value: '18', detail: '3 em pausa operacional' },
- { label: 'Transferencias hoje', value: '23', detail: 'Tempo medio 4m 20s' },
+ { label: 'Transferências hoje', value: '23', detail: 'Tempo médio 4m 20s' },
];
export const adminMetrics = [
{ label: 'Usuários ativos', value: '64', detail: '8 supervisores configurados' },
- { label: 'Áreas cadastradas', value: '3', detail: 'Suporte, Financeiro e Comercial' },
+ { label: 'Especialidades cadastradas', value: '3', detail: 'Suporte, Financeiro e Comercial' },
{ label: 'Conteúdos IA', value: '28', detail: '6 aguardando revisão' },
{ label: 'Canais conectados', value: '1', detail: 'WhatsApp em homologação' },
];
@@ -100,7 +100,7 @@ export const aiContentRows = [
id: 'c3',
title: 'Argumentario de proposta comercial',
area: 'Comercial',
- status: 'Revisao',
+ status: 'Revisão',
updatedAt: 'Segunda',
},
];