omnichannel-frontend/docs/chat-whatsapp.md

6.2 KiB

Modulo de Chat WhatsApp (Frontend)

Visao geral

O modulo de Chat no frontend integra as conversas em tempo real do WhatsApp diretamente na tela de atendimento do operador.

A interface e altamente responsiva, provendo feedback instantaneo de envio (zero latencia) e sincronizando com o backend via WebSockets (Socket.io) para atualizar estados de de-duplicacao, novas mensagens, midias e controle de posse do atendimento.


Componentes Principais

1. Hook de Negocio (useChat.js)

Centraliza todo o estado das conversas, conexao WebSocket e operacoes de rede:

  • contacts: Lista de chats ativos sincronizados. Cada contato possui um objeto assignment (atribuicao) normalizado.
  • messagesByContact: Map de historico de mensagens por JID/contato.
  • takeChat(): Dispara a requisicao de rede /whatsapp/assign enviando o ID do atendente e o ID numerico da area do usuario logado (convertido com seguranca para inteiro).
  • sendMessage(): Trata a de-duplicacao de mensagens em milissegundos e gerencia a concorrência (race condition).

2. Painel de Atendimento (ChatWindow.jsx)

O container principal da conversa selecionada. Ele renderiza:

  • Header: Mostra o nome resolvido do cliente, canal (WhatsApp) e o indicador de quem esta atendendo.
  • Historico: Area de scroll contendo as bolhas de mensagens do atendente (agent) e do cliente (customer), incluindo visualizadores para imagens, audios e links de arquivos.
  • Footer de Input: Caixa de texto com suporte a tecla Enter e icone de anexo de midia (com validacao automatica de tamanho).

Mecanismos de UX e Estabilidade

1. Insercao Instantanea (UX Zero-Latency)

Para evitar que o atendente perceba qualquer latencia de rede, o envio e dividido em duas etapas:

  1. Fase Local: A bolha de mensagem e inserida na tela imediatamente com um ID temporario (temp- + timestamp) e o texto digitado. O input de texto e arquivos e limpo na mesma hora.
  2. Fase de Disparo: A requisicao HTTP POST e disparada para o backend em segundo plano.

2. De-duplicacao de Mensagens (Prevecao de Race Condition)

Como o backend envia a mensagem recebida via WebSocket assim que o Puppeteer a dispara, a bolha poderia aparecer duplicada na tela se a requisição de envio original ainda estivesse processando.

  • A Solucao: O hook de WebSocket compara as mensagens recebidas em tempo real. Se o texto bater e a diferenca temporal de timestamp for inferior a 4 segundos, ele identifica a bolha temp-... local, remove o prefixo temporario e atualiza-a com o ID oficial do WhatsApp gerado no servidor. Zero duplicacoes, zero flashes na tela.

3. Validação de Posse (Type-Safe User IDs)

Para evitar conflitos na exibicao do banner "⚠️ Atendido por outro colaborador", realizamos casting explicito dos IDs dos usuarios envolvidos:

const isAssignedToMe = activeContact?.assignment?.userId && String(activeContact.assignment.userId) === String(currentUser.id);
const isAssignedToOthers = activeContact?.assignment && String(activeContact.assignment.userId) !== String(currentUser.id);

Isso impede que comparacoes como 4 === "4" (inteiro vindo do banco relacional vs string vindo do localStorage/JWT) avaliem incorretamente como falso, mantendo a tela bloqueada ou liberada com precisao.

4. Layout e Rolagem Estrita (680px Scroll)

A interface de mensagens possui limitacoes verticais restritas para evitar que a tela se alongue infinitamente para baixo.

  • A bolha de historico e fixada com altura proporcional (height: 680px ou calc) e controle de transbordo overflow-y: auto.
  • O hook de chat escuta mudancas na lista de mensagens e realiza rolagem automatica suave (smooth) para o fim da tela sempre que uma nova bolha e adicionada.

Novos Fluxos Homologados (WhatsApp / Meta)

1. Novo Atendimento Inteligente (NewAttendancePage.jsx)

  • Remoção do Seletor de Área: O seletor manual foi removido da tela para simplificar a operação. O sistema resolve a área dinamicamente a partir do atendente logado (currentUser.areaPrincipal ou areas[0]).
  • Bloqueio de Campo: Ao escolher um contato dos recentes ou da busca lateral, o input do telefone e do nome do cliente ficam bloqueados para escrita.
  • Modo "Novo Número": Ao clicar no botão, o operador habilita os inputs de nome e telefone. Caso inicie o chat sem digitar um nome personalizado, o sistema aplica um fallback limpo no formato Contato Novo (+55...).

2. Bloqueio e Envio de Templates Meta (ChatWindow.jsx)

Como a API oficial do WhatsApp/Meta exige uma mensagem pré-aprovada para iniciar conversas ativas (sem histórico prévio), a interface aplica travas estritas:

  • Travamento do Input: Se a conversa selecionada possuir histórico de envio vazio (!hasAgentMessages), a caixa de texto principal e o botão "Enviar" ficam bloqueados.
  • Painel de Templates: Logo acima do rodapé de digitação, renderiza-se um seletor horizontal com os templates oficiais Meta ativos no banco (buscados de GET /whatsapp/templates).
  • Substituição Dinâmica: Ao clicar em um template, as variáveis |NOME|, |DATA| ou |PROTOCOLO| são interpoladas em tempo real com os dados do cliente, populando o input principal e liberando o fluxo de envio da primeira mensagem.

3. Gerenciamento de Templates para Supervisores (SupervisorPage.jsx)

Supervisores possuem controle administrativo total sobre as mensagens homologadas:

  • CRUD de Modelos: Exibe todos os templates de WhatsApp em formato de cards visuais.
  • Painel de Edição: Permite criar novos templates ou editar identificadores/conteúdos de templates existentes. As alterações persistem imediatamente no banco PostgreSQL por meio dos endpoints /whatsapp/templates.

Como Integrar e Rodar

Variaveis de Ambiente

O frontend conecta no WebSocket e na API do backend usando a porta padrao do NestJS:

VITE_API_URL=http://localhost:3001
VITE_WS_URL=http://localhost:3001

Compilando e Rodando localmente

cd frontend
npm run dev

Ao selecionar uma conversa de canal "WhatsApp" que esteja livre, basta digitar uma mensagem e pressionar Enter. O chat sera automaticamente assumido por voce em tempo real, gravando no PostgreSQL e desbloqueando a janela de chat de forma instantanea.