2026-03-19 18:22:18 -03:00
|
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
|
|
|
|
|
|
|
function ChannelBadge({ channel }) {
|
|
|
|
|
const colors = {
|
|
|
|
|
WhatsApp: '#2bb741',
|
|
|
|
|
Email: '#e5a22a',
|
|
|
|
|
SMS: '#00a4b7',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<span
|
|
|
|
|
style={{
|
|
|
|
|
display: 'inline-flex',
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
borderRadius: 999,
|
|
|
|
|
padding: '0.22rem 0.6rem',
|
|
|
|
|
background: `${colors[channel] || '#003150'}16`,
|
|
|
|
|
color: colors[channel] || '#003150',
|
|
|
|
|
fontSize: '0.8rem',
|
|
|
|
|
fontWeight: 700,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{channel}
|
|
|
|
|
</span>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function MessagesWorkspace({
|
|
|
|
|
conversations,
|
|
|
|
|
activeConversationId,
|
|
|
|
|
onSelectConversation,
|
|
|
|
|
actionItems,
|
|
|
|
|
isWideDesktop = false,
|
|
|
|
|
isDesktop = false,
|
|
|
|
|
isTablet = false,
|
|
|
|
|
isMobile = false,
|
|
|
|
|
}) {
|
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
const activeConversation =
|
|
|
|
|
conversations.find((conversation) => conversation.id === activeConversationId) ||
|
|
|
|
|
conversations[0];
|
|
|
|
|
|
|
|
|
|
const gridTemplateColumns = isMobile
|
|
|
|
|
? '1fr'
|
|
|
|
|
: isWideDesktop
|
|
|
|
|
? 'minmax(240px, 0.95fr) minmax(360px, 1.8fr) minmax(220px, 0.8fr)'
|
|
|
|
|
: isDesktop || isTablet
|
|
|
|
|
? 'minmax(260px, 320px) minmax(0, 1fr)'
|
|
|
|
|
: '1fr';
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
display: 'grid',
|
|
|
|
|
gridTemplateColumns,
|
|
|
|
|
gap: '1rem',
|
|
|
|
|
alignItems: 'start',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<section
|
|
|
|
|
style={{
|
|
|
|
|
background: '#fff',
|
|
|
|
|
borderRadius: '26px',
|
|
|
|
|
border: '1px solid var(--color-border)',
|
|
|
|
|
padding: '1rem',
|
|
|
|
|
display: 'grid',
|
|
|
|
|
gap: '0.75rem',
|
|
|
|
|
minWidth: 0,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div>
|
|
|
|
|
<strong style={{ fontSize: '1.05rem' }}>Conversas</strong>
|
|
|
|
|
<p style={{ margin: '0.35rem 0 0', color: 'var(--color-text-soft)' }}>
|
|
|
|
|
Atendimento em tempo real por canal.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{conversations.map((conversation) => {
|
|
|
|
|
const isActive = conversation.id === activeConversation.id;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<button
|
|
|
|
|
key={conversation.id}
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() => onSelectConversation(conversation.id)}
|
|
|
|
|
style={{
|
|
|
|
|
border: '1px solid',
|
|
|
|
|
borderColor: isActive ? 'rgba(0, 164, 183, 0.26)' : 'var(--color-border)',
|
|
|
|
|
borderRadius: '20px',
|
|
|
|
|
padding: '1rem',
|
|
|
|
|
background: isActive ? 'rgba(0, 164, 183, 0.08)' : '#fff',
|
|
|
|
|
textAlign: 'left',
|
|
|
|
|
display: 'grid',
|
|
|
|
|
gap: '0.6rem',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '1rem' }}>
|
|
|
|
|
<strong>{conversation.name}</strong>
|
|
|
|
|
<span style={{ color: 'var(--color-text-soft)', fontSize: '0.86rem' }}>
|
|
|
|
|
{conversation.time}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', gap: '0.75rem' }}>
|
|
|
|
|
<ChannelBadge channel={conversation.channel} />
|
|
|
|
|
{conversation.unread ? (
|
|
|
|
|
<span
|
|
|
|
|
style={{
|
|
|
|
|
minWidth: 24,
|
|
|
|
|
borderRadius: 999,
|
|
|
|
|
padding: '0.15rem 0.45rem',
|
|
|
|
|
background: 'var(--color-secondary)',
|
|
|
|
|
color: '#fff',
|
|
|
|
|
fontSize: '0.78rem',
|
|
|
|
|
fontWeight: 700,
|
|
|
|
|
textAlign: 'center',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{conversation.unread}
|
|
|
|
|
</span>
|
|
|
|
|
) : null}
|
|
|
|
|
</div>
|
|
|
|
|
<span style={{ color: 'var(--color-text-soft)' }}>{conversation.lastMessage}</span>
|
|
|
|
|
</button>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section
|
|
|
|
|
style={{
|
|
|
|
|
background: '#fff',
|
|
|
|
|
borderRadius: '26px',
|
|
|
|
|
border: '1px solid var(--color-border)',
|
|
|
|
|
display: 'grid',
|
|
|
|
|
gridTemplateRows: 'auto 1fr auto',
|
|
|
|
|
minHeight: 580,
|
|
|
|
|
overflow: 'hidden',
|
|
|
|
|
minWidth: 0,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<header
|
|
|
|
|
style={{
|
|
|
|
|
padding: '1.15rem 1.25rem',
|
|
|
|
|
borderBottom: '1px solid var(--color-border)',
|
|
|
|
|
display: 'flex',
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
|
gap: '1rem',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div>
|
|
|
|
|
<strong style={{ display: 'block', fontSize: '1.08rem' }}>{activeConversation.name}</strong>
|
|
|
|
|
<span style={{ color: 'var(--color-text-soft)' }}>
|
|
|
|
|
{activeConversation.status === 'online' ? 'Online agora' : 'Offline'}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div style={{ display: 'flex', gap: '0.6rem', flexWrap: 'wrap' }}>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() => navigate('/chat')}
|
|
|
|
|
style={{
|
|
|
|
|
border: '1px solid var(--color-border)',
|
|
|
|
|
borderRadius: '14px',
|
|
|
|
|
padding: '0.7rem 0.9rem',
|
|
|
|
|
background: '#fff',
|
|
|
|
|
color: 'var(--color-primary)',
|
|
|
|
|
fontWeight: 700,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Abrir chat
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
style={{
|
|
|
|
|
border: 'none',
|
|
|
|
|
borderRadius: '14px',
|
|
|
|
|
padding: '0.7rem 0.9rem',
|
|
|
|
|
background: 'rgba(0, 49, 80, 0.08)',
|
|
|
|
|
color: 'var(--color-primary)',
|
|
|
|
|
fontWeight: 700,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Transferir
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
padding: '1.25rem',
|
|
|
|
|
display: 'grid',
|
|
|
|
|
gap: '0.9rem',
|
|
|
|
|
alignContent: 'start',
|
|
|
|
|
background:
|
|
|
|
|
'linear-gradient(180deg, rgba(245, 248, 251, 0.45), rgba(255, 255, 255, 0.9))',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{activeConversation.messages.map((message) => {
|
|
|
|
|
const isAgent = message.from === 'agent';
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
key={message.id}
|
|
|
|
|
style={{
|
|
|
|
|
justifySelf: isAgent ? 'end' : 'start',
|
|
|
|
|
maxWidth: '72%',
|
|
|
|
|
padding: '0.95rem 1rem',
|
|
|
|
|
borderRadius: isAgent ? '18px 18px 6px 18px' : '18px 18px 18px 6px',
|
|
|
|
|
background: isAgent ? 'var(--color-primary)' : '#edf1f5',
|
|
|
|
|
color: isAgent ? '#fff' : 'var(--color-text)',
|
|
|
|
|
boxShadow: 'var(--shadow-md)',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{message.text}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<footer
|
|
|
|
|
style={{
|
|
|
|
|
padding: '1rem 1.25rem 1.25rem',
|
|
|
|
|
borderTop: '1px solid var(--color-border)',
|
|
|
|
|
display: 'grid',
|
|
|
|
|
gridTemplateColumns: '1fr auto',
|
|
|
|
|
gap: '0.75rem',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value="Posso acionar o time responsavel e te retorno em seguida."
|
|
|
|
|
readOnly
|
|
|
|
|
style={{
|
|
|
|
|
border: '1px solid var(--color-border)',
|
|
|
|
|
borderRadius: '18px',
|
|
|
|
|
padding: '0.95rem 1rem',
|
|
|
|
|
background: '#fff',
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
style={{
|
|
|
|
|
border: 'none',
|
|
|
|
|
borderRadius: '18px',
|
|
|
|
|
padding: '0.95rem 1.2rem',
|
|
|
|
|
background: 'linear-gradient(135deg, var(--color-primary), #0b5a86)',
|
|
|
|
|
color: '#fff',
|
|
|
|
|
fontWeight: 700,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Enviar
|
|
|
|
|
</button>
|
|
|
|
|
</footer>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<aside
|
|
|
|
|
style={{
|
|
|
|
|
background: '#fff',
|
|
|
|
|
borderRadius: '26px',
|
|
|
|
|
border: '1px solid var(--color-border)',
|
|
|
|
|
padding: '1.2rem',
|
|
|
|
|
display: 'grid',
|
|
|
|
|
gap: '1rem',
|
|
|
|
|
alignContent: 'start',
|
|
|
|
|
gridColumn: isWideDesktop ? 'auto' : '1 / -1',
|
|
|
|
|
minWidth: 0,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div>
|
2026-03-31 17:59:44 -03:00
|
|
|
<strong style={{ fontSize: '1.05rem' }}>Painel de ações</strong>
|
2026-03-19 18:22:18 -03:00
|
|
|
<p style={{ margin: '0.35rem 0 0', color: 'var(--color-text-soft)' }}>
|
2026-03-31 17:59:44 -03:00
|
|
|
Contexto rápido do atendimento selecionado.
|
2026-03-19 18:22:18 -03:00
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{actionItems.map((item) => (
|
|
|
|
|
<article
|
|
|
|
|
key={item.title}
|
|
|
|
|
style={{
|
|
|
|
|
borderRadius: '20px',
|
|
|
|
|
padding: '1rem',
|
|
|
|
|
background: 'rgba(0, 49, 80, 0.04)',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<span style={{ color: 'var(--color-text-soft)', display: 'block', marginBottom: '0.35rem' }}>
|
|
|
|
|
{item.title}
|
|
|
|
|
</span>
|
|
|
|
|
<strong>{item.value}</strong>
|
|
|
|
|
</article>
|
|
|
|
|
))}
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() => navigate('/new-attendance')}
|
|
|
|
|
style={{
|
|
|
|
|
border: '1px solid var(--color-border)',
|
|
|
|
|
borderRadius: '18px',
|
|
|
|
|
padding: '0.95rem 1rem',
|
|
|
|
|
background: '#fff',
|
|
|
|
|
color: 'var(--color-primary)',
|
|
|
|
|
fontWeight: 700,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Criar novo fluxo
|
|
|
|
|
</button>
|
|
|
|
|
</aside>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|