- {#if solicitacoes === undefined}
+ {#if solicitacoes === undefined || solicitacoes === null}
- {:else if solicitacoesFiltradas.length === 0}
+ {:else if !Array.isArray(solicitacoes) || solicitacoes.length === 0}
-
Nenhuma solicitação encontrada
+
+ {#if statusFiltro || tipoFiltro}
+ Nenhuma solicitação encontrada com os filtros aplicados
+ {:else}
+ Nenhuma solicitação encontrada
+ {/if}
+
+ {#if statusFiltro || tipoFiltro}
+
+ {/if}
+
+
+
Nenhuma solicitação encontrada com o termo "{termoBusca}"
+
@@ -230,6 +276,23 @@
E-mail: {solicitacao.usuarioEmail}
+ {#if solicitacao.consentimentoTermo}
+
+ Termo de Consentimento:
+ Aceito
+
+ (v.{solicitacao.consentimentoTermo.versao} em{' '}
+ {format(new Date(solicitacao.consentimentoTermo.aceitoEm), 'dd/MM/yyyy', {
+ locale: ptBR
+ })})
+
+
+ {:else}
+
+ Termo de Consentimento:
+ Não aceito
+
+ {/if}
Criada em:{' '}
{format(new Date(solicitacao.criadoEm), "dd/MM/yyyy 'às' HH:mm", {
diff --git a/packages/backend/convex/_generated/api.d.ts b/packages/backend/convex/_generated/api.d.ts
index 799c897..beb3c67 100644
--- a/packages/backend/convex/_generated/api.d.ts
+++ b/packages/backend/convex/_generated/api.d.ts
@@ -69,6 +69,7 @@ import type * as tables_enderecos from "../tables/enderecos.js";
import type * as tables_ferias from "../tables/ferias.js";
import type * as tables_flows from "../tables/flows.js";
import type * as tables_funcionarios from "../tables/funcionarios.js";
+import type * as tables_lgpdTables from "../tables/lgpdTables.js";
import type * as tables_licencas from "../tables/licencas.js";
import type * as tables_pedidos from "../tables/pedidos.js";
import type * as tables_ponto from "../tables/ponto.js";
@@ -155,6 +156,7 @@ declare const fullApi: ApiFromModules<{
"tables/ferias": typeof tables_ferias;
"tables/flows": typeof tables_flows;
"tables/funcionarios": typeof tables_funcionarios;
+ "tables/lgpdTables": typeof tables_lgpdTables;
"tables/licencas": typeof tables_licencas;
"tables/pedidos": typeof tables_pedidos;
"tables/ponto": typeof tables_ponto;
diff --git a/packages/backend/convex/lgpd.ts b/packages/backend/convex/lgpd.ts
index 1740bff..26f2e09 100644
--- a/packages/backend/convex/lgpd.ts
+++ b/packages/backend/convex/lgpd.ts
@@ -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 => {
+ 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 => r.status === 'fulfilled')
+ .map((r) => r.value);
+
return resultado;
}
});