feat: implement comprehensive chat system with user presence management, notification handling, and avatar integration; enhance UI components for improved user experience

This commit is contained in:
2025-10-28 11:57:54 -03:00
parent 81e6eb4a42
commit ee2c9c3ae0
47 changed files with 8274 additions and 195 deletions

View File

@@ -198,11 +198,28 @@ export default defineSchema({
ultimoAcesso: v.optional(v.number()),
criadoEm: v.number(),
atualizadoEm: v.number(),
// Campos de Chat e Perfil
avatar: v.optional(v.string()), // "avatar-1" até "avatar-15" ou storageId
fotoPerfil: v.optional(v.id("_storage")),
setor: v.optional(v.string()),
statusMensagem: v.optional(v.string()), // max 100 chars
statusPresenca: v.optional(v.union(
v.literal("online"),
v.literal("offline"),
v.literal("ausente"),
v.literal("externo"),
v.literal("em_reuniao")
)),
ultimaAtividade: v.optional(v.number()), // timestamp
notificacoesAtivadas: v.optional(v.boolean()),
somNotificacao: v.optional(v.boolean()),
})
.index("by_matricula", ["matricula"])
.index("by_email", ["email"])
.index("by_role", ["roleId"])
.index("by_ativo", ["ativo"]),
.index("by_ativo", ["ativo"])
.index("by_status_presenca", ["statusPresenca"]),
roles: defineTable({
nome: v.string(), // "admin", "ti", "usuario_avancado", "usuario"
@@ -294,4 +311,82 @@ export default defineSchema({
descricao: v.string(),
})
.index("by_chave", ["chave"]),
// Sistema de Chat
conversas: defineTable({
tipo: v.union(v.literal("individual"), v.literal("grupo")),
nome: v.optional(v.string()), // nome do grupo
avatar: v.optional(v.string()), // avatar do grupo
participantes: v.array(v.id("usuarios")), // IDs dos participantes
ultimaMensagem: v.optional(v.string()),
ultimaMensagemTimestamp: v.optional(v.number()),
criadoPor: v.id("usuarios"),
criadoEm: v.number(),
})
.index("by_criado_por", ["criadoPor"])
.index("by_tipo", ["tipo"])
.index("by_ultima_mensagem", ["ultimaMensagemTimestamp"]),
mensagens: defineTable({
conversaId: v.id("conversas"),
remetenteId: v.id("usuarios"),
tipo: v.union(
v.literal("texto"),
v.literal("arquivo"),
v.literal("imagem")
),
conteudo: v.string(), // texto ou nome do arquivo
arquivoId: v.optional(v.id("_storage")),
arquivoNome: v.optional(v.string()),
arquivoTamanho: v.optional(v.number()),
arquivoTipo: v.optional(v.string()),
reagiuPor: v.optional(v.array(v.object({
usuarioId: v.id("usuarios"),
emoji: v.string()
}))),
mencoes: v.optional(v.array(v.id("usuarios"))),
agendadaPara: v.optional(v.number()), // timestamp
enviadaEm: v.number(),
editadaEm: v.optional(v.number()),
deletada: v.optional(v.boolean()),
})
.index("by_conversa", ["conversaId", "enviadaEm"])
.index("by_remetente", ["remetenteId"])
.index("by_agendamento", ["agendadaPara"]),
leituras: defineTable({
conversaId: v.id("conversas"),
usuarioId: v.id("usuarios"),
ultimaMensagemLida: v.id("mensagens"),
lidaEm: v.number(),
})
.index("by_conversa_usuario", ["conversaId", "usuarioId"])
.index("by_usuario", ["usuarioId"]),
notificacoes: defineTable({
usuarioId: v.id("usuarios"),
tipo: v.union(
v.literal("nova_mensagem"),
v.literal("mencao"),
v.literal("grupo_criado"),
v.literal("adicionado_grupo")
),
conversaId: v.optional(v.id("conversas")),
mensagemId: v.optional(v.id("mensagens")),
remetenteId: v.optional(v.id("usuarios")),
titulo: v.string(),
descricao: v.string(),
lida: v.boolean(),
criadaEm: v.number(),
})
.index("by_usuario", ["usuarioId", "lida", "criadaEm"])
.index("by_usuario_lida", ["usuarioId", "lida"]),
digitando: defineTable({
conversaId: v.id("conversas"),
usuarioId: v.id("usuarios"),
iniciouEm: v.number(),
})
.index("by_conversa", ["conversaId", "iniciouEm"])
.index("by_usuario", ["usuarioId"]),
});