+
{/if}
diff --git a/packages/backend/convex/chat.ts b/packages/backend/convex/chat.ts
index 127b3bf..2ef4646 100644
--- a/packages/backend/convex/chat.ts
+++ b/packages/backend/convex/chat.ts
@@ -346,6 +346,7 @@ export const enviarMensagem = mutation({
mencoes: args.mencoes,
respostaPara: args.respostaPara,
enviadaEm: Date.now(),
+ lidaPor: [], // Inicializar como array vazio
});
// Detectar URLs no conteúdo e extrair preview (apenas para mensagens de texto, assíncrono)
@@ -495,14 +496,19 @@ export const agendarMensagem = mutation({
throw new Error("Você não pertence a esta conversa");
}
+ // Normalizar conteúdo para busca
+ const conteudoBusca = normalizarTextoParaBusca(args.conteudo);
+
// Criar mensagem agendada
const mensagemId = await ctx.db.insert("mensagens", {
conversaId: args.conversaId,
remetenteId: usuarioAtual._id,
tipo: "texto",
conteudo: args.conteudo,
+ conteudoBusca,
agendadaPara: args.agendadaPara,
- enviadaEm: args.agendadaPara, // Será usada quando a mensagem for enviada
+ enviadaEm: args.agendadaPara, // Será atualizado quando a mensagem for enviada
+ lidaPor: [], // Inicializar como array vazio
});
return mensagemId;
@@ -662,6 +668,29 @@ export const marcarComoLida = mutation({
});
}
+ // Atualizar status de leitura nas mensagens
+ // Buscar todas as mensagens até a mensagem atual (incluindo ela) na conversa
+ const todasMensagens = await ctx.db
+ .query("mensagens")
+ .withIndex("by_conversa", (q) => q.eq("conversaId", args.conversaId))
+ .filter((q) =>
+ q.and(
+ q.lte(q.field("enviadaEm"), mensagem.enviadaEm),
+ q.neq(q.field("remetenteId"), usuarioAtual._id) // Apenas mensagens de outros usuários
+ )
+ )
+ .collect();
+
+ // Atualizar cada mensagem para incluir o usuário atual no array lidaPor (se ainda não estiver)
+ for (const msg of todasMensagens) {
+ const lidaPor = msg.lidaPor || [];
+ if (!lidaPor.includes(usuarioAtual._id)) {
+ await ctx.db.patch(msg._id, {
+ lidaPor: [...lidaPor, usuarioAtual._id],
+ });
+ }
+ }
+
// Marcar notificações desta conversa como lidas
const notificacoes = await ctx.db
.query("notificacoes")
@@ -1455,16 +1484,33 @@ export const enviarNotificacaoReuniao = mutation({
// Criar notificação para todos os participantes
for (const participanteId of conversa.participantes) {
+ const tituloNotificacao = args.titulo || "Notificação da sala de reunião";
+ const descricaoNotificacao = args.mensagem.substring(0, 100); // Limitar descrição para push
+
+ // Criar notificação no banco
await ctx.db.insert("notificacoes", {
usuarioId: participanteId,
tipo: "nova_mensagem",
conversaId: args.conversaId,
remetenteId: usuarioAtual._id,
- titulo: args.titulo || "Notificação da sala de reunião",
+ titulo: tituloNotificacao,
descricao: args.mensagem,
lida: false,
criadaEm: Date.now(),
});
+
+ // Enviar push notification (assíncrono, não bloqueia)
+ ctx.scheduler.runAfter(0, internal.pushNotifications.enviarPushNotification, {
+ usuarioId: participanteId,
+ titulo: tituloNotificacao,
+ corpo: descricaoNotificacao,
+ data: {
+ conversaId: args.conversaId,
+ tipo: "notificacao_reuniao",
+ },
+ }).catch((error) => {
+ console.error(`Erro ao agendar push para usuário ${participanteId}:`, error);
+ });
}
return { sucesso: true };
@@ -1952,6 +1998,13 @@ export const listarTodosUsuarios = query({
const funcionario = await ctx.db.get(u.funcionarioId);
matricula = funcionario?.matricula;
}
+
+ // Buscar URL da foto de perfil se existir
+ let fotoPerfilUrl: string | null = null;
+ if (u.fotoPerfil) {
+ fotoPerfilUrl = await ctx.storage.getUrl(u.fotoPerfil);
+ }
+
return {
_id: u._id,
nome: u.nome,
@@ -1959,6 +2012,7 @@ export const listarTodosUsuarios = query({
matricula,
avatar: u.avatar,
fotoPerfil: u.fotoPerfil,
+ fotoPerfilUrl,
statusPresenca: u.statusPresenca,
statusMensagem: u.statusMensagem,
setor: u.setor,
@@ -2246,22 +2300,23 @@ export const enviarMensagensAgendadas = internalMutation({
const agora = Date.now();
// Buscar mensagens que deveriam ser enviadas
+ // Como o índice by_agendamento indexa por agendadaPara, podemos usar range query
+ // Buscar mensagens com agendadaPara entre 0 e agora (mensagens agendadas que já devem ser enviadas)
+ // Valores undefined não aparecem no índice, então só buscamos mensagens realmente agendadas
const mensagensAgendadas = await ctx.db
.query("mensagens")
- .withIndex("by_agendamento")
- .filter((q) =>
- q.and(
- q.neq(q.field("agendadaPara"), undefined),
- q.lte(q.field("agendadaPara"), agora)
- )
- )
+ .withIndex("by_agendamento", (q) => q.gte("agendadaPara", 0).lte("agendadaPara", agora))
.collect();
for (const mensagem of mensagensAgendadas) {
+ // Normalizar conteúdo para busca (se ainda não foi feito)
+ const conteudoBusca = mensagem.conteudoBusca || normalizarTextoParaBusca(mensagem.conteudo);
+
// Atualizar mensagem para "enviada"
await ctx.db.patch(mensagem._id, {
agendadaPara: undefined,
enviadaEm: agora,
+ conteudoBusca: conteudoBusca, // Garantir que tem conteúdo de busca
});
// Atualizar última mensagem da conversa
@@ -2275,19 +2330,43 @@ export const enviarMensagensAgendadas = internalMutation({
// Criar notificações para outros participantes
const remetente = await ctx.db.get(mensagem.remetenteId);
- for (const participanteId of conversa.participantes) {
- if (participanteId !== mensagem.remetenteId) {
- await ctx.db.insert("notificacoes", {
- usuarioId: participanteId,
- tipo: "nova_mensagem",
- conversaId: mensagem.conversaId,
- mensagemId: mensagem._id,
- remetenteId: mensagem.remetenteId,
- titulo: `Nova mensagem de ${remetente?.nome || "Usuário"}`,
- descricao: mensagem.conteudo.substring(0, 100),
- lida: false,
- criadaEm: agora,
- });
+ if (remetente) {
+ // Determinar tipo de notificação (se há menções)
+ const tipoNotificacao = mensagem.mencoes && mensagem.mencoes.length > 0 ? "mencao" : "nova_mensagem";
+ const titulo = tipoNotificacao === "mencao"
+ ? `${remetente.nome} mencionou você`
+ : `Nova mensagem de ${remetente.nome}`;
+ const descricao = mensagem.conteudo.substring(0, 100);
+
+ for (const participanteId of conversa.participantes) {
+ if (participanteId !== mensagem.remetenteId) {
+ // Criar notificação no banco
+ await ctx.db.insert("notificacoes", {
+ usuarioId: participanteId,
+ tipo: tipoNotificacao,
+ conversaId: mensagem.conversaId,
+ mensagemId: mensagem._id,
+ remetenteId: mensagem.remetenteId,
+ titulo,
+ descricao,
+ lida: false,
+ criadaEm: agora,
+ });
+
+ // Enviar push notification (assíncrono, não bloqueia)
+ ctx.scheduler.runAfter(0, internal.pushNotifications.enviarPushNotification, {
+ usuarioId: participanteId,
+ titulo,
+ corpo: descricao,
+ data: {
+ conversaId: mensagem.conversaId,
+ mensagemId: mensagem._id,
+ tipo: tipoNotificacao,
+ },
+ }).catch((error) => {
+ console.error(`Erro ao agendar push para usuário ${participanteId}:`, error);
+ });
+ }
}
}
}
diff --git a/packages/backend/convex/schema.ts b/packages/backend/convex/schema.ts
index 7a3fb75..c5b501e 100644
--- a/packages/backend/convex/schema.ts
+++ b/packages/backend/convex/schema.ts
@@ -671,6 +671,7 @@ export default defineSchema({
enviadaEm: v.number(),
editadaEm: v.optional(v.number()),
deletada: v.optional(v.boolean()),
+ lidaPor: v.optional(v.array(v.id("usuarios"))), // IDs dos usuários que leram a mensagem
})
.index("by_conversa", ["conversaId", "enviadaEm"])
.index("by_remetente", ["remetenteId"])