omnichannel-frontend/src/modules/chat/pages/ChatPage.jsx

267 lines
8.4 KiB
React
Raw Normal View History

import { Link, useSearchParams } from 'react-router-dom';
import { useEffect, useRef, useState } from 'react';
import { BrandMark } from '../../../shared/components/BrandMark';
import { useViewport } from '../../../shared/hooks/useViewport';
import { ChatConversationList } from '../components/ChatConversationList';
import { ChatTransferPanel } from '../components/ChatTransferPanel';
import { ContactProfilePanel } from '../components/ContactProfilePanel';
import { ChatWindow } from '../components/ChatWindow';
import { useChat } from '../hooks/useChat';
import { quickReplies } from '../services/chatMocks';
export function ChatPage() {
const [searchParams, setSearchParams] = useSearchParams();
const { isWideDesktop, isDesktop, isTablet, isMobile } = useViewport();
const {
currentUserId,
contacts,
activeContact,
activeContactId,
setActiveContactId,
messages,
draft,
setDraft,
attachedFile,
attachFile,
removeAttachedFile,
sendMessage,
hydrateMessageMedia,
assumeChat,
releaseChat,
canAssumeChat,
canReply,
assignmentLabel,
transferNoteLabel,
updateContactProfile,
isReplying,
selectedArea,
setSelectedArea,
isTransferOpen,
setIsTransferOpen,
transferArea,
setTransferArea,
transferAreas,
attendants,
isSameUserArea,
transferAttendant,
setTransferAttendant,
transferNote,
setTransferNote,
submitTransfer,
isPaused,
pauseDurationLabel,
} = useChat();
const requestedChatId = searchParams.get('chatId');
const handledRequestedChatIdRef = useRef('');
const [isContactPanelOpen, setIsContactPanelOpen] = useState(false);
useEffect(() => {
if (!requestedChatId) return;
if (handledRequestedChatIdRef.current === requestedChatId) return;
if (!contacts.some((contact) => contact.id === requestedChatId)) return;
handledRequestedChatIdRef.current = requestedChatId;
setActiveContactId(requestedChatId);
setSearchParams({}, { replace: true });
}, [requestedChatId, contacts, setActiveContactId, setSearchParams]);
function selectContact(contactId) {
setActiveContactId(contactId);
if (requestedChatId) {
setSearchParams({}, { replace: true });
}
}
const gridTemplateColumns = isMobile
? '1fr'
: isWideDesktop
? 'minmax(260px, 320px) minmax(0, 1.6fr) minmax(280px, 320px)'
: isDesktop || isTablet
? 'minmax(260px, 320px) minmax(0, 1fr)'
: '1fr';
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.25rem',
}}
>
<header
style={{
display: 'grid',
gridTemplateColumns: isMobile ? '1fr' : 'auto 1fr auto',
gap: '1rem',
alignItems: 'center',
}}
>
<BrandMark />
<div
style={{
justifySelf: isMobile ? 'stretch' : 'center',
padding: '0.85rem 1rem',
borderRadius: '18px',
background: 'rgba(0, 49, 80, 0.06)',
color: 'var(--color-primary)',
fontWeight: 700,
textAlign: 'center',
}}
>
{isPaused ? `Pausado ha ${pauseDurationLabel}` : 'Atendimento em tempo real'}
</div>
<Link
to="/home"
style={{
justifySelf: isMobile ? 'stretch' : 'end',
borderRadius: '16px',
padding: '0.85rem 1rem',
background: 'var(--color-primary)',
color: '#fff',
fontWeight: 700,
textAlign: 'center',
}}
>
Voltar para home
</Link>
</header>
<section
style={{
display: 'grid',
gridTemplateColumns,
gap: '1rem',
alignItems: 'stretch',
}}
>
<ChatConversationList
contacts={contacts}
activeContactId={activeContactId}
onSelectContact={selectContact}
onOpenContact={() => {
setIsTransferOpen(false);
setIsContactPanelOpen(true);
}}
currentUserId={currentUserId}
isMobile={isMobile}
/>
<div style={{ display: 'grid', gap: '1rem', minWidth: 0, alignContent: 'start' }}>
<ChatWindow
contact={activeContact}
messages={messages}
selectedArea={selectedArea}
setSelectedArea={setSelectedArea}
draft={draft}
setDraft={setDraft}
attachedFile={attachedFile}
onAttachFile={attachFile}
onRemoveAttachedFile={removeAttachedFile}
onLoadMedia={hydrateMessageMedia}
onSend={sendMessage}
onToggleTransfer={() => {
setIsContactPanelOpen(false);
setIsTransferOpen((current) => !current);
}}
onAssumeChat={assumeChat}
onReleaseChat={releaseChat}
canAssumeChat={canAssumeChat}
canReply={canReply}
assignmentLabel={assignmentLabel}
transferNote={transferNoteLabel}
isReplying={isReplying}
isPaused={isPaused}
pauseDurationLabel={pauseDurationLabel}
isMobile={isMobile}
/>
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))',
gap: '0.75rem',
}}
>
{quickReplies.map((reply) => (
<button
key={reply}
type="button"
onClick={() => setDraft(reply)}
disabled={isPaused}
style={{
border: '1px solid var(--color-border)',
borderRadius: '18px',
padding: '0.85rem 1rem',
background: '#fff',
color: 'var(--color-primary)',
fontWeight: 600,
textAlign: 'left',
opacity: isPaused ? 0.55 : 1,
}}
>
{reply}
</button>
))}
</div>
</div>
{isWideDesktop ? (
<>
<ChatTransferPanel
isOpen={isTransferOpen}
transferArea={transferArea}
setTransferArea={setTransferArea}
transferAreas={transferAreas}
attendants={attendants}
isSameUserArea={isSameUserArea}
transferAttendant={transferAttendant}
setTransferAttendant={setTransferAttendant}
transferNote={transferNote}
setTransferNote={setTransferNote}
onSubmit={submitTransfer}
onClose={() => setIsTransferOpen(false)}
/>
<ContactProfilePanel
isOpen={isContactPanelOpen}
contact={activeContact}
onClose={() => setIsContactPanelOpen(false)}
onSaved={updateContactProfile}
/>
</>
) : null}
</section>
{!isWideDesktop ? (
<>
<ChatTransferPanel
isOpen={isTransferOpen}
transferArea={transferArea}
setTransferArea={setTransferArea}
transferAreas={transferAreas}
attendants={attendants}
isSameUserArea={isSameUserArea}
transferAttendant={transferAttendant}
setTransferAttendant={setTransferAttendant}
transferNote={transferNote}
setTransferNote={setTransferNote}
onSubmit={submitTransfer}
onClose={() => setIsTransferOpen(false)}
/>
<ContactProfilePanel
isOpen={isContactPanelOpen}
contact={activeContact}
onClose={() => setIsContactPanelOpen(false)}
onSaved={updateContactProfile}
/>
</>
) : null}
</section>
</main>
);
}