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

@@ -30,7 +30,17 @@ let observacoes = $state('');
let carregando = $state(false);
const client = useConvexClient();
const minhasSolicitacoes = useQuery(api.lgpd.listarMinhasSolicitacoes, {});
const minhasSolicitacoesQuery = useQuery(api.lgpd.listarMinhasSolicitacoes, {});
// Garantir que sempre seja um array ou undefined
const minhasSolicitacoes = $derived(
minhasSolicitacoesQuery === undefined || minhasSolicitacoesQuery === null
? undefined
: Array.isArray(minhasSolicitacoesQuery)
? minhasSolicitacoesQuery
: []
);
const exportarDados = useQuery(api.lgpd.exportarDadosUsuario, {});
const tiposSolicitacao: Array<{ valor: TipoSolicitacao; label: string; descricao: string }> = [
@@ -241,16 +251,26 @@ let carregando = $state(false);
<!-- Minhas Solicitações -->
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title text-2xl mb-4">Minhas Solicitações</h2>
<div class="flex items-center justify-between mb-4">
<h2 class="card-title text-2xl">Minhas Solicitações</h2>
{#if minhasSolicitacoes && Array.isArray(minhasSolicitacoes)}
<div class="badge badge-outline">
{minhasSolicitacoes.length} solicitação{minhasSolicitacoes.length !== 1 ? 'ões' : ''}
</div>
{/if}
</div>
{#if minhasSolicitacoes === undefined}
{#if minhasSolicitacoes === undefined || minhasSolicitacoes === null}
<div class="flex justify-center items-center py-10">
<span class="loading loading-spinner loading-lg text-primary"></span>
</div>
{:else if minhasSolicitacoes.length === 0}
{:else if !Array.isArray(minhasSolicitacoes) || minhasSolicitacoes.length === 0}
<div class="text-center py-10">
<FileText class="h-16 w-16 text-base-content/30 mx-auto mb-4" />
<p class="text-base-content/60">Nenhuma solicitação encontrada</p>
<p class="text-xs text-base-content/40 mt-2">
Suas solicitações aparecerão aqui após serem criadas
</p>
</div>
{:else}
<div class="space-y-4">

View File

@@ -32,10 +32,14 @@
let termoBusca = $state('');
const client = useConvexClient();
const solicitacoes = useQuery(api.lgpd.listarSolicitacoes, {
// Query reativa que atualiza quando os filtros mudam
const solicitacoesQuery = $derived({
status: statusFiltro || undefined,
tipo: tipoFiltro || undefined
});
const solicitacoes = useQuery(api.lgpd.listarSolicitacoes, solicitacoesQuery);
let solicitacaoSelecionada = $state<string | null>(null);
let resposta = $state('');
@@ -85,15 +89,21 @@
}
function filtrarSolicitacoes() {
if (!solicitacoes) return [];
if (!termoBusca) return solicitacoes;
// Verificar se solicitacoes existe e é um array
if (!solicitacoes || !Array.isArray(solicitacoes)) return [];
// Se não há termo de busca, retorna todas as solicitações
if (!termoBusca || termoBusca.trim() === '') return solicitacoes;
const busca = termoBusca.toLowerCase();
// Filtrar por termo de busca
const busca = termoBusca.toLowerCase().trim();
return solicitacoes.filter(
(s) =>
s.usuarioNome.toLowerCase().includes(busca) ||
s.usuarioEmail.toLowerCase().includes(busca) ||
(s.usuarioMatricula?.toLowerCase().includes(busca) ?? false)
(s.usuarioNome?.toLowerCase().includes(busca) ?? false) ||
(s.usuarioEmail?.toLowerCase().includes(busca) ?? false) ||
(s.usuarioMatricula?.toLowerCase().includes(busca) ?? false) ||
(getTipoLabel(s.tipo).toLowerCase().includes(busca)) ||
(getStatusBadge(s.status).label.toLowerCase().includes(busca))
);
}
@@ -193,16 +203,52 @@
<!-- Lista de Solicitações -->
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title text-2xl mb-4">Solicitações</h2>
<div class="flex items-center justify-between mb-4">
<h2 class="card-title text-2xl">Solicitações</h2>
{#if solicitacoes && Array.isArray(solicitacoes)}
<div class="badge badge-outline">
Total: {solicitacoes.length} | Exibindo: {solicitacoesFiltradas.length}
</div>
{/if}
</div>
{#if solicitacoes === undefined}
{#if solicitacoes === undefined || solicitacoes === null}
<div class="flex justify-center items-center py-20">
<span class="loading loading-spinner loading-lg text-primary"></span>
</div>
{:else if solicitacoesFiltradas.length === 0}
{:else if !Array.isArray(solicitacoes) || solicitacoes.length === 0}
<div class="text-center py-10">
<FileText class="h-16 w-16 text-base-content/30 mx-auto mb-4" />
<p class="text-base-content/60">Nenhuma solicitação encontrada</p>
<p class="text-base-content/60">
{#if statusFiltro || tipoFiltro}
Nenhuma solicitação encontrada com os filtros aplicados
{:else}
Nenhuma solicitação encontrada
{/if}
</p>
{#if statusFiltro || tipoFiltro}
<button
onclick={() => {
statusFiltro = null;
tipoFiltro = null;
termoBusca = '';
}}
class="btn btn-sm btn-outline mt-4"
>
Limpar Filtros
</button>
{/if}
</div>
{:else if solicitacoesFiltradas.length === 0 && termoBusca}
<div class="text-center py-10">
<Search class="h-16 w-16 text-base-content/30 mx-auto mb-4" />
<p class="text-base-content/60">Nenhuma solicitação encontrada com o termo "{termoBusca}"</p>
<button
onclick={() => (termoBusca = '')}
class="btn btn-sm btn-outline mt-4"
>
Limpar Busca
</button>
</div>
{:else}
<div class="space-y-4">
@@ -230,6 +276,23 @@
<div>
<span class="font-semibold">E-mail:</span> {solicitacao.usuarioEmail}
</div>
{#if solicitacao.consentimentoTermo}
<div class="flex items-center gap-2">
<span class="font-semibold">Termo de Consentimento:</span>
<span class="badge badge-success badge-sm">Aceito</span>
<span class="text-xs text-base-content/60">
(v.{solicitacao.consentimentoTermo.versao} em{' '}
{format(new Date(solicitacao.consentimentoTermo.aceitoEm), 'dd/MM/yyyy', {
locale: ptBR
})})
</span>
</div>
{:else}
<div class="flex items-center gap-2">
<span class="font-semibold">Termo de Consentimento:</span>
<span class="badge badge-warning badge-sm">Não aceito</span>
</div>
{/if}
<div>
<span class="font-semibold">Criada em:</span>{' '}
{format(new Date(solicitacao.criadoEm), "dd/MM/yyyy 'às' HH:mm", {