feat: enhance employee and symbol management with new features, improved UI components, and backend schema updates
This commit is contained in:
320
packages/backend/convex/usuarios.ts
Normal file
320
packages/backend/convex/usuarios.ts
Normal file
@@ -0,0 +1,320 @@
|
||||
import { v } from "convex/values";
|
||||
import { mutation, query } from "./_generated/server";
|
||||
import { hashPassword } from "./auth/utils";
|
||||
|
||||
/**
|
||||
* Criar novo usuário (apenas TI)
|
||||
*/
|
||||
export const criar = mutation({
|
||||
args: {
|
||||
matricula: v.string(),
|
||||
nome: v.string(),
|
||||
email: v.string(),
|
||||
roleId: v.id("roles"),
|
||||
funcionarioId: v.optional(v.id("funcionarios")),
|
||||
senhaInicial: v.string(),
|
||||
},
|
||||
returns: v.union(
|
||||
v.object({ sucesso: v.literal(true), usuarioId: v.id("usuarios") }),
|
||||
v.object({ sucesso: v.literal(false), erro: v.string() })
|
||||
),
|
||||
handler: async (ctx, args) => {
|
||||
// Verificar se matrícula já existe
|
||||
const existente = await ctx.db
|
||||
.query("usuarios")
|
||||
.withIndex("by_matricula", (q) => q.eq("matricula", args.matricula))
|
||||
.first();
|
||||
|
||||
if (existente) {
|
||||
return { sucesso: false as const, erro: "Matrícula já cadastrada" };
|
||||
}
|
||||
|
||||
// Verificar se email já existe
|
||||
const emailExistente = await ctx.db
|
||||
.query("usuarios")
|
||||
.withIndex("by_email", (q) => q.eq("email", args.email))
|
||||
.first();
|
||||
|
||||
if (emailExistente) {
|
||||
return { sucesso: false as const, erro: "E-mail já cadastrado" };
|
||||
}
|
||||
|
||||
// Gerar hash da senha inicial
|
||||
const senhaHash = await hashPassword(args.senhaInicial);
|
||||
|
||||
// Criar usuário
|
||||
const usuarioId = await ctx.db.insert("usuarios", {
|
||||
matricula: args.matricula,
|
||||
senhaHash,
|
||||
nome: args.nome,
|
||||
email: args.email,
|
||||
funcionarioId: args.funcionarioId,
|
||||
roleId: args.roleId,
|
||||
ativo: true,
|
||||
primeiroAcesso: true,
|
||||
criadoEm: Date.now(),
|
||||
atualizadoEm: Date.now(),
|
||||
});
|
||||
|
||||
return { sucesso: true as const, usuarioId };
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Listar todos os usuários com filtros
|
||||
*/
|
||||
export const listar = query({
|
||||
args: {
|
||||
setor: v.optional(v.string()),
|
||||
matricula: v.optional(v.string()),
|
||||
ativo: v.optional(v.boolean()),
|
||||
},
|
||||
returns: v.array(
|
||||
v.object({
|
||||
_id: v.id("usuarios"),
|
||||
matricula: v.string(),
|
||||
nome: v.string(),
|
||||
email: v.string(),
|
||||
ativo: v.boolean(),
|
||||
primeiroAcesso: v.boolean(),
|
||||
ultimoAcesso: v.optional(v.number()),
|
||||
criadoEm: v.number(),
|
||||
role: v.object({
|
||||
_id: v.id("roles"),
|
||||
nome: v.string(),
|
||||
nivel: v.number(),
|
||||
setor: v.optional(v.string()),
|
||||
}),
|
||||
funcionario: v.optional(
|
||||
v.object({
|
||||
_id: v.id("funcionarios"),
|
||||
nome: v.string(),
|
||||
simboloTipo: v.union(
|
||||
v.literal("cargo_comissionado"),
|
||||
v.literal("funcao_gratificada")
|
||||
),
|
||||
})
|
||||
),
|
||||
})
|
||||
),
|
||||
handler: async (ctx, args) => {
|
||||
let usuarios = await ctx.db.query("usuarios").collect();
|
||||
|
||||
// Filtrar por matrícula
|
||||
if (args.matricula) {
|
||||
usuarios = usuarios.filter((u) =>
|
||||
u.matricula.includes(args.matricula!)
|
||||
);
|
||||
}
|
||||
|
||||
// Filtrar por ativo
|
||||
if (args.ativo !== undefined) {
|
||||
usuarios = usuarios.filter((u) => u.ativo === args.ativo);
|
||||
}
|
||||
|
||||
// Buscar roles e funcionários
|
||||
const resultado = [];
|
||||
for (const usuario of usuarios) {
|
||||
const role = await ctx.db.get(usuario.roleId);
|
||||
if (!role) continue;
|
||||
|
||||
// Filtrar por setor
|
||||
if (args.setor && role.setor !== args.setor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let funcionario = undefined;
|
||||
if (usuario.funcionarioId) {
|
||||
const func = await ctx.db.get(usuario.funcionarioId);
|
||||
if (func) {
|
||||
funcionario = {
|
||||
_id: func._id,
|
||||
nome: func.nome,
|
||||
simboloTipo: func.simboloTipo,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
resultado.push({
|
||||
_id: usuario._id,
|
||||
matricula: usuario.matricula,
|
||||
nome: usuario.nome,
|
||||
email: usuario.email,
|
||||
ativo: usuario.ativo,
|
||||
primeiroAcesso: usuario.primeiroAcesso,
|
||||
ultimoAcesso: usuario.ultimoAcesso,
|
||||
criadoEm: usuario.criadoEm,
|
||||
role: {
|
||||
_id: role._id,
|
||||
nome: role.nome,
|
||||
nivel: role.nivel,
|
||||
setor: role.setor,
|
||||
},
|
||||
funcionario,
|
||||
});
|
||||
}
|
||||
|
||||
return resultado;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Ativar/Desativar usuário
|
||||
*/
|
||||
export const alterarStatus = mutation({
|
||||
args: {
|
||||
usuarioId: v.id("usuarios"),
|
||||
ativo: v.boolean(),
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
await ctx.db.patch(args.usuarioId, {
|
||||
ativo: args.ativo,
|
||||
atualizadoEm: Date.now(),
|
||||
});
|
||||
|
||||
// Se desativar, desativar todas as sessões
|
||||
if (!args.ativo) {
|
||||
const sessoes = await ctx.db
|
||||
.query("sessoes")
|
||||
.withIndex("by_usuario", (q) => q.eq("usuarioId", args.usuarioId))
|
||||
.collect();
|
||||
|
||||
for (const sessao of sessoes) {
|
||||
await ctx.db.patch(sessao._id, { ativo: false });
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Resetar senha do usuário
|
||||
*/
|
||||
export const resetarSenha = mutation({
|
||||
args: {
|
||||
usuarioId: v.id("usuarios"),
|
||||
novaSenha: v.string(),
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
const senhaHash = await hashPassword(args.novaSenha);
|
||||
|
||||
await ctx.db.patch(args.usuarioId, {
|
||||
senhaHash,
|
||||
primeiroAcesso: true,
|
||||
atualizadoEm: Date.now(),
|
||||
});
|
||||
|
||||
// Desativar todas as sessões
|
||||
const sessoes = await ctx.db
|
||||
.query("sessoes")
|
||||
.withIndex("by_usuario", (q) => q.eq("usuarioId", args.usuarioId))
|
||||
.collect();
|
||||
|
||||
for (const sessao of sessoes) {
|
||||
await ctx.db.patch(sessao._id, { ativo: false });
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Excluir usuário
|
||||
*/
|
||||
export const excluir = mutation({
|
||||
args: {
|
||||
usuarioId: v.id("usuarios"),
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
// Excluir sessões
|
||||
const sessoes = await ctx.db
|
||||
.query("sessoes")
|
||||
.withIndex("by_usuario", (q) => q.eq("usuarioId", args.usuarioId))
|
||||
.collect();
|
||||
|
||||
for (const sessao of sessoes) {
|
||||
await ctx.db.delete(sessao._id);
|
||||
}
|
||||
|
||||
// Excluir usuário
|
||||
await ctx.db.delete(args.usuarioId);
|
||||
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Ativar usuário
|
||||
*/
|
||||
export const ativar = mutation({
|
||||
args: {
|
||||
id: v.id("usuarios"),
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
await ctx.db.patch(args.id, {
|
||||
ativo: true,
|
||||
atualizadoEm: Date.now(),
|
||||
});
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Desativar usuário
|
||||
*/
|
||||
export const desativar = mutation({
|
||||
args: {
|
||||
id: v.id("usuarios"),
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
await ctx.db.patch(args.id, {
|
||||
ativo: false,
|
||||
atualizadoEm: Date.now(),
|
||||
});
|
||||
|
||||
// Desativar todas as sessões
|
||||
const sessoes = await ctx.db
|
||||
.query("sessoes")
|
||||
.withIndex("by_usuario", (q) => q.eq("usuarioId", args.id))
|
||||
.collect();
|
||||
|
||||
for (const sessao of sessoes) {
|
||||
await ctx.db.patch(sessao._id, { ativo: false });
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Alterar role de um usuário
|
||||
*/
|
||||
export const alterarRole = mutation({
|
||||
args: {
|
||||
usuarioId: v.id("usuarios"),
|
||||
novaRoleId: v.id("roles"),
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
// Verificar se a role existe
|
||||
const role = await ctx.db.get(args.novaRoleId);
|
||||
if (!role) {
|
||||
throw new Error("Role não encontrada");
|
||||
}
|
||||
|
||||
// Atualizar usuário
|
||||
await ctx.db.patch(args.usuarioId, {
|
||||
roleId: args.novaRoleId,
|
||||
atualizadoEm: Date.now(),
|
||||
});
|
||||
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user