|
|
@@ -36,6 +36,9 @@ export function useConversas() {
|
|
|
let ultimoTimestamp = null;
|
|
|
let buscandoNovasMensagens = false;
|
|
|
let conversasEpoch = 0;
|
|
|
+ // duplo clique na mesma conversa passa pelo guard de id; o epoch distingue as aberturas
|
|
|
+ let aberturaEpoch = 0;
|
|
|
+ let sugestaoEpoch = 0;
|
|
|
const midiaEmResolucao = new Set();
|
|
|
|
|
|
function limparMidiaCache() {
|
|
|
@@ -92,18 +95,19 @@ export function useConversas() {
|
|
|
async function buscarSugestao() {
|
|
|
if(!conversaAtivaId.value) return;
|
|
|
const idAlvo = conversaAtivaId.value;
|
|
|
+ const epoch = ++sugestaoEpoch;
|
|
|
sugestaoLoading.value = true;
|
|
|
sugestaoError.value = "";
|
|
|
try {
|
|
|
const { sugestao: texto } = await gerarSugestaoResposta(idAlvo);
|
|
|
- if ( conversaAtivaId.value !== idAlvo) return;
|
|
|
+ if (epoch !== sugestaoEpoch) return;
|
|
|
sugestao.value = texto;
|
|
|
} catch (err){
|
|
|
- if ( conversaAtivaId.value !== idAlvo) return;
|
|
|
+ if (epoch !== sugestaoEpoch) return;
|
|
|
sugestao.value = null;
|
|
|
sugestaoError.value = friendlyErrorMessage(err, "Falha ao gerar sugestão");
|
|
|
} finally {
|
|
|
- sugestaoLoading.value = false;
|
|
|
+ if (epoch === sugestaoEpoch) sugestaoLoading.value = false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -133,32 +137,40 @@ export function useConversas() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ function invalidarSugestao() {
|
|
|
+ sugestaoEpoch++;
|
|
|
+ sugestao.value = null;
|
|
|
+ sugestaoError.value = "";
|
|
|
+ sugestaoLoading.value = false;
|
|
|
+ }
|
|
|
+
|
|
|
async function abrirConversa(id) {
|
|
|
+ const abertura = ++aberturaEpoch;
|
|
|
pararPolling();
|
|
|
conversaAtivaId.value = id;
|
|
|
mensagens.value = [];
|
|
|
limparMidiaCache();
|
|
|
ultimoTimestamp = null;
|
|
|
- sugestao.value = null;
|
|
|
- sugestaoError.value = "";
|
|
|
+ invalidarSugestao();
|
|
|
mensagensLoading.value = true;
|
|
|
mensagensError.value = "";
|
|
|
|
|
|
try {
|
|
|
const { results } = await listarMensagensConversa(id);
|
|
|
- if (conversaAtivaId.value !== id) return;
|
|
|
+ if (abertura !== aberturaEpoch) return;
|
|
|
mensagens.value = results;
|
|
|
ultimoTimestamp = results.length > 0 ? results[results.length - 1].Timestamp : null;
|
|
|
if (results.length && results[results.length - 1].Direcao === "entrada") buscarSugestao();
|
|
|
} catch (err) {
|
|
|
- if (conversaAtivaId.value !== id) return;
|
|
|
+ if (abertura !== aberturaEpoch) return;
|
|
|
mensagensError.value = friendlyErrorMessage(err, "Falha ao carregar mensagens");
|
|
|
} finally {
|
|
|
- if (conversaAtivaId.value === id) mensagensLoading.value = false;
|
|
|
+ if (abertura === aberturaEpoch) mensagensLoading.value = false;
|
|
|
}
|
|
|
|
|
|
- if (conversaAtivaId.value !== id) return;
|
|
|
+ if (abertura !== aberturaEpoch) return;
|
|
|
|
|
|
+ pararPolling();
|
|
|
pollTimer = setInterval(() => {
|
|
|
if (document.visibilityState === "visible") buscarNovasMensagens();
|
|
|
}, POLL_INTERVAL_MS);
|
|
|
@@ -166,13 +178,14 @@ export function useConversas() {
|
|
|
}
|
|
|
|
|
|
function fecharConversa() {
|
|
|
+ aberturaEpoch++;
|
|
|
pararPolling();
|
|
|
conversaAtivaId.value = null;
|
|
|
mensagens.value = [];
|
|
|
+ mensagensLoading.value = false;
|
|
|
limparMidiaCache();
|
|
|
ultimoTimestamp = null;
|
|
|
- sugestao.value = null;
|
|
|
- sugestaoError.value = "";
|
|
|
+ invalidarSugestao();
|
|
|
}
|
|
|
|
|
|
async function enviarResposta(texto) {
|
|
|
@@ -194,7 +207,10 @@ export function useConversas() {
|
|
|
|
|
|
async function excluirConversa(id) {
|
|
|
await excluirConversaApi(id);
|
|
|
- conversasEpoch++;
|
|
|
+ // invalida um carregarConversas em voo (que traria a conversa excluída de volta) — e por isso
|
|
|
+ // o loading dele precisa ser desligado aqui, já que o finally dele não vai mais fazê-lo
|
|
|
+ conversasEpoch++;
|
|
|
+ conversasLoading.value = false;
|
|
|
conversas.value = conversas.value.filter((c) => c.Id !== id);
|
|
|
if (conversaAtivaId.value === id) fecharConversa();
|
|
|
}
|