feat: implement user consent verification and redirection for LGPD compliance in dashboard layout and consent term page
This commit is contained in:
@@ -1,10 +1,49 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
|
import { useQuery } from 'convex-svelte';
|
||||||
|
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||||
import ActionGuard from '$lib/components/ActionGuard.svelte';
|
import ActionGuard from '$lib/components/ActionGuard.svelte';
|
||||||
import { Toaster } from 'svelte-sonner';
|
import { Toaster } from 'svelte-sonner';
|
||||||
import PushNotificationManager from '$lib/components/PushNotificationManager.svelte';
|
import PushNotificationManager from '$lib/components/PushNotificationManager.svelte';
|
||||||
const { children } = $props();
|
const { children } = $props();
|
||||||
|
|
||||||
|
// Usuário atual e consentimento LGPD
|
||||||
|
const currentUser = useQuery(api.auth.getCurrentUser, {});
|
||||||
|
const consentimentoLGPD = useQuery(api.lgpd.verificarConsentimento, { tipo: 'termo_uso' });
|
||||||
|
|
||||||
|
// Redirecionar para o termo de consentimento se obrigatório e não aceito
|
||||||
|
$effect(() => {
|
||||||
|
const p = page.url.pathname;
|
||||||
|
|
||||||
|
// Rotas públicas/que não exigem termo
|
||||||
|
if (
|
||||||
|
p === '/' ||
|
||||||
|
p === '/abrir-chamado' ||
|
||||||
|
p === '/termo-consentimento' ||
|
||||||
|
p.startsWith('/privacidade') ||
|
||||||
|
p.startsWith('/api/')
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Precisa estar autenticado para exigir LGPD
|
||||||
|
if (!currentUser?.data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query ainda carregando ou sem dados
|
||||||
|
if (!consentimentoLGPD?.data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = consentimentoLGPD.data;
|
||||||
|
|
||||||
|
if (data.termoObrigatorio && !data.aceito) {
|
||||||
|
const redirect = encodeURIComponent(p);
|
||||||
|
window.location.href = `/termo-consentimento?redirect=${redirect}`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Resolver recurso/ação a partir da rota
|
// Resolver recurso/ação a partir da rota
|
||||||
const routeAction = $derived.by(() => {
|
const routeAction = $derived.by(() => {
|
||||||
const p = page.url.pathname;
|
const p = page.url.pathname;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { resolve } from '$app/paths';
|
import { resolve } from '$app/paths';
|
||||||
|
import { page } from '$app/state';
|
||||||
import { Shield, CheckCircle, AlertCircle, FileText } from 'lucide-svelte';
|
import { Shield, CheckCircle, AlertCircle, FileText } from 'lucide-svelte';
|
||||||
import { useQuery, useMutation } from 'convex-svelte';
|
import { useQuery, useMutation } from 'convex-svelte';
|
||||||
import { api } from '@sgse-app/backend/convex/_generated/api';
|
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||||
@@ -21,6 +22,18 @@
|
|||||||
const termoObrigatorio = $derived(consentimentoQuery?.data?.termoObrigatorio ?? false);
|
const termoObrigatorio = $derived(consentimentoQuery?.data?.termoObrigatorio ?? false);
|
||||||
const versaoTermoAtual = $derived(consentimentoQuery?.data?.versaoTermoAtual ?? '1.0');
|
const versaoTermoAtual = $derived(consentimentoQuery?.data?.versaoTermoAtual ?? '1.0');
|
||||||
|
|
||||||
|
// Rota de retorno após aceite
|
||||||
|
const redirectTo = $derived(page.url.searchParams.get('redirect') || '/');
|
||||||
|
|
||||||
|
function navegarDeVolta() {
|
||||||
|
// Se vier algo como URL absoluta, mantemos; senão usamos resolve
|
||||||
|
if (redirectTo.startsWith('/')) {
|
||||||
|
window.location.href = redirectTo;
|
||||||
|
} else {
|
||||||
|
window.location.href = resolve(redirectTo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function aceitarTermo() {
|
async function aceitarTermo() {
|
||||||
if (termoObrigatorio && !aceito) {
|
if (termoObrigatorio && !aceito) {
|
||||||
erro = 'Você precisa aceitar o termo para continuar';
|
erro = 'Você precisa aceitar o termo para continuar';
|
||||||
@@ -29,7 +42,7 @@
|
|||||||
|
|
||||||
if (!aceito) {
|
if (!aceito) {
|
||||||
// Se não é obrigatório e não aceitou, apenas redireciona
|
// Se não é obrigatório e não aceitou, apenas redireciona
|
||||||
window.location.href = resolve('/');
|
navegarDeVolta();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,6 +56,7 @@
|
|||||||
versao: versaoTermoAtual
|
versao: versaoTermoAtual
|
||||||
});
|
});
|
||||||
sucesso = true;
|
sucesso = true;
|
||||||
|
navegarDeVolta();
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
erro = e instanceof Error ? e.message : 'Erro ao registrar consentimento';
|
erro = e instanceof Error ? e.message : 'Erro ao registrar consentimento';
|
||||||
} finally {
|
} finally {
|
||||||
@@ -102,9 +116,9 @@
|
|||||||
<p class="text-base-content/80 mb-6">
|
<p class="text-base-content/80 mb-6">
|
||||||
Seu consentimento foi registrado. Você pode acessar o sistema normalmente.
|
Seu consentimento foi registrado. Você pode acessar o sistema normalmente.
|
||||||
</p>
|
</p>
|
||||||
<a href={resolve('/')} class="btn btn-primary btn-lg">
|
<button type="button" class="btn btn-primary btn-lg" onclick={navegarDeVolta}>
|
||||||
Continuar para o Sistema
|
Continuar para o Sistema
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
|
|||||||
Reference in New Issue
Block a user