feat: enhance chat functionality with new conversation and meeting room features
- Added support for creating and managing group conversations and meeting rooms, allowing users to initiate discussions with multiple participants. - Implemented a modal for creating new conversations, including options for individual, group, and meeting room types. - Enhanced the chat list component to filter and display conversations based on type, improving user navigation. - Introduced admin functionalities for meeting rooms, enabling user management and role assignments within the chat interface. - Updated backend schema and API to accommodate new conversation types and related operations, ensuring robust data handling.
This commit is contained in:
@@ -48,6 +48,30 @@ async function getUsuarioAutenticado(ctx: QueryCtx | MutationCtx) {
|
||||
return usuarioAtual;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function para verificar se usuário é administrador de uma sala de reunião
|
||||
*/
|
||||
async function verificarPermissaoAdmin(
|
||||
ctx: QueryCtx | MutationCtx,
|
||||
conversaId: Id<"conversas">,
|
||||
usuarioId: Id<"usuarios">
|
||||
): Promise<boolean> {
|
||||
const conversa = await ctx.db.get(conversaId);
|
||||
if (!conversa) return false;
|
||||
|
||||
// Verificar se é sala de reunião
|
||||
if (conversa.tipo !== "sala_reuniao") return false;
|
||||
|
||||
// Verificar se tem array de administradores
|
||||
if (!conversa.administradores || conversa.administradores.length === 0) {
|
||||
// Se não tem administradores definidos, o criador é admin por padrão
|
||||
return conversa.criadoPor === usuarioId;
|
||||
}
|
||||
|
||||
// Verificar se está na lista de administradores
|
||||
return conversa.administradores.includes(usuarioId);
|
||||
}
|
||||
|
||||
// ========== MUTATIONS ==========
|
||||
|
||||
/**
|
||||
@@ -55,7 +79,7 @@ async function getUsuarioAutenticado(ctx: QueryCtx | MutationCtx) {
|
||||
*/
|
||||
export const criarConversa = mutation({
|
||||
args: {
|
||||
tipo: v.union(v.literal("individual"), v.literal("grupo")),
|
||||
tipo: v.union(v.literal("individual"), v.literal("grupo"), v.literal("sala_reuniao")),
|
||||
participantes: v.array(v.id("usuarios")),
|
||||
nome: v.optional(v.string()),
|
||||
avatar: v.optional(v.string()),
|
||||
@@ -86,27 +110,38 @@ export const criarConversa = mutation({
|
||||
}
|
||||
}
|
||||
|
||||
// Criar nova conversa
|
||||
const conversaId = await ctx.db.insert("conversas", {
|
||||
// Preparar dados da conversa
|
||||
const dadosConversa: any = {
|
||||
tipo: args.tipo,
|
||||
nome: args.nome,
|
||||
avatar: args.avatar,
|
||||
participantes: args.participantes,
|
||||
criadoPor: usuarioAtual._id,
|
||||
criadoEm: Date.now(),
|
||||
});
|
||||
};
|
||||
|
||||
// Se for sala de reunião, adicionar administradores (criador sempre é admin)
|
||||
if (args.tipo === "sala_reuniao") {
|
||||
dadosConversa.administradores = [usuarioAtual._id];
|
||||
}
|
||||
|
||||
// Criar nova conversa
|
||||
const conversaId = await ctx.db.insert("conversas", dadosConversa);
|
||||
|
||||
// Criar notificações para outros participantes
|
||||
if (args.tipo === "grupo") {
|
||||
if (args.tipo === "grupo" || args.tipo === "sala_reuniao") {
|
||||
const tipoNotificacao = args.tipo === "sala_reuniao" ? "adicionado_grupo" : "adicionado_grupo";
|
||||
const tipoTexto = args.tipo === "sala_reuniao" ? "sala de reunião" : "grupo";
|
||||
|
||||
for (const participanteId of args.participantes) {
|
||||
if (participanteId !== usuarioAtual._id) {
|
||||
await ctx.db.insert("notificacoes", {
|
||||
usuarioId: participanteId,
|
||||
tipo: "adicionado_grupo",
|
||||
tipo: tipoNotificacao,
|
||||
conversaId,
|
||||
remetenteId: usuarioAtual._id,
|
||||
titulo: "Adicionado a grupo",
|
||||
descricao: `Você foi adicionado ao grupo "${
|
||||
titulo: args.tipo === "sala_reuniao" ? "Adicionado a sala de reunião" : "Adicionado a grupo",
|
||||
descricao: `Você foi adicionado à ${tipoTexto} "${
|
||||
args.nome || "Sem nome"
|
||||
}" por ${usuarioAtual.nome}`,
|
||||
lida: false,
|
||||
@@ -120,6 +155,69 @@ export const criarConversa = mutation({
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Cria uma nova sala de reunião (wrapper específico para facilitar uso)
|
||||
*/
|
||||
export const criarSalaReuniao = mutation({
|
||||
args: {
|
||||
nome: v.string(),
|
||||
participantes: v.array(v.id("usuarios")),
|
||||
avatar: v.optional(v.string()),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
const usuarioAtual = await getUsuarioAutenticado(ctx);
|
||||
if (!usuarioAtual) throw new Error("Não autenticado");
|
||||
|
||||
// Validar nome
|
||||
if (!args.nome || args.nome.trim().length === 0) {
|
||||
throw new Error("O nome da sala de reunião é obrigatório");
|
||||
}
|
||||
|
||||
// Validar participantes
|
||||
const participantesUnicos = [...new Set(args.participantes)];
|
||||
if (!participantesUnicos.includes(usuarioAtual._id)) {
|
||||
participantesUnicos.push(usuarioAtual._id);
|
||||
}
|
||||
|
||||
// Preparar dados da conversa
|
||||
const dadosConversa: any = {
|
||||
tipo: "sala_reuniao" as const,
|
||||
nome: args.nome.trim(),
|
||||
avatar: args.avatar,
|
||||
participantes: participantesUnicos,
|
||||
criadoPor: usuarioAtual._id,
|
||||
criadoEm: Date.now(),
|
||||
administradores: [usuarioAtual._id], // Criador sempre é admin
|
||||
};
|
||||
|
||||
// Criar nova conversa
|
||||
const conversaId = await ctx.db.insert("conversas", dadosConversa);
|
||||
|
||||
// Criar notificações para outros participantes
|
||||
const tipoNotificacao = "adicionado_grupo";
|
||||
const tipoTexto = "sala de reunião";
|
||||
|
||||
for (const participanteId of participantesUnicos) {
|
||||
if (participanteId !== usuarioAtual._id) {
|
||||
await ctx.db.insert("notificacoes", {
|
||||
usuarioId: participanteId,
|
||||
tipo: tipoNotificacao,
|
||||
conversaId,
|
||||
remetenteId: usuarioAtual._id,
|
||||
titulo: "Adicionado a sala de reunião",
|
||||
descricao: `Você foi adicionado à ${tipoTexto} "${
|
||||
args.nome || "Sem nome"
|
||||
}" por ${usuarioAtual.nome}`,
|
||||
lida: false,
|
||||
criadaEm: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return conversaId;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Cria ou busca uma conversa individual com outro usuário
|
||||
*/
|
||||
@@ -840,7 +938,10 @@ export const deletarMensagem = mutation({
|
||||
throw new Error("Mensagem inválida");
|
||||
}
|
||||
|
||||
if (mensagem.remetenteId !== usuarioAtual._id) {
|
||||
// Verificar se é admin de sala de reunião ou se é o próprio remetente
|
||||
const isAdmin = await verificarPermissaoAdmin(ctx, mensagem.conversaId, usuarioAtual._id);
|
||||
|
||||
if (mensagem.remetenteId !== usuarioAtual._id && !isAdmin) {
|
||||
throw new Error("Você só pode deletar suas próprias mensagens");
|
||||
}
|
||||
|
||||
@@ -853,8 +954,370 @@ export const deletarMensagem = mutation({
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Deleta uma mensagem como administrador (com notificação ao remetente)
|
||||
*/
|
||||
export const deletarMensagemComoAdmin = mutation({
|
||||
args: {
|
||||
mensagemId: v.id("mensagens"),
|
||||
},
|
||||
returns: v.object({ sucesso: v.boolean(), erro: v.optional(v.string()) }),
|
||||
handler: async (ctx, args) => {
|
||||
const usuarioAtual = await getUsuarioAutenticado(ctx);
|
||||
if (!usuarioAtual) {
|
||||
return { sucesso: false, erro: "Não autenticado" };
|
||||
}
|
||||
|
||||
const mensagem = await ctx.db.get(args.mensagemId);
|
||||
if (!mensagem) {
|
||||
return { sucesso: false, erro: "Mensagem não encontrada" };
|
||||
}
|
||||
|
||||
// SEGURANÇA: Verificar se a mensagem pertence a uma conversa onde o usuário é participante
|
||||
const conversa = await ctx.db.get(mensagem.conversaId);
|
||||
if (!conversa || !conversa.participantes.includes(usuarioAtual._id)) {
|
||||
return { sucesso: false, erro: "Você não tem acesso a esta mensagem" };
|
||||
}
|
||||
|
||||
// SEGURANÇA: Verificar se o remetente da mensagem é participante da conversa
|
||||
if (!conversa.participantes.includes(mensagem.remetenteId)) {
|
||||
return { sucesso: false, erro: "Mensagem inválida" };
|
||||
}
|
||||
|
||||
// Verificar se usuário é administrador da sala
|
||||
const isAdmin = await verificarPermissaoAdmin(ctx, mensagem.conversaId, usuarioAtual._id);
|
||||
if (!isAdmin) {
|
||||
return { sucesso: false, erro: "Apenas administradores podem deletar mensagens de outros usuários" };
|
||||
}
|
||||
|
||||
// Não permitir deletar mensagem já deletada
|
||||
if (mensagem.deletada) {
|
||||
return { sucesso: false, erro: "Mensagem já foi deletada" };
|
||||
}
|
||||
|
||||
// Deletar mensagem
|
||||
await ctx.db.patch(args.mensagemId, {
|
||||
deletada: true,
|
||||
conteudo: "Mensagem deletada por administrador",
|
||||
});
|
||||
|
||||
// Criar notificação para o remetente original (se não for o próprio admin)
|
||||
if (mensagem.remetenteId !== usuarioAtual._id) {
|
||||
const remetente = await ctx.db.get(mensagem.remetenteId);
|
||||
if (remetente) {
|
||||
await ctx.db.insert("notificacoes", {
|
||||
usuarioId: mensagem.remetenteId,
|
||||
tipo: "nova_mensagem",
|
||||
conversaId: mensagem.conversaId,
|
||||
mensagemId: args.mensagemId,
|
||||
remetenteId: usuarioAtual._id,
|
||||
titulo: "Mensagem deletada",
|
||||
descricao: `Sua mensagem foi deletada por um administrador da sala "${conversa.nome || "Sem nome"}"`,
|
||||
lida: false,
|
||||
criadaEm: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { sucesso: true };
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Adiciona um participante à sala de reunião (apenas administradores)
|
||||
*/
|
||||
export const adicionarParticipanteSala = mutation({
|
||||
args: {
|
||||
conversaId: v.id("conversas"),
|
||||
participanteId: v.id("usuarios"),
|
||||
},
|
||||
returns: v.object({ sucesso: v.boolean(), erro: v.optional(v.string()) }),
|
||||
handler: async (ctx, args) => {
|
||||
const usuarioAtual = await getUsuarioAutenticado(ctx);
|
||||
if (!usuarioAtual) {
|
||||
return { sucesso: false, erro: "Não autenticado" };
|
||||
}
|
||||
|
||||
const conversa = await ctx.db.get(args.conversaId);
|
||||
if (!conversa) {
|
||||
return { sucesso: false, erro: "Sala de reunião não encontrada" };
|
||||
}
|
||||
|
||||
// Verificar se é sala de reunião
|
||||
if (conversa.tipo !== "sala_reuniao") {
|
||||
return { sucesso: false, erro: "Esta funcionalidade é apenas para salas de reunião" };
|
||||
}
|
||||
|
||||
// Verificar se usuário é administrador
|
||||
const isAdmin = await verificarPermissaoAdmin(ctx, args.conversaId, usuarioAtual._id);
|
||||
if (!isAdmin) {
|
||||
return { sucesso: false, erro: "Apenas administradores podem adicionar participantes" };
|
||||
}
|
||||
|
||||
// Verificar se participante já está na sala
|
||||
if (conversa.participantes.includes(args.participanteId)) {
|
||||
return { sucesso: false, erro: "Usuário já é participante desta sala" };
|
||||
}
|
||||
|
||||
// Verificar se participante existe
|
||||
const participante = await ctx.db.get(args.participanteId);
|
||||
if (!participante) {
|
||||
return { sucesso: false, erro: "Usuário não encontrado" };
|
||||
}
|
||||
|
||||
// Adicionar participante
|
||||
const novosParticipantes = [...conversa.participantes, args.participanteId];
|
||||
await ctx.db.patch(args.conversaId, {
|
||||
participantes: novosParticipantes,
|
||||
});
|
||||
|
||||
// Criar notificação para o novo participante
|
||||
await ctx.db.insert("notificacoes", {
|
||||
usuarioId: args.participanteId,
|
||||
tipo: "adicionado_grupo",
|
||||
conversaId: args.conversaId,
|
||||
remetenteId: usuarioAtual._id,
|
||||
titulo: "Adicionado a sala de reunião",
|
||||
descricao: `Você foi adicionado à sala de reunião "${conversa.nome || "Sem nome"}" por ${usuarioAtual.nome}`,
|
||||
lida: false,
|
||||
criadaEm: Date.now(),
|
||||
});
|
||||
|
||||
return { sucesso: true };
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Remove um participante da sala de reunião (apenas administradores, não pode remover outros admins)
|
||||
*/
|
||||
export const removerParticipanteSala = mutation({
|
||||
args: {
|
||||
conversaId: v.id("conversas"),
|
||||
participanteId: v.id("usuarios"),
|
||||
},
|
||||
returns: v.object({ sucesso: v.boolean(), erro: v.optional(v.string()) }),
|
||||
handler: async (ctx, args) => {
|
||||
const usuarioAtual = await getUsuarioAutenticado(ctx);
|
||||
if (!usuarioAtual) {
|
||||
return { sucesso: false, erro: "Não autenticado" };
|
||||
}
|
||||
|
||||
const conversa = await ctx.db.get(args.conversaId);
|
||||
if (!conversa) {
|
||||
return { sucesso: false, erro: "Sala de reunião não encontrada" };
|
||||
}
|
||||
|
||||
// Verificar se é sala de reunião
|
||||
if (conversa.tipo !== "sala_reuniao") {
|
||||
return { sucesso: false, erro: "Esta funcionalidade é apenas para salas de reunião" };
|
||||
}
|
||||
|
||||
// Verificar se usuário é administrador
|
||||
const isAdmin = await verificarPermissaoAdmin(ctx, args.conversaId, usuarioAtual._id);
|
||||
if (!isAdmin) {
|
||||
return { sucesso: false, erro: "Apenas administradores podem remover participantes" };
|
||||
}
|
||||
|
||||
// Verificar se participante está na sala
|
||||
if (!conversa.participantes.includes(args.participanteId)) {
|
||||
return { sucesso: false, erro: "Usuário não é participante desta sala" };
|
||||
}
|
||||
|
||||
// Verificar se está tentando remover outro administrador
|
||||
const isParticipanteAdmin = await verificarPermissaoAdmin(ctx, args.conversaId, args.participanteId);
|
||||
if (isParticipanteAdmin) {
|
||||
return { sucesso: false, erro: "Não é possível remover outros administradores" };
|
||||
}
|
||||
|
||||
// Remover participante
|
||||
const novosParticipantes = conversa.participantes.filter((p) => p !== args.participanteId);
|
||||
await ctx.db.patch(args.conversaId, {
|
||||
participantes: novosParticipantes,
|
||||
});
|
||||
|
||||
// Criar notificação para o participante removido
|
||||
const participanteRemovido = await ctx.db.get(args.participanteId);
|
||||
if (participanteRemovido) {
|
||||
await ctx.db.insert("notificacoes", {
|
||||
usuarioId: args.participanteId,
|
||||
tipo: "nova_mensagem",
|
||||
conversaId: args.conversaId,
|
||||
remetenteId: usuarioAtual._id,
|
||||
titulo: "Removido da sala de reunião",
|
||||
descricao: `Você foi removido da sala de reunião "${conversa.nome || "Sem nome"}" por ${usuarioAtual.nome}`,
|
||||
lida: false,
|
||||
criadaEm: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
return { sucesso: true };
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Promove um participante a administrador (apenas administradores)
|
||||
*/
|
||||
export const promoverAdministrador = mutation({
|
||||
args: {
|
||||
conversaId: v.id("conversas"),
|
||||
participanteId: v.id("usuarios"),
|
||||
},
|
||||
returns: v.object({ sucesso: v.boolean(), erro: v.optional(v.string()) }),
|
||||
handler: async (ctx, args) => {
|
||||
const usuarioAtual = await getUsuarioAutenticado(ctx);
|
||||
if (!usuarioAtual) {
|
||||
return { sucesso: false, erro: "Não autenticado" };
|
||||
}
|
||||
|
||||
const conversa = await ctx.db.get(args.conversaId);
|
||||
if (!conversa) {
|
||||
return { sucesso: false, erro: "Sala de reunião não encontrada" };
|
||||
}
|
||||
|
||||
// Verificar se é sala de reunião
|
||||
if (conversa.tipo !== "sala_reuniao") {
|
||||
return { sucesso: false, erro: "Esta funcionalidade é apenas para salas de reunião" };
|
||||
}
|
||||
|
||||
// Verificar se usuário é administrador
|
||||
const isAdmin = await verificarPermissaoAdmin(ctx, args.conversaId, usuarioAtual._id);
|
||||
if (!isAdmin) {
|
||||
return { sucesso: false, erro: "Apenas administradores podem promover outros administradores" };
|
||||
}
|
||||
|
||||
// Verificar se participante está na sala
|
||||
if (!conversa.participantes.includes(args.participanteId)) {
|
||||
return { sucesso: false, erro: "Usuário não é participante desta sala" };
|
||||
}
|
||||
|
||||
// Verificar se já é administrador
|
||||
const jaEhAdmin = await verificarPermissaoAdmin(ctx, args.conversaId, args.participanteId);
|
||||
if (jaEhAdmin) {
|
||||
return { sucesso: false, erro: "Usuário já é administrador desta sala" };
|
||||
}
|
||||
|
||||
// Obter lista atual de administradores ou criar nova
|
||||
const administradoresAtuais = conversa.administradores || [];
|
||||
|
||||
// Se não está na lista, adicionar
|
||||
if (!administradoresAtuais.includes(args.participanteId)) {
|
||||
const novosAdministradores = [...administradoresAtuais, args.participanteId];
|
||||
await ctx.db.patch(args.conversaId, {
|
||||
administradores: novosAdministradores,
|
||||
});
|
||||
|
||||
// Criar notificação para o novo administrador
|
||||
const novoAdmin = await ctx.db.get(args.participanteId);
|
||||
if (novoAdmin) {
|
||||
await ctx.db.insert("notificacoes", {
|
||||
usuarioId: args.participanteId,
|
||||
tipo: "nova_mensagem",
|
||||
conversaId: args.conversaId,
|
||||
remetenteId: usuarioAtual._id,
|
||||
titulo: "Promovido a administrador",
|
||||
descricao: `Você foi promovido a administrador da sala de reunião "${conversa.nome || "Sem nome"}" por ${usuarioAtual.nome}`,
|
||||
lida: false,
|
||||
criadaEm: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { sucesso: true };
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Rebaixa um administrador a participante (apenas administradores, não pode rebaixar a si mesmo)
|
||||
*/
|
||||
export const rebaixarAdministrador = mutation({
|
||||
args: {
|
||||
conversaId: v.id("conversas"),
|
||||
participanteId: v.id("usuarios"),
|
||||
},
|
||||
returns: v.object({ sucesso: v.boolean(), erro: v.optional(v.string()) }),
|
||||
handler: async (ctx, args) => {
|
||||
const usuarioAtual = await getUsuarioAutenticado(ctx);
|
||||
if (!usuarioAtual) {
|
||||
return { sucesso: false, erro: "Não autenticado" };
|
||||
}
|
||||
|
||||
const conversa = await ctx.db.get(args.conversaId);
|
||||
if (!conversa) {
|
||||
return { sucesso: false, erro: "Sala de reunião não encontrada" };
|
||||
}
|
||||
|
||||
// Verificar se é sala de reunião
|
||||
if (conversa.tipo !== "sala_reuniao") {
|
||||
return { sucesso: false, erro: "Esta funcionalidade é apenas para salas de reunião" };
|
||||
}
|
||||
|
||||
// Verificar se usuário é administrador
|
||||
const isAdmin = await verificarPermissaoAdmin(ctx, args.conversaId, usuarioAtual._id);
|
||||
if (!isAdmin) {
|
||||
return { sucesso: false, erro: "Apenas administradores podem rebaixar outros administradores" };
|
||||
}
|
||||
|
||||
// Não permitir rebaixar a si mesmo
|
||||
if (args.participanteId === usuarioAtual._id) {
|
||||
return { sucesso: false, erro: "Você não pode rebaixar a si mesmo" };
|
||||
}
|
||||
|
||||
// Verificar se é administrador
|
||||
const isParticipanteAdmin = await verificarPermissaoAdmin(ctx, args.conversaId, args.participanteId);
|
||||
if (!isParticipanteAdmin) {
|
||||
return { sucesso: false, erro: "Usuário não é administrador desta sala" };
|
||||
}
|
||||
|
||||
// Não permitir rebaixar o criador da sala
|
||||
if (conversa.criadoPor === args.participanteId) {
|
||||
return { sucesso: false, erro: "Não é possível rebaixar o criador da sala" };
|
||||
}
|
||||
|
||||
// Remover da lista de administradores
|
||||
const administradoresAtuais = conversa.administradores || [];
|
||||
const novosAdministradores = administradoresAtuais.filter((adminId) => adminId !== args.participanteId);
|
||||
|
||||
await ctx.db.patch(args.conversaId, {
|
||||
administradores: novosAdministradores.length > 0 ? novosAdministradores : undefined,
|
||||
});
|
||||
|
||||
// Criar notificação para o administrador rebaixado
|
||||
const adminRebaixado = await ctx.db.get(args.participanteId);
|
||||
if (adminRebaixado) {
|
||||
await ctx.db.insert("notificacoes", {
|
||||
usuarioId: args.participanteId,
|
||||
tipo: "nova_mensagem",
|
||||
conversaId: args.conversaId,
|
||||
remetenteId: usuarioAtual._id,
|
||||
titulo: "Rebaixado de administrador",
|
||||
descricao: `Você foi rebaixado de administrador da sala de reunião "${conversa.nome || "Sem nome"}" por ${usuarioAtual.nome}`,
|
||||
lida: false,
|
||||
criadaEm: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
return { sucesso: true };
|
||||
},
|
||||
});
|
||||
|
||||
// ========== QUERIES ==========
|
||||
|
||||
/**
|
||||
* Verifica se o usuário atual é administrador de uma sala de reunião
|
||||
*/
|
||||
export const verificarSeEhAdmin = query({
|
||||
args: {
|
||||
conversaId: v.id("conversas"),
|
||||
},
|
||||
returns: v.boolean(),
|
||||
handler: async (ctx, args) => {
|
||||
const usuarioAtual = await getUsuarioAutenticado(ctx);
|
||||
if (!usuarioAtual) return false;
|
||||
|
||||
return await verificarPermissaoAdmin(ctx, args.conversaId, usuarioAtual._id);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Lista todas as conversas do usuário logado
|
||||
* SEGURANÇA: Usuário só vê conversas onde é participante
|
||||
@@ -947,11 +1410,36 @@ export const listarConversas = query({
|
||||
).length;
|
||||
}
|
||||
|
||||
// Verificar se usuário é administrador (apenas para salas de reunião)
|
||||
const isAdmin = conversa.tipo === "sala_reuniao"
|
||||
? await verificarPermissaoAdmin(ctx, conversa._id, usuarioAtual._id)
|
||||
: false;
|
||||
|
||||
// Enriquecer participantes com fotoPerfilUrl (para grupos e salas)
|
||||
const participantesInfo = await Promise.all(
|
||||
participantes
|
||||
.filter((p) => p !== null)
|
||||
.map(async (participante) => {
|
||||
if (!participante) return null;
|
||||
|
||||
let fotoPerfilUrl = null;
|
||||
if (participante.fotoPerfil) {
|
||||
fotoPerfilUrl = await ctx.storage.getUrl(participante.fotoPerfil);
|
||||
}
|
||||
|
||||
return {
|
||||
...participante,
|
||||
fotoPerfilUrl,
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
...conversa,
|
||||
outroUsuario,
|
||||
participantesInfo: participantes.filter((p) => p !== null),
|
||||
participantesInfo: participantesInfo.filter((p) => p !== null),
|
||||
naoLidas,
|
||||
isAdmin, // Adicionar flag de admin
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user