omnichannel-frontend/src/modules/home/components/MessagesWorkspace.jsx
Rafael Lopes 8e29dde2a1 Initial commit
- Telas iniciais do projeto criadas
- Estrutura de pastas e arquivos definida
- Componentes instalados e linguagem definida
- Vite configurado para React e build de dev rapida
- Mockups de dados criados para desenvolvimento dos módulos
- Documentação inicial criada para guiar o desenvolvimento e uso do projeto
2026-03-19 18:22:18 -03:00

309 lines
9.1 KiB
JavaScript

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>
<strong style={{ fontSize: '1.05rem' }}>Painel de acoes</strong>
<p style={{ margin: '0.35rem 0 0', color: 'var(--color-text-soft)' }}>
Contexto rapido do atendimento selecionado.
</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>
);
}