omnichannel-frontend/src/modules/home/pages/HomePage.jsx

171 lines
5.4 KiB
React
Raw Normal View History

import { useState } from 'react';
import { BrandMark } from '../../../shared/components/BrandMark';
import { HomeSidebar } from '../components/HomeSidebar';
import { HomeTopbar } from '../components/HomeTopbar';
import { MessagesWorkspace } from '../components/MessagesWorkspace';
import { CallsWorkspace } from '../components/CallsWorkspace';
import { AttendantOpsPanel } from '../components/AttendantOpsPanel';
import { recentCalls, sidebarItems } from '../services/homeMocks';
import { useViewport } from '../../../shared/hooks/useViewport';
import { useChat } from '../../chat/hooks/useChat';
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 ? '[Midia]' : ''),
timestamp: message.timestamp,
})),
};
}
export function HomePage() {
const { isWideDesktop, isDesktop, isTablet, isMobile } = useViewport();
const {
contacts,
activeContactId,
setActiveContactId,
messages,
sendMessage,
isLoadingChats,
} = useChat();
const [activeTab, setActiveTab] = useState('messages');
const [searchValue, setSearchValue] = useState('');
const conversations = contacts.map((contact) =>
toHomeConversation(contact, contact.id === activeContactId ? messages : []),
);
const search = searchValue.trim().toLowerCase();
const filteredConversations = !search
? conversations
: conversations.filter((conversation) => {
const haystack = `${conversation.name} ${conversation.channel} ${conversation.lastMessage}`;
return haystack.toLowerCase().includes(search);
});
const safeConversationId =
filteredConversations.find((conversation) => conversation.id === activeContactId)?.id ||
filteredConversations[0]?.id ||
conversations[0]?.id;
return (
<main
style={{
minHeight: '100vh',
padding: '1.5rem',
}}
>
<section
style={{
width: 'min(1680px, calc(100vw - 3rem))',
margin: '0 auto',
background: 'var(--color-surface-strong)',
borderRadius: '32px',
boxShadow: 'var(--shadow-lg)',
padding: '1.5rem',
display: 'grid',
gap: '1.5rem',
}}
>
<div
style={{
display: 'grid',
gridTemplateColumns: isDesktop ? 'minmax(340px, 380px) minmax(0, 1fr)' : '1fr',
gap: '1.5rem',
alignItems: 'start',
}}
>
<div
style={{
display: 'grid',
gap: '1.25rem',
}}
>
<div
style={{
background: '#fff',
border: '1px solid var(--color-border)',
borderRadius: '28px',
padding: '1.5rem',
}}
>
<BrandMark size="lg" />
</div>
<HomeSidebar items={sidebarItems} activeItem="dashboard" isMobile={!isDesktop} />
</div>
<div style={{ display: 'grid', gap: '1.25rem', minWidth: 0 }}>
<HomeTopbar
activeTab={activeTab}
onTabChange={setActiveTab}
searchValue={searchValue}
onSearchChange={setSearchValue}
isWideDesktop={isWideDesktop}
isDesktop={isDesktop}
isTablet={isTablet}
isMobile={isMobile}
/>
<section
style={{
display: 'grid',
gap: '1rem',
}}
>
<AttendantOpsPanel activeChatsCount={filteredConversations.length} />
{isLoadingChats ? (
<div
style={{
border: '1px solid var(--color-border)',
borderRadius: 18,
padding: '0.85rem 1rem',
background: '#fff',
color: 'var(--color-text-soft)',
fontWeight: 700,
}}
>
Atualizando conversas do WhatsApp...
</div>
) : null}
{activeTab === 'messages' ? (
<MessagesWorkspace
conversations={filteredConversations}
activeConversationId={safeConversationId}
onSelectConversation={setActiveContactId}
onSendSuggestedReply={async (conversationId, reply) => {
setActiveContactId(conversationId);
await sendMessage(reply, conversationId);
}}
isWideDesktop={isWideDesktop}
isDesktop={isDesktop}
isTablet={isTablet}
isMobile={isMobile}
/>
) : (
<CallsWorkspace
calls={recentCalls}
isWideDesktop={isWideDesktop}
isDesktop={isDesktop}
isMobile={isMobile}
/>
)}
</section>
</div>
</div>
</section>
</main>
);
}