FEAT: Adicionado canais e integracoes no painel administrativo
This commit is contained in:
parent
751038be0f
commit
072cd1cb75
@ -58,6 +58,49 @@ const initialNotices = [
|
||||
{ id: 'n2', text: 'Templates de abertura ativa atualizados para WhatsApp.' },
|
||||
];
|
||||
|
||||
const integrationCards = [
|
||||
{
|
||||
id: 'whatsapp',
|
||||
group: 'Canal',
|
||||
name: 'WhatsApp',
|
||||
icon: 'WA',
|
||||
color: '#20a45b',
|
||||
description: 'Canal principal para atendimento, abertura ativa e continuidade das conversas no chat.',
|
||||
},
|
||||
{
|
||||
id: 'sms',
|
||||
group: 'Canal',
|
||||
name: 'SMS',
|
||||
icon: 'SM',
|
||||
color: '#00a4b7',
|
||||
description: 'Envio de comunicados curtos, confirmações e mensagens transacionais para contatos sem WhatsApp.',
|
||||
},
|
||||
{
|
||||
id: 'email',
|
||||
group: 'Canal',
|
||||
name: 'Email',
|
||||
icon: 'EM',
|
||||
color: '#d8891c',
|
||||
description: 'Recebimento e resposta de demandas por email dentro da fila omnichannel.',
|
||||
},
|
||||
{
|
||||
id: 'sharepoint',
|
||||
group: 'Integração',
|
||||
name: 'SharePoint',
|
||||
icon: 'SP',
|
||||
color: '#036c70',
|
||||
description: 'Permite que a IA visualize documentos autorizados para alimentar e manter a base de conhecimento.',
|
||||
},
|
||||
{
|
||||
id: 'gupy',
|
||||
group: 'Integração',
|
||||
name: 'Gupy',
|
||||
icon: 'GP',
|
||||
color: '#7b4cc2',
|
||||
description: 'Conecta vagas abertas e processos dos candidatos para enriquecer a base de conhecimento.',
|
||||
},
|
||||
];
|
||||
|
||||
function formatMinutes(minutes) {
|
||||
if (minutes === null || minutes === undefined || Number.isNaN(Number(minutes))) return 'Sem dados';
|
||||
return `${Number(minutes)} min`;
|
||||
@ -163,6 +206,13 @@ export function AdminPage() {
|
||||
const [editUserProfileId, setEditUserProfileId] = useState('');
|
||||
const [editUserSpecialties, setEditUserSpecialties] = useState([]);
|
||||
const [specialtyToAdd, setSpecialtyToAdd] = useState('');
|
||||
const [integrationStates, setIntegrationStates] = useState({
|
||||
whatsapp: true,
|
||||
sms: false,
|
||||
email: false,
|
||||
sharepoint: false,
|
||||
gupy: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
@ -1216,6 +1266,186 @@ export function AdminPage() {
|
||||
);
|
||||
}
|
||||
|
||||
function renderChannelsIntegrations() {
|
||||
const activeCount = integrationCards.filter((item) => integrationStates[item.id]).length;
|
||||
const channelCount = integrationCards.filter((item) => item.group === 'Canal' && integrationStates[item.id]).length;
|
||||
const integrationCount = integrationCards.filter((item) => item.group === 'Integração' && integrationStates[item.id]).length;
|
||||
|
||||
return (
|
||||
<section style={{ display: 'grid', gap: '1rem' }}>
|
||||
<DataPanel
|
||||
title="Canais e Integrações"
|
||||
description="Controle quais canais ficam disponíveis e quais integrações alimentam a operação e a IA."
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: isMobile ? '1fr' : 'repeat(3, minmax(0, 1fr))',
|
||||
gap: '0.8rem',
|
||||
}}
|
||||
>
|
||||
{[
|
||||
{ label: 'Ativos', value: activeCount },
|
||||
{ label: 'Canais habilitados', value: channelCount },
|
||||
{ label: 'Integrações habilitadas', value: integrationCount },
|
||||
].map((item) => (
|
||||
<div
|
||||
key={item.label}
|
||||
style={{
|
||||
border: '1px solid var(--color-border)',
|
||||
borderRadius: 18,
|
||||
padding: '1rem',
|
||||
background: '#f8fbfc',
|
||||
display: 'grid',
|
||||
gap: '0.25rem',
|
||||
}}
|
||||
>
|
||||
<span style={{ color: 'var(--color-text-soft)', fontWeight: 700 }}>{item.label}</span>
|
||||
<strong style={{ fontSize: '1.55rem' }}>{item.value}</strong>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</DataPanel>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: isMobile ? '1fr' : isTablet ? 'repeat(2, minmax(0, 1fr))' : 'repeat(3, minmax(0, 1fr))',
|
||||
gap: '1rem',
|
||||
}}
|
||||
>
|
||||
{integrationCards.map((item) => {
|
||||
const isEnabled = Boolean(integrationStates[item.id]);
|
||||
|
||||
return (
|
||||
<article
|
||||
key={item.id}
|
||||
style={{
|
||||
border: `1px solid ${isEnabled ? `${item.color}55` : 'var(--color-border)'}`,
|
||||
borderRadius: 22,
|
||||
padding: '1.1rem',
|
||||
background: isEnabled ? `${item.color}0f` : '#fff',
|
||||
display: 'grid',
|
||||
gap: '1rem',
|
||||
minHeight: 260,
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: '0.85rem' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '0.8rem', minWidth: 0 }}>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style={{
|
||||
width: 52,
|
||||
height: 52,
|
||||
borderRadius: 16,
|
||||
display: 'grid',
|
||||
placeItems: 'center',
|
||||
background: item.color,
|
||||
color: '#fff',
|
||||
fontWeight: 900,
|
||||
letterSpacing: 0,
|
||||
boxShadow: `0 12px 22px ${item.color}24`,
|
||||
flex: '0 0 auto',
|
||||
}}
|
||||
>
|
||||
{item.icon}
|
||||
</div>
|
||||
<div style={{ minWidth: 0 }}>
|
||||
<span
|
||||
style={{
|
||||
display: 'inline-flex',
|
||||
borderRadius: 999,
|
||||
padding: '0.18rem 0.55rem',
|
||||
background: `${item.color}18`,
|
||||
color: item.color,
|
||||
fontSize: '0.78rem',
|
||||
fontWeight: 800,
|
||||
}}
|
||||
>
|
||||
{item.group}
|
||||
</span>
|
||||
<strong style={{ display: 'block', marginTop: '0.35rem', fontSize: '1.15rem' }}>{item.name}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
aria-pressed={isEnabled}
|
||||
onClick={() => {
|
||||
setIntegrationStates((current) => ({
|
||||
...current,
|
||||
[item.id]: !current[item.id],
|
||||
}));
|
||||
}}
|
||||
style={{
|
||||
border: 'none',
|
||||
borderRadius: 999,
|
||||
width: 54,
|
||||
height: 30,
|
||||
padding: 3,
|
||||
background: isEnabled ? item.color : '#d6e0e5',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: isEnabled ? 'flex-end' : 'flex-start',
|
||||
cursor: 'pointer',
|
||||
flex: '0 0 auto',
|
||||
}}
|
||||
title={isEnabled ? `Desabilitar ${item.name}` : `Habilitar ${item.name}`}
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
style={{
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: '50%',
|
||||
background: '#fff',
|
||||
boxShadow: '0 3px 8px rgba(0, 0, 0, 0.18)',
|
||||
}}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p style={{ margin: 0, color: 'var(--color-text-soft)', lineHeight: 1.5, fontWeight: 650 }}>
|
||||
{item.description}
|
||||
</p>
|
||||
|
||||
<div
|
||||
style={{
|
||||
marginTop: 'auto',
|
||||
borderTop: '1px solid var(--color-border)',
|
||||
paddingTop: '0.85rem',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
gap: '0.75rem',
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<span style={{ color: isEnabled ? item.color : 'var(--color-text-soft)', fontWeight: 800 }}>
|
||||
{isEnabled ? 'Habilitado' : 'Desabilitado'}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
border: `1px solid ${item.color}44`,
|
||||
borderRadius: 14,
|
||||
padding: '0.65rem 0.8rem',
|
||||
background: '#fff',
|
||||
color: item.color,
|
||||
fontWeight: 800,
|
||||
}}
|
||||
>
|
||||
Configurar
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function renderPlaceholder(title, description) {
|
||||
return (
|
||||
<DataPanel title={title} description={description}>
|
||||
@ -1234,7 +1464,7 @@ export function AdminPage() {
|
||||
knowledge: <KnowledgeBasePanel areas={areas} mode="admin" isMobile={isMobile} />,
|
||||
'ai-contents': renderAiContents(),
|
||||
audit: renderAudit(),
|
||||
channels: renderPlaceholder('Canais', 'Status e configurações dos canais conectados.'),
|
||||
channels: renderChannelsIntegrations(),
|
||||
attendance: (
|
||||
<AdminAttendanceWorkspace
|
||||
isWideDesktop={isWideDesktop}
|
||||
@ -1259,6 +1489,8 @@ export function AdminPage() {
|
||||
? 'Operação'
|
||||
: activeAdminSection === 'audit'
|
||||
? 'Auditoria'
|
||||
: activeAdminSection === 'channels'
|
||||
? 'Canais e Integração'
|
||||
: activeAdminSection === 'ai-contents'
|
||||
? 'Conteúdos da IA'
|
||||
: activeAdminSection === 'knowledge'
|
||||
@ -1275,6 +1507,8 @@ export function AdminPage() {
|
||||
? 'Indicadores do dia, fila de espera e acompanhamento operacional do time.'
|
||||
: activeAdminSection === 'audit'
|
||||
? 'Logs administrativos e operacionais com paginação de 100 eventos.'
|
||||
: activeAdminSection === 'channels'
|
||||
? 'Canais de atendimento e integrações que alimentam a operação e a IA.'
|
||||
: activeAdminSection === 'ai-contents'
|
||||
? 'Base de documentos que será consultada pela IA em fase de testes.'
|
||||
: activeAdminSection === 'knowledge'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user