refactor: enhance role management UI and integrate profile management features

- Introduced a modal for managing user profiles, allowing for the creation and editing of profiles with improved state management.
- Updated the role filtering logic to enhance type safety and readability.
- Refactored UI components for better user experience, including improved button states and loading indicators.
- Removed outdated code related to permissions and streamlined the overall structure for maintainability.
This commit is contained in:
2025-11-03 15:14:33 -03:00
parent c1d9958c9f
commit 0d011b8f42
38 changed files with 2664 additions and 4919 deletions

View File

@@ -128,36 +128,69 @@ export const listar = query({
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(),
bloqueado: v.optional(v.boolean()),
motivoBloqueio: v.optional(v.string()),
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")
),
})
),
})
),
// returns: v.array(
// v.object({
// _id: v.id("usuarios"),
// matricula: v.string(),
// nome: v.string(),
// email: v.string(),
// ativo: v.boolean(),
// bloqueado: v.optional(v.boolean()),
// motivoBloqueio: v.optional(v.string()),
// primeiroAcesso: v.boolean(),
// ultimoAcesso: v.optional(v.number()),
// criadoEm: v.number(),
// role: v.union(
// v.object({
// _id: v.id("roles"),
// _creationTime: v.optional(v.number()),
// criadoPor: v.optional(v.id("usuarios")),
// customizado: v.optional(v.boolean()),
// descricao: v.string(),
// editavel: v.optional(v.boolean()),
// nome: v.string(),
// nivel: v.number(),
// setor: v.optional(v.string()),
// }),
// v.object({
// _id: v.id("roles"),
// _creationTime: v.optional(v.number()),
// criadoPor: v.optional(v.id("usuarios")),
// customizado: v.optional(v.boolean()),
// descricao: v.literal("Perfil não encontrado"),
// editavel: v.optional(v.boolean()),
// nome: v.literal("erro_role_ausente"),
// nivel: v.literal(999),
// setor: v.optional(v.string()),
// erro: v.literal(true),
// })
// ),
// funcionario: v.optional(
// v.object({
// _id: v.id("funcionarios"),
// nome: v.string(),
// matricula: v.optional(v.string()),
// descricaoCargo: v.optional(v.string()),
// simboloTipo: v.union(
// v.literal("cargo_comissionado"),
// v.literal("funcao_gratificada")
// ),
// })
// ),
// avisos: v.optional(
// v.array(
// v.object({
// tipo: v.union(
// v.literal("erro"),
// v.literal("aviso"),
// v.literal("info")
// ),
// mensagem: v.string(),
// })
// )
// ),
// })
// ),
handler: async (ctx, args) => {
let usuarios = await ctx.db.query("usuarios").collect();
@@ -173,46 +206,136 @@ export const listar = query({
// Buscar roles e funcionários
const resultado = [];
const usuariosSemRole: Array<{ nome: string; matricula: string; roleId: Id<"roles"> }> = [];
for (const usuario of usuarios) {
const role = await ctx.db.get(usuario.roleId);
if (!role) continue;
try {
const role = await ctx.db.get(usuario.roleId);
// Se a role não existe, criar uma role de erro mas ainda incluir o usuário
if (!role) {
usuariosSemRole.push({
nome: usuario.nome,
matricula: usuario.matricula,
roleId: usuario.roleId,
});
// Filtrar por setor - se filtro está ativo e role não existe, pular
if (args.setor) {
continue;
}
// Filtrar por setor
if (args.setor && role.setor !== args.setor) {
continue;
}
// Incluir usuário com role de erro
let funcionario = undefined;
if (usuario.funcionarioId) {
try {
const func = await ctx.db.get(usuario.funcionarioId);
if (func) {
funcionario = {
_id: func._id,
nome: func.nome,
matricula: func.matricula,
descricaoCargo: func.descricaoCargo,
simboloTipo: func.simboloTipo,
};
}
} catch (error) {
console.error(`Erro ao buscar funcionário ${usuario.funcionarioId} para usuário ${usuario._id}:`, error);
}
}
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,
};
// Criar role de erro (sem _creationTime pois a role não existe)
resultado.push({
_id: usuario._id,
matricula: usuario.matricula,
nome: usuario.nome,
email: usuario.email,
ativo: usuario.ativo,
bloqueado: usuario.bloqueado,
motivoBloqueio: usuario.motivoBloqueio,
primeiroAcesso: usuario.primeiroAcesso,
ultimoAcesso: usuario.ultimoAcesso,
criadoEm: usuario.criadoEm,
role: {
_id: usuario.roleId,
descricao: "Perfil não encontrado" as const,
nome: "erro_role_ausente" as const,
nivel: 999 as const,
erro: true as const,
},
funcionario,
avisos: [
{
tipo: "erro" as const,
mensagem: `Perfil de acesso (ID: ${usuario.roleId}) não encontrado. Este usuário precisa ter seu perfil reatribuído.`,
},
],
});
continue;
}
}
resultado.push({
_id: usuario._id,
matricula: usuario.matricula,
nome: usuario.nome,
email: usuario.email,
ativo: usuario.ativo,
bloqueado: usuario.bloqueado,
motivoBloqueio: usuario.motivoBloqueio,
primeiroAcesso: usuario.primeiroAcesso,
ultimoAcesso: usuario.ultimoAcesso,
criadoEm: usuario.criadoEm,
role: {
// Filtrar por setor
if (args.setor && role.setor !== args.setor) {
continue;
}
// Buscar funcionário associado
let funcionario = undefined;
if (usuario.funcionarioId) {
try {
const func = await ctx.db.get(usuario.funcionarioId);
if (func) {
funcionario = {
_id: func._id,
nome: func.nome,
matricula: func.matricula,
descricaoCargo: func.descricaoCargo,
simboloTipo: func.simboloTipo,
};
}
} catch (error) {
console.error(`Erro ao buscar funcionário ${usuario.funcionarioId} para usuário ${usuario._id}:`, error);
}
}
// Construir objeto role - incluir _creationTime se existir (campo automático do Convex)
const roleObj = {
_id: role._id,
descricao: role.descricao,
nome: role.nome,
nivel: role.nivel,
setor: role.setor,
},
funcionario,
});
...(role.criadoPor !== undefined && { criadoPor: role.criadoPor }),
...(role.customizado !== undefined && { customizado: role.customizado }),
...(role.editavel !== undefined && { editavel: role.editavel }),
...(role.setor !== undefined && { setor: role.setor }),
};
resultado.push({
_id: usuario._id,
matricula: usuario.matricula,
nome: usuario.nome,
email: usuario.email,
ativo: usuario.ativo,
bloqueado: usuario.bloqueado,
motivoBloqueio: usuario.motivoBloqueio,
primeiroAcesso: usuario.primeiroAcesso,
ultimoAcesso: usuario.ultimoAcesso,
criadoEm: usuario.criadoEm,
role: roleObj,
funcionario,
});
} catch (error) {
console.error(`Erro ao processar usuário ${usuario._id}:`, error);
// Continua processando outros usuários mesmo se houver erro em um
}
}
// Log de usuários sem role para depuração
if (usuariosSemRole.length > 0) {
console.warn(
`⚠️ Encontrados ${usuariosSemRole.length} usuário(s) com perfil ausente:`,
usuariosSemRole.map((u) => `${u.nome} (${u.matricula}) - RoleID: ${u.roleId}`)
);
}
return resultado;