refactor: improve data handling and UI feedback in LGPD-related components; enhance error handling and consent term display

This commit is contained in:
2025-12-02 14:03:52 -03:00
parent e81054874f
commit ffa4dc5fb2
5 changed files with 254 additions and 64 deletions

View File

@@ -311,26 +311,37 @@ export const listarMinhasSolicitacoes = query({
return [];
}
let solicitacoes = await ctx.db
.query('solicitacoesLGPD')
.withIndex('by_usuario', (q) => q.eq('usuarioId', usuario._id))
.order('desc')
.collect();
try {
let solicitacoes = await ctx.db
.query('solicitacoesLGPD')
.withIndex('by_usuario', (q) => q.eq('usuarioId', usuario._id))
.collect();
if (args.status) {
solicitacoes = solicitacoes.filter((s) => s.status === args.status);
// Filtrar por status se especificado
if (args.status) {
solicitacoes = solicitacoes.filter((s) => s.status === args.status);
}
// Ordenar por data de criação (mais recentes primeiro)
solicitacoes.sort((a, b) => b.criadoEm - a.criadoEm);
const resultado = solicitacoes.map((s) => ({
_id: s._id,
tipo: s.tipo,
status: s.status,
criadoEm: s.criadoEm,
prazoResposta: s.prazoResposta,
respondidoEm: s.respondidoEm ?? null,
resposta: s.resposta ?? null,
arquivoResposta: s.arquivoResposta ? s.arquivoResposta.toString() : null
}));
console.log(`[listarMinhasSolicitacoes] Usuário: ${usuario._id}, Solicitações encontradas: ${resultado.length}`);
return resultado;
} catch (error) {
console.error('[listarMinhasSolicitacoes] Erro ao listar minhas solicitações:', error);
return [];
}
return solicitacoes.map((s) => ({
_id: s._id,
tipo: s.tipo,
status: s.status,
criadoEm: s.criadoEm,
prazoResposta: s.prazoResposta,
respondidoEm: s.respondidoEm ?? null,
resposta: s.resposta ?? null,
arquivoResposta: s.arquivoResposta ? s.arquivoResposta.toString() : null
}));
}
});
@@ -370,7 +381,16 @@ export const listarSolicitacoes = query({
criadoEm: v.number(),
prazoResposta: v.number(),
respondidoEm: v.union(v.number(), v.null()),
respondidoPorNome: v.union(v.string(), v.null())
respondidoPorNome: v.union(v.string(), v.null()),
consentimentoTermo: v.union(
v.object({
aceito: v.boolean(),
versao: v.string(),
aceitoEm: v.number(),
revogadoEm: v.union(v.number(), v.null())
}),
v.null()
)
})
),
handler: async (ctx, args) => {
@@ -382,52 +402,137 @@ export const listarSolicitacoes = query({
// Verificar se é TI (simplificado - pode melhorar com verificação de role)
// Por enquanto, qualquer usuário autenticado pode ver (será melhorado)
let solicitacoes = await ctx.db.query('solicitacoesLGPD').order('desc').collect();
// Buscar TODAS as solicitações sem filtros iniciais
let solicitacoes = await ctx.db.query('solicitacoesLGPD').collect();
// Filtrar por status
if (args.status) {
solicitacoes = solicitacoes.filter((s) => s.status === args.status);
}
// Filtrar por tipo
if (args.tipo) {
solicitacoes = solicitacoes.filter((s) => s.tipo === args.tipo);
}
// Ordenar por data de criação (mais recentes primeiro)
solicitacoes.sort((a, b) => b.criadoEm - a.criadoEm);
// Aplicar limite se especificado
if (args.limite) {
solicitacoes = solicitacoes.slice(0, args.limite);
}
// Tipo do resultado enriquecido
type SolicitacaoEnriquecida = {
_id: Id<'solicitacoesLGPD'>;
tipo: string;
status: string;
usuarioNome: string;
usuarioEmail: string;
usuarioMatricula: string | null;
criadoEm: number;
prazoResposta: number;
respondidoEm: number | null;
respondidoPorNome: string | null;
consentimentoTermo: {
aceito: boolean;
versao: string;
aceitoEm: number;
revogadoEm: number | null;
} | null;
};
// Enriquecer com dados do usuário
const resultado = await Promise.all(
solicitacoes.map(async (s) => {
const usuarioSolicitante = await ctx.db.get(s.usuarioId);
let matricula: string | null = null;
// Usar Promise.allSettled para garantir que todas as solicitações sejam processadas,
// mesmo se houver erro ao buscar dados de algum usuário
const resultados = await Promise.allSettled(
solicitacoes.map(async (s): Promise<SolicitacaoEnriquecida> => {
try {
const usuarioSolicitante = await ctx.db.get(s.usuarioId);
let matricula: string | null = null;
if (usuarioSolicitante?.funcionarioId) {
const funcionario = await ctx.db.get(usuarioSolicitante.funcionarioId);
matricula = funcionario?.matricula ?? null;
if (usuarioSolicitante?.funcionarioId) {
const funcionario = await ctx.db.get(usuarioSolicitante.funcionarioId);
matricula = funcionario?.matricula ?? null;
}
let respondidoPorNome: string | null = null;
if (s.respondidoPor) {
const respondente = await ctx.db.get(s.respondidoPor);
respondidoPorNome = respondente?.nome ?? null;
}
// Buscar consentimento do termo de uso
let consentimentoTermo: {
aceito: boolean;
versao: string;
aceitoEm: number;
revogadoEm: number | null;
} | null = null;
if (usuarioSolicitante) {
try {
const consentimento = await ctx.db
.query('consentimentos')
.withIndex('by_usuario_tipo', (q) =>
q.eq('usuarioId', usuarioSolicitante._id).eq('tipo', 'termo_uso')
)
.order('desc')
.first();
if (consentimento && consentimento.aceito && !consentimento.revogadoEm) {
consentimentoTermo = {
aceito: consentimento.aceito,
versao: consentimento.versao,
aceitoEm: consentimento.aceitoEm,
revogadoEm: consentimento.revogadoEm ?? null
};
}
} catch (error) {
// Se houver erro ao buscar consentimento, continua sem ele
console.error('Erro ao buscar consentimento:', error);
}
}
return {
_id: s._id,
tipo: s.tipo,
status: s.status,
usuarioNome: usuarioSolicitante?.nome ?? 'Usuário Desconhecido',
usuarioEmail: usuarioSolicitante?.email ?? '',
usuarioMatricula: matricula,
criadoEm: s.criadoEm,
prazoResposta: s.prazoResposta,
respondidoEm: s.respondidoEm ?? null,
respondidoPorNome,
consentimentoTermo
};
} catch (error) {
// Se houver erro ao processar uma solicitação, retorna com dados mínimos
console.error('Erro ao processar solicitação:', s._id, error);
return {
_id: s._id,
tipo: s.tipo,
status: s.status,
usuarioNome: 'Erro ao carregar',
usuarioEmail: '',
usuarioMatricula: null,
criadoEm: s.criadoEm,
prazoResposta: s.prazoResposta,
respondidoEm: s.respondidoEm ?? null,
respondidoPorNome: null,
consentimentoTermo: null
};
}
let respondidoPorNome: string | null = null;
if (s.respondidoPor) {
const respondente = await ctx.db.get(s.respondidoPor);
respondidoPorNome = respondente?.nome ?? null;
}
return {
_id: s._id,
tipo: s.tipo,
status: s.status,
usuarioNome: usuarioSolicitante?.nome ?? 'Usuário Desconhecido',
usuarioEmail: usuarioSolicitante?.email ?? '',
usuarioMatricula: matricula,
criadoEm: s.criadoEm,
prazoResposta: s.prazoResposta,
respondidoEm: s.respondidoEm ?? null,
respondidoPorNome
};
})
);
// Filtrar apenas resultados bem-sucedidos e converter para o tipo correto
const resultado = resultados
.filter((r): r is PromiseFulfilledResult<SolicitacaoEnriquecida> => r.status === 'fulfilled')
.map((r) => r.value);
return resultado;
}
});