fix: update dependencies and improve chat component structure

- Updated `lucide-svelte` dependency to version 0.552.0 across multiple files for consistency.
- Refactored chat components to enhance structure and readability, including adjustments to the Sidebar, ChatList, and MessageInput components.
- Improved notification handling in chat components to ensure better user experience and responsiveness.
- Added type safety enhancements in various components to ensure better integration with backend data models.
This commit is contained in:
2025-11-05 11:52:01 -03:00
parent 1774b135b3
commit 6cb7414dcc
15 changed files with 377 additions and 408 deletions

View File

@@ -11,6 +11,7 @@
} from "$lib/stores/chatStore";
import { useQuery } from "convex-svelte";
import { api } from "@sgse-app/backend/convex/_generated/api";
import type { Id } from "@sgse-app/backend/convex/_generated/dataModel";
import ChatList from "./ChatList.svelte";
import ChatWindow from "./ChatWindow.svelte";
import { authStore } from "$lib/stores/auth.svelte";
@@ -156,18 +157,70 @@
activeConversation = $conversaAtiva;
});
// Tipos para conversas
type ConversaComTimestamp = {
_id: string;
ultimaMensagemTimestamp?: number;
ultimaMensagemRemetenteId?: string; // ID do remetente da última mensagem
ultimaMensagem?: string;
nome?: string;
outroUsuario?: { nome: string };
};
// Detectar novas mensagens globalmente (mesmo quando chat está fechado/minimizado)
const todasConversas = useQuery(api.chat.listarConversas, {});
let ultimoTimestampGlobal = $state<number>(0);
let mensagensNotificadasGlobal = $state<Set<string>>(new Set());
let showGlobalNotificationPopup = $state(false);
let globalNotificationMessage = $state<{ remetente: string; conteudo: string; conversaId: string } | null>(null);
let globalNotificationTimeout: ReturnType<typeof setTimeout> | null = null;
// Carregar mensagens já notificadas do localStorage ao montar
let mensagensCarregadasGlobal = $state(false);
$effect(() => {
if (typeof window !== 'undefined' && !mensagensCarregadasGlobal) {
const saved = localStorage.getItem('chat-mensagens-notificadas-global');
if (saved) {
try {
const ids = JSON.parse(saved) as string[];
mensagensNotificadasGlobal = new Set(ids);
} catch {
mensagensNotificadasGlobal = new Set();
}
}
mensagensCarregadasGlobal = true;
// Marcar todas as mensagens atuais como já visualizadas (não tocar beep ao abrir)
if (todasConversas?.data) {
const conversas = todasConversas.data as ConversaComTimestamp[];
conversas.forEach((conv) => {
if (conv.ultimaMensagemTimestamp) {
const mensagemId = `${conv._id}-${conv.ultimaMensagemTimestamp}`;
mensagensNotificadasGlobal.add(mensagemId);
}
});
salvarMensagensNotificadasGlobal();
}
}
});
// Salvar mensagens notificadas no localStorage
function salvarMensagensNotificadasGlobal() {
if (typeof window !== 'undefined') {
const ids = Array.from(mensagensNotificadasGlobal);
// Limitar a 1000 IDs para não encher o localStorage
const idsLimitados = ids.slice(-1000);
localStorage.setItem('chat-mensagens-notificadas-global', JSON.stringify(idsLimitados));
}
}
// Função para tocar som de notificação
function tocarSomNotificacaoGlobal() {
try {
const AudioContext = window.AudioContext || (window as any).webkitAudioContext;
const audioContext = new AudioContext();
const AudioContextClass = window.AudioContext || (window as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;
if (!AudioContextClass) return;
const audioContext = new AudioContextClass();
if (audioContext.state === 'suspended') {
audioContext.resume().then(() => {
const oscillator = audioContext.createOscillator();
@@ -200,32 +253,44 @@
$effect(() => {
if (todasConversas?.data && authStore.usuario?._id) {
// Encontrar o maior timestamp de todas as conversas
let maiorTimestamp = 0;
let conversaComNovaMensagem: any = null;
const conversas = todasConversas.data as ConversaComTimestamp[];
todasConversas.data.forEach((conv: any) => {
if (conv.ultimaMensagemTimestamp && conv.ultimaMensagemTimestamp > maiorTimestamp) {
maiorTimestamp = conv.ultimaMensagemTimestamp;
conversaComNovaMensagem = conv;
// Encontrar conversas com novas mensagens
const meuId = String(authStore.usuario._id);
conversas.forEach((conv) => {
if (!conv.ultimaMensagemTimestamp) return;
// Verificar se a última mensagem foi enviada pelo usuário atual
const remetenteIdStr = conv.ultimaMensagemRemetenteId ? String(conv.ultimaMensagemRemetenteId) : null;
if (remetenteIdStr && remetenteIdStr === meuId) {
// Mensagem enviada pelo próprio usuário - não tocar beep nem mostrar notificação
return;
}
});
// Se há nova mensagem (timestamp maior) e não estamos vendo essa conversa, tocar som e mostrar popup
if (maiorTimestamp > ultimoTimestampGlobal && conversaComNovaMensagem) {
// Criar ID único para esta mensagem: conversaId-timestamp
const mensagemId = `${conv._id}-${conv.ultimaMensagemTimestamp}`;
// Verificar se já foi notificada
if (mensagensNotificadasGlobal.has(mensagemId)) return;
const conversaAtivaId = activeConversation ? String(activeConversation) : null;
const conversaIdStr = String(conversaComNovaMensagem._id);
const conversaIdStr = String(conv._id);
// Só mostrar notificação se não estamos vendo essa conversa
if (!isOpen || conversaAtivaId !== conversaIdStr) {
// Tocar som de notificação
// Marcar como notificada antes de tocar som (evita duplicação)
mensagensNotificadasGlobal.add(mensagemId);
salvarMensagensNotificadasGlobal();
// Tocar som de notificação (apenas uma vez)
tocarSomNotificacaoGlobal();
// Mostrar popup de notificação
globalNotificationMessage = {
remetente: conversaComNovaMensagem.outroUsuario?.nome || conversaComNovaMensagem.nome || "Usuário",
conteudo: conversaComNovaMensagem.ultimaMensagem || "",
conversaId: conversaComNovaMensagem._id
remetente: conv.outroUsuario?.nome || conv.nome || "Usuário",
conteudo: conv.ultimaMensagem || "",
conversaId: conv._id
};
showGlobalNotificationPopup = true;
@@ -238,9 +303,7 @@
globalNotificationMessage = null;
}, 5000);
}
ultimoTimestampGlobal = maiorTimestamp;
}
});
}
});
@@ -676,7 +739,7 @@
}
// Abrir chat e conversa ao clicar
abrirChat();
abrirConversa(globalNotificationMessage.conversaId as any);
abrirConversa(globalNotificationMessage.conversaId as Id<"conversas">);
}}
>
<div class="flex items-start gap-3">