feat: enhance push notification management and error handling

- Implemented error handling for unhandled promise rejections related to message channels, improving stability during push notification operations.
- Updated the PushNotificationManager component to manage push subscription registration with timeouts, preventing application hangs.
- Enhanced the sidebar and chat components to display user avatars, improving user experience and visual consistency.
- Refactored email processing logic to support scheduled email sending, integrating new backend functionalities for better email management.
- Improved overall error handling and logging across components to reduce console spam and enhance debugging capabilities.
This commit is contained in:
2025-11-05 06:14:52 -03:00
parent f6671e0f16
commit aa3e3470cd
20 changed files with 2515 additions and 1665 deletions

View File

@@ -4,7 +4,7 @@ import { hashPassword, generateToken } from "./auth/utils";
import { registrarAtividade } from "./logsAtividades";
import { Id, Doc } from "./_generated/dataModel";
import { api } from "./_generated/api";
import type { QueryCtx } from "./_generated/server";
import type { QueryCtx, MutationCtx } from "./_generated/server";
/**
* Helper para obter a matrícula do usuário (do funcionário se houver)
@@ -20,6 +20,38 @@ async function obterMatriculaUsuario(
return undefined;
}
/**
* Helper para obter usuário autenticado (Better Auth ou Sessão)
* Usa a mesma lógica do obterPerfil para garantir consistência
*/
async function getUsuarioAutenticado(ctx: QueryCtx | MutationCtx) {
// Tentar autenticação via Better Auth primeiro
const identity = await ctx.auth.getUserIdentity();
let usuarioAtual = null;
if (identity && identity.email) {
usuarioAtual = await ctx.db
.query("usuarios")
.withIndex("by_email", (q) => q.eq("email", identity.email!))
.first();
}
// Se não encontrou via Better Auth, tentar via sessão mais recente
if (!usuarioAtual) {
const sessaoAtiva = await ctx.db
.query("sessoes")
.filter((q) => q.eq(q.field("ativo"), true))
.order("desc")
.first();
if (sessaoAtiva) {
usuarioAtual = await ctx.db.get(sessaoAtiva.usuarioId);
}
}
return usuarioAtual;
}
/**
* Associar funcionário a um usuário
*/
@@ -761,15 +793,25 @@ export const listarParaChat = query({
})
),
handler: async (ctx) => {
// Obter usuário autenticado usando função helper compartilhada
const usuarioAtual = await getUsuarioAutenticado(ctx);
// Buscar todos os usuários ativos
const usuarios = await ctx.db
.query("usuarios")
.filter((q) => q.eq(q.field("ativo"), true))
.collect();
// Filtrar o usuário atual da lista apenas se conseguimos identificá-lo com certeza
// Se não conseguimos identificar (usuarioAtual é null), retornar todos
// O frontend fará um filtro adicional usando obterPerfil como camada de segurança
const usuariosFiltrados = usuarioAtual
? usuarios.filter((u) => u._id !== usuarioAtual._id)
: usuarios;
// Buscar foto de perfil URL para cada usuário
const usuariosComFoto = await Promise.all(
usuarios.map(async (usuario) => {
usuariosFiltrados.map(async (usuario) => {
let fotoPerfilUrl = null;
if (usuario.fotoPerfil) {
fotoPerfilUrl = await ctx.storage.getUrl(usuario.fotoPerfil);