refactor: remove ActionGuard and MenuProtection components, simplifying permission checks in various dashboard routes and enhancing footer with privacy policy link

This commit is contained in:
2025-12-13 10:50:57 -03:00
parent 13ec7cc8e3
commit c068715fc1
64 changed files with 504 additions and 585 deletions

View File

@@ -3,16 +3,16 @@ import { api } from '@sgse-app/backend/convex/_generated/api';
import { error, redirect } from '@sveltejs/kit';
import type { FunctionReference } from 'convex/server';
export const load = async ({ locals }) => {
export const load = async ({ locals, url }) => {
if (!locals.token) {
throw redirect(302, '/login');
throw redirect(302, '/login?redirect=' + url.pathname);
}
try {
const client = createConvexHttpClient({ token: locals.token });
const currentUser = await client.query(api.auth.getCurrentUser as FunctionReference<'query'>);
if (!currentUser) {
throw redirect(302, '/login');
throw redirect(302, '/login?redirect=' + url.pathname);
}
return { currentUser };
} catch {

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -2,7 +2,6 @@
import { api } from '@sgse-app/backend/convex/_generated/api';
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
import { useConvexClient, useQuery } from 'convex-svelte';
import ActionGuard from '$lib/components/ActionGuard.svelte';
const client = useConvexClient();
@@ -232,25 +231,23 @@
</p>
</div>
<div class="flex items-center gap-4">
<ActionGuard recurso="setores" acao="criar">
<button class="btn btn-primary shadow-lg" onclick={openCreateModal}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
/>
</svg>
Novo Setor
</button>
</ActionGuard>
<button class="btn btn-primary shadow-lg" onclick={openCreateModal}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
/>
</svg>
Novo Setor
</button>
</div>
</div>
</section>
@@ -307,52 +304,48 @@
<td class="text-base-content/60 text-sm">{formatDate(setor.createdAt)}</td>
<td class="text-right">
<div class="flex justify-end gap-2">
<ActionGuard recurso="setores" acao="editar">
<button
class="btn btn-ghost btn-sm"
onclick={() => openEditModal(setor)}
aria-label="Editar setor {setor.nome}"
<button
class="btn btn-ghost btn-sm"
onclick={() => openEditModal(setor)}
aria-label="Editar setor {setor.nome}"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
/>
</svg>
</button>
</ActionGuard>
<ActionGuard recurso="setores" acao="excluir">
<button
class="btn btn-ghost btn-sm text-error"
onclick={() => openDeleteModal(setor)}
aria-label="Excluir setor {setor.nome}"
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
/>
</svg>
</button>
<button
class="btn btn-ghost btn-sm text-error"
onclick={() => openDeleteModal(setor)}
aria-label="Excluir setor {setor.nome}"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</button>
</ActionGuard>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
</button>
</div>
</td>
</tr>

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -1,368 +0,0 @@
<script lang="ts">
import { api } from '@sgse-app/backend/convex/_generated/api';
import { useConvexClient } from 'convex-svelte';
import { resolve } from '$app/paths';
const convex = useConvexClient();
let matricula = $state('');
let email = $state('');
let carregando = $state(false);
let notice = $state<{
type: 'success' | 'error' | 'info';
message: string;
} | null>(null);
let solicitacaoEnviada = $state(false);
async function handleSubmit(e: Event) {
e.preventDefault();
notice = null;
if (!matricula || !email) {
notice = {
type: 'error',
message: 'Por favor, preencha todos os campos'
};
return;
}
carregando = true;
try {
// Verificar se o usuário existe
const usuarios = await convex.query(api.usuarios.listar, {
matricula: matricula
});
const usuario = usuarios.find((u) => u.matricula === matricula && u.email === email);
if (!usuario) {
notice = {
type: 'error',
message: 'Matrícula ou e-mail não encontrados. Verifique os dados e tente novamente.'
};
carregando = false;
return;
}
// Simular envio de solicitação
solicitacaoEnviada = true;
notice = {
type: 'success',
message: 'Solicitação enviada com sucesso! A equipe de TI entrará em contato em breve.'
};
// Limpar campos
matricula = '';
email = '';
} catch (error: any) {
notice = {
type: 'error',
message: error.message || 'Erro ao processar solicitação'
};
} finally {
carregando = false;
}
}
</script>
<main class="container mx-auto max-w-2xl px-4 py-8">
<!-- Header -->
<div class="mb-8">
<div class="mb-2 flex items-center gap-3">
<svg
xmlns="http://www.w3.org/2000/svg"
class="text-primary h-10 w-10"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<h1 class="text-primary text-4xl font-bold">Esqueci Minha Senha</h1>
</div>
<p class="text-base-content/70 text-lg">Solicite a recuperação da sua senha de acesso</p>
</div>
<!-- Breadcrumbs -->
<div class="breadcrumbs mb-6 text-sm">
<ul>
<li><a href={resolve('/')}>Dashboard</a></li>
<li>Esqueci Minha Senha</li>
</ul>
</div>
<!-- Alertas -->
{#if notice}
<div
class="alert {notice.type === 'success'
? 'alert-success'
: notice.type === 'error'
? 'alert-error'
: 'alert-info'} mb-6 shadow-lg"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 shrink-0 stroke-current"
fill="none"
viewBox="0 0 24 24"
>
{#if notice.type === 'success'}
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
{:else if notice.type === 'error'}
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
{:else}
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
{/if}
</svg>
<span>{notice.message}</span>
</div>
{/if}
{#if !solicitacaoEnviada}
<!-- Formulário -->
<div class="card bg-base-100 border-base-300 border shadow-xl">
<div class="card-body">
<div class="alert alert-info mb-6">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 shrink-0 stroke-current"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<div>
<h3 class="font-bold">Como funciona?</h3>
<p class="text-sm">
Informe sua matrícula e e-mail cadastrados. A equipe de TI receberá sua solicitação e
entrará em contato para resetar sua senha.
</p>
</div>
</div>
<form onsubmit={handleSubmit} class="space-y-6">
<!-- Matrícula -->
<div class="form-control">
<label class="label" for="matricula">
<span class="label-text font-semibold">Matrícula</span>
<span class="label-text-alt text-error">*</span>
</label>
<input
id="matricula"
type="text"
placeholder="Digite sua matrícula"
class="input input-bordered input-primary w-full"
bind:value={matricula}
required
disabled={carregando}
/>
</div>
<!-- E-mail -->
<div class="form-control">
<label class="label" for="email">
<span class="label-text font-semibold">E-mail</span>
<span class="label-text-alt text-error">*</span>
</label>
<input
id="email"
type="email"
placeholder="Digite seu e-mail cadastrado"
class="input input-bordered input-primary w-full"
bind:value={email}
required
disabled={carregando}
/>
<label class="label">
<span class="label-text-alt text-base-content/60">
Use o e-mail cadastrado no sistema
</span>
</label>
</div>
<!-- Botões -->
<div class="mt-8 flex justify-end gap-4">
<a href={resolve('/')} class="btn" class:btn-disabled={carregando}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 19l-7-7m0 0l7-7m-7 7h18"
/>
</svg>
Voltar
</a>
<button type="submit" class="btn btn-primary" disabled={carregando}>
{#if carregando}
<span class="loading loading-spinner loading-sm"></span>
Enviando...
{:else}
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
/>
</svg>
Enviar Solicitação
{/if}
</button>
</div>
</form>
</div>
</div>
{:else}
<!-- Mensagem de Sucesso -->
<div class="card bg-success/10 border-success/30 border shadow-xl">
<div class="card-body text-center">
<div class="mb-4 flex justify-center">
<svg
xmlns="http://www.w3.org/2000/svg"
class="text-success h-24 w-24"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
</div>
<h2 class="text-success mb-4 text-2xl font-bold">Solicitação Enviada!</h2>
<p class="text-base-content/70 mb-6">
Sua solicitação de recuperação de senha foi enviada para a equipe de TI. Você receberá um
contato em breve com as instruções para resetar sua senha.
</p>
<div class="flex justify-center gap-4">
<a href={resolve('/')} class="btn btn-primary">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
/>
</svg>
Voltar ao Dashboard
</a>
<button type="button" class="btn" onclick={() => (solicitacaoEnviada = false)}>
Enviar Nova Solicitação
</button>
</div>
</div>
</div>
{/if}
<!-- Card de Contato -->
<div class="card bg-base-200 mt-6 shadow-lg">
<div class="card-body">
<h3 class="card-title text-lg">
<svg
xmlns="http://www.w3.org/2000/svg"
class="text-info h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
Precisa de Ajuda?
</h3>
<p class="text-base-content/70 text-sm">
Se você não conseguir recuperar sua senha ou tiver problemas com o sistema, entre em contato
diretamente com a equipe de TI:
</p>
<div class="mt-4 space-y-2">
<div class="flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
class="text-primary h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
/>
</svg>
<span class="text-sm">ti@sgse.pe.gov.br</span>
</div>
<div class="flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
class="text-primary h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"
/>
</svg>
<span class="text-sm">(81) 3183-8000</span>
</div>
</div>
</div>
</div>
</main>

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -3,7 +3,6 @@
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
import { useConvexClient, useQuery } from 'convex-svelte';
import { goto } from '$app/navigation';
import ActionGuard from '$lib/components/ActionGuard.svelte';
const client = useConvexClient();
@@ -164,26 +163,24 @@
<option value="archived">Arquivado</option>
</select>
<ActionGuard recurso="fluxos_templates" acao="criar">
<button class="btn btn-secondary shadow-lg" onclick={openCreateModal}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
/>
</svg>
Novo Template
</button>
</ActionGuard>
<button class="btn btn-secondary shadow-lg" onclick={openCreateModal}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
/>
</svg>
Novo Template
</button>
</div>
</div>
</section>

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -4,7 +4,6 @@
import { useConvexClient, useQuery } from 'convex-svelte';
import { resolve } from '$app/paths';
import { page } from '$app/stores';
import ActionGuard from '$lib/components/ActionGuard.svelte';
const client = useConvexClient();
let instanceId = $derived($page.params.id as Id<'flowInstances'>);
@@ -416,26 +415,24 @@
</div>
{#if instance.status === 'active'}
<ActionGuard recurso="fluxos_instancias" acao="cancelar">
<button class="btn btn-error btn-outline" onclick={() => (showCancelModal = true)}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
Cancelar Fluxo
</button>
</ActionGuard>
<button class="btn btn-error btn-outline" onclick={() => (showCancelModal = true)}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
Cancelar Fluxo
</button>
{/if}
</div>
</div>
@@ -616,67 +613,59 @@
{#if instance.status === 'active'}
<div class="flex flex-wrap gap-2">
{#if step.status === 'pending'}
<ActionGuard recurso="fluxos_instancias" acao="avancar_passo">
<button
class="btn btn-info btn-sm"
onclick={() => handleStartStep(step._id)}
disabled={isProcessing}
>
Iniciar
</button>
</ActionGuard>
<button
class="btn btn-info btn-sm"
onclick={() => handleStartStep(step._id)}
disabled={isProcessing}
>
Iniciar
</button>
{:else if step.status === 'in_progress'}
<ActionGuard recurso="fluxos_instancias" acao="avancar_passo">
<button
class="btn btn-success btn-sm"
onclick={() => handleCompleteStep(step._id)}
disabled={isProcessing}
>
Concluir
</button>
<button
class="btn btn-warning btn-sm"
onclick={() => handleBlockStep(step._id)}
disabled={isProcessing}
>
Bloquear
</button>
</ActionGuard>
<button
class="btn btn-success btn-sm"
onclick={() => handleCompleteStep(step._id)}
disabled={isProcessing}
>
Concluir
</button>
<button
class="btn btn-warning btn-sm"
onclick={() => handleBlockStep(step._id)}
disabled={isProcessing}
>
Bloquear
</button>
{:else if step.status === 'blocked'}
<ActionGuard recurso="fluxos_instancias" acao="avancar_passo">
<button
class="btn btn-info btn-sm"
onclick={() => handleStartStep(step._id)}
disabled={isProcessing}
>
Desbloquear
</button>
</ActionGuard>
<button
class="btn btn-info btn-sm"
onclick={() => handleStartStep(step._id)}
disabled={isProcessing}
>
Desbloquear
</button>
{/if}
<ActionGuard recurso="fluxos_instancias" acao="atribuir_usuario">
<button
class="btn btn-ghost btn-sm"
onclick={() => openReassignModal(step)}
aria-label="Reatribuir responsável"
<button
class="btn btn-ghost btn-sm"
onclick={() => openReassignModal(step)}
aria-label="Reatribuir responsável"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
/>
</svg>
</button>
</ActionGuard>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
/>
</svg>
</button>
<button
class="btn btn-ghost btn-sm"
@@ -700,29 +689,27 @@
</svg>
</button>
<ActionGuard recurso="fluxos_documentos" acao="upload">
<button
class="btn btn-ghost btn-sm"
onclick={() => openUploadModal(step)}
aria-label="Upload de documento"
<button
class="btn btn-ghost btn-sm"
onclick={() => openUploadModal(step)}
aria-label="Upload de documento"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
/>
</svg>
</button>
</ActionGuard>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
/>
</svg>
</button>
</div>
{/if}
</div>
@@ -759,15 +746,13 @@
/>
</svg>
{doc.name}
<ActionGuard recurso="fluxos_documentos" acao="excluir">
<button
class="btn btn-ghost btn-xs text-error"
onclick={() => handleDeleteDocument(doc._id)}
aria-label="Excluir documento {doc.name}"
>
×
</button>
</ActionGuard>
<button
class="btn btn-ghost btn-xs text-error"
onclick={() => handleDeleteDocument(doc._id)}
aria-label="Excluir documento {doc.name}"
>
×
</button>
</div>
{/each}
</div>

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -3,7 +3,6 @@
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
import { useConvexClient, useQuery } from 'convex-svelte';
import { goto } from '$app/navigation';
import ActionGuard from '$lib/components/ActionGuard.svelte';
const client = useConvexClient();
@@ -148,26 +147,24 @@
<option value="cancelled">Cancelado</option>
</select>
<ActionGuard recurso="fluxos_instancias" acao="criar">
<button class="btn btn-info shadow-lg" onclick={openCreateModal}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
/>
</svg>
Nova Instância
</button>
</ActionGuard>
<button class="btn btn-info shadow-lg" onclick={openCreateModal}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
/>
</svg>
Nova Instância
</button>
</div>
</div>
</section>

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -3,7 +3,6 @@
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
import { useConvexClient, useQuery } from 'convex-svelte';
import { goto } from '$app/navigation';
import ActionGuard from '$lib/components/ActionGuard.svelte';
const client = useConvexClient();
@@ -148,26 +147,24 @@
<option value="cancelled">Cancelado</option>
</select>
<ActionGuard recurso="fluxos_instancias" acao="criar">
<button class="btn btn-info shadow-lg" onclick={openCreateModal}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
/>
</svg>
Novo Fluxo
</button>
</ActionGuard>
<button class="btn btn-info shadow-lg" onclick={openCreateModal}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
/>
</svg>
Novo Fluxo
</button>
</div>
</div>
</section>

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -5,7 +5,6 @@
import { goto } from '$app/navigation';
import { resolve } from '$app/paths';
import { page } from '$app/stores';
import ActionGuard from '$lib/components/ActionGuard.svelte';
import RelogioPrazo from '$lib/components/RelogioPrazo.svelte';
const client = useConvexClient();
@@ -651,26 +650,24 @@
</div>
{#if instance.status === 'active'}
<ActionGuard recurso="fluxos_instancias" acao="cancelar">
<button class="btn btn-error btn-outline" onclick={() => (showCancelModal = true)}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
Cancelar Fluxo
</button>
</ActionGuard>
<button class="btn btn-error btn-outline" onclick={() => (showCancelModal = true)}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
Cancelar Fluxo
</button>
{/if}
</div>
</div>
@@ -867,68 +864,60 @@
{#if instance.status === 'active'}
<div class="flex flex-wrap gap-2">
{#if step.status === 'pending'}
<ActionGuard recurso="fluxos_instancias" acao="avancar_passo">
<button
class="btn btn-info btn-sm"
onclick={() => handleStartStep(step._id)}
disabled={isProcessing}
>
Iniciar
</button>
</ActionGuard>
<button
class="btn btn-info btn-sm"
onclick={() => handleStartStep(step._id)}
disabled={isProcessing}
>
Iniciar
</button>
{:else if step.status === 'in_progress'}
<ActionGuard recurso="fluxos_instancias" acao="avancar_passo">
<button
class="btn btn-success btn-sm"
onclick={() => handleCompleteStep(step._id)}
disabled={isProcessing}
>
Concluir
</button>
<button
class="btn btn-warning btn-sm"
onclick={() => handleBlockStep(step._id)}
disabled={isProcessing}
>
Bloquear
</button>
</ActionGuard>
<button
class="btn btn-success btn-sm"
onclick={() => handleCompleteStep(step._id)}
disabled={isProcessing}
>
Concluir
</button>
<button
class="btn btn-warning btn-sm"
onclick={() => handleBlockStep(step._id)}
disabled={isProcessing}
>
Bloquear
</button>
{:else if step.status === 'blocked'}
<ActionGuard recurso="fluxos_instancias" acao="avancar_passo">
<button
class="btn btn-info btn-sm"
onclick={() => handleStartStep(step._id)}
disabled={isProcessing}
>
Desbloquear
</button>
</ActionGuard>
<button
class="btn btn-info btn-sm"
onclick={() => handleStartStep(step._id)}
disabled={isProcessing}
>
Desbloquear
</button>
{/if}
<ActionGuard recurso="fluxos_instancias" acao="atribuir_usuario">
<button
class="btn btn-ghost btn-sm"
onclick={() => openReassignModal(step)}
aria-label="Reatribuir responsável"
title="Reatribuir responsável"
<button
class="btn btn-ghost btn-sm"
onclick={() => openReassignModal(step)}
aria-label="Reatribuir responsável"
title="Reatribuir responsável"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
/>
</svg>
</button>
</ActionGuard>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
/>
</svg>
</button>
</div>
{/if}
</div>
@@ -1104,30 +1093,28 @@
{/if}
</div>
{#if instance.status === 'active'}
<ActionGuard recurso="fluxos_documentos" acao="upload">
<button
class="btn btn-ghost btn-xs"
onclick={() => openUploadModal(step)}
aria-label="Upload de documento"
<button
class="btn btn-ghost btn-xs"
onclick={() => openUploadModal(step)}
aria-label="Upload de documento"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
/>
</svg>
Enviar
</button>
</ActionGuard>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
/>
</svg>
Enviar
</button>
{/if}
</div>
@@ -1158,29 +1145,27 @@
</div>
</div>
{#if instance.status === 'active'}
<ActionGuard recurso="fluxos_documentos" acao="excluir">
<button
class="btn btn-ghost btn-xs text-error shrink-0"
onclick={() => handleDeleteDocument(doc._id)}
aria-label="Excluir documento {doc.name}"
<button
class="btn btn-ghost btn-xs text-error shrink-0"
onclick={() => handleDeleteDocument(doc._id)}
aria-label="Excluir documento {doc.name}"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</ActionGuard>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
{/if}
</div>
{/each}

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -1,434 +0,0 @@
<script lang="ts">
import { resolve } from '$app/paths';
import { Shield, FileText, Mail, Phone, Calendar } from 'lucide-svelte';
import { useQuery } from 'convex-svelte';
import { api } from '@sgse-app/backend/convex/_generated/api';
const configLGPD = useQuery(api.lgpd.obterConfiguracaoLGPD, {});
const encarregadoNome = $derived(
configLGPD?.data?.encarregadoNome || 'Encarregado de Proteção de Dados'
);
const encarregadoEmail = $derived(
configLGPD?.data?.encarregadoEmail || 'lgpd@esportes.pe.gov.br'
);
const encarregadoTelefone = $derived(configLGPD?.data?.encarregadoTelefone || '(81) 3184-XXXX');
const encarregadoHorario = $derived(
configLGPD?.data?.encarregadoHorarioAtendimento || 'Segunda a Sexta, das 8h às 17h'
);
</script>
<div class="container mx-auto max-w-4xl px-4 py-8">
<!-- Header -->
<div class="mb-8">
<div class="mb-4 flex items-center gap-4">
<div class="bg-primary/10 rounded-xl p-3">
<Shield class="text-primary h-8 w-8" strokeWidth={2} />
</div>
<div>
<h1 class="text-base-content text-3xl font-bold">Política de Privacidade</h1>
<p class="text-base-content/60 mt-1">
Lei Geral de Proteção de Dados Pessoais (LGPD) - Lei nº 13.709/2018
</p>
</div>
</div>
<div class="text-base-content/60 flex items-center gap-2 text-sm">
<Calendar class="h-4 w-4" />
<span>Última atualização: {new Date().toLocaleDateString('pt-BR')}</span>
</div>
</div>
<!-- Conteúdo -->
<div class="prose prose-lg max-w-none">
<!-- Introdução -->
<section class="card bg-base-100 mb-6 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4 text-2xl">1. Introdução</h2>
<p class="text-base-content/80">
A Secretaria de Esportes do Estado de Pernambuco, no exercício de suas atribuições
constitucionais e legais, está comprometida com a proteção dos dados pessoais de seus
servidores, colaboradores e cidadãos, em conformidade com a Lei Geral de Proteção de Dados
Pessoais (LGPD) - Lei nº 13.709/2018.
</p>
<p class="text-base-content/80 mt-4">
Esta Política de Privacidade descreve como coletamos, utilizamos, armazenamos e protegemos
seus dados pessoais no Sistema de Gestão da Secretaria de Esportes (SGSE).
</p>
</div>
</section>
<!-- Dados Coletados -->
<section class="card bg-base-100 mb-6 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4 text-2xl">2. Dados Pessoais Coletados</h2>
<p class="text-base-content/80 mb-4">
O SGSE coleta e processa os seguintes tipos de dados pessoais:
</p>
<div class="space-y-3">
<div class="flex items-start gap-3">
<FileText class="text-primary mt-1 h-5 w-5 flex-shrink-0" />
<div>
<h3 class="font-semibold">Dados de Identificação</h3>
<p class="text-base-content/70 text-sm">
Nome completo, CPF, RG, data de nascimento, naturalidade, nacionalidade, estado
civil, filiação (nome do pai e mãe)
</p>
</div>
</div>
<div class="flex items-start gap-3">
<FileText class="text-primary mt-1 h-5 w-5 flex-shrink-0" />
<div>
<h3 class="font-semibold">Dados de Contato</h3>
<p class="text-base-content/70 text-sm">
E-mail, telefone, endereço residencial e endereços de marcação de ponto
</p>
</div>
</div>
<div class="flex items-start gap-3">
<FileText class="text-primary mt-1 h-5 w-5 flex-shrink-0" />
<div>
<h3 class="font-semibold">Dados Profissionais</h3>
<p class="text-base-content/70 text-sm">
Matrícula, cargo, função, setor, data de admissão, regime de trabalho, documentos
profissionais (CTPS, título eleitor, reservista, PIS)
</p>
</div>
</div>
<div class="flex items-start gap-3">
<FileText class="text-primary mt-1 h-5 w-5 flex-shrink-0" />
<div>
<h3 class="font-semibold">Dados de Saúde</h3>
<p class="text-base-content/70 text-sm">
Atestados médicos, licenças de saúde, grupo sanguíneo, fator RH (quando necessário
para atividades específicas)
</p>
</div>
</div>
<div class="flex items-start gap-3">
<FileText class="text-primary mt-1 h-5 w-5 flex-shrink-0" />
<div>
<h3 class="font-semibold">Dados de Acesso</h3>
<p class="text-base-content/70 text-sm">
Credenciais de acesso, logs de acesso, endereço IP, histórico de atividades no
sistema
</p>
</div>
</div>
</div>
</div>
</section>
<!-- Finalidade -->
<section class="card bg-base-100 mb-6 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4 text-2xl">3. Finalidade do Tratamento</h2>
<p class="text-base-content/80 mb-4">
Os dados pessoais são tratados para as seguintes finalidades:
</p>
<ul class="text-base-content/80 list-inside list-disc space-y-2">
<li>Gestão de recursos humanos e folha de pagamento</li>
<li>Controle de ponto e registro de jornada de trabalho</li>
<li>Gestão de férias, ausências e licenças</li>
<li>Processamento de atestados médicos e licenças de saúde</li>
<li>Gestão de chamados e suporte técnico</li>
<li>Comunicação interna e notificações</li>
<li>Cumprimento de obrigações legais e regulatórias</li>
<li>Execução de políticas públicas</li>
<li>Segurança e prevenção de fraudes</li>
<li>Auditoria e controle interno</li>
</ul>
</div>
</section>
<!-- Base Legal -->
<section class="card bg-base-100 mb-6 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4 text-2xl">4. Base Legal do Tratamento</h2>
<p class="text-base-content/80 mb-4">
O tratamento de dados pessoais no SGSE fundamenta-se nas seguintes bases legais, conforme
previsto no Art. 7º da LGPD:
</p>
<div class="space-y-3">
<div class="bg-primary/5 rounded-lg p-4">
<h3 class="text-primary mb-2 font-semibold">I. Execução de Políticas Públicas</h3>
<p class="text-base-content/70 text-sm">
Art. 7º, II - Para a execução de políticas públicas previstas em leis ou regulamentos
</p>
</div>
<div class="bg-primary/5 rounded-lg p-4">
<h3 class="text-primary mb-2 font-semibold">II. Cumprimento de Obrigação Legal</h3>
<p class="text-base-content/70 text-sm">
Art. 7º, I - Para cumprimento de obrigação legal ou regulatória pelo controlador
</p>
</div>
<div class="bg-primary/5 rounded-lg p-4">
<h3 class="text-primary mb-2 font-semibold">III. Execução de Contrato</h3>
<p class="text-base-content/70 text-sm">
Art. 7º, V - Para a execução de contrato ou de procedimentos preliminares relacionados
a contrato do qual seja parte o titular
</p>
</div>
<div class="bg-primary/5 rounded-lg p-4">
<h3 class="text-primary mb-2 font-semibold">IV. Proteção da Vida e Saúde</h3>
<p class="text-base-content/70 text-sm">
Art. 7º, VI e VII - Para a proteção da vida ou da incolumidade física do titular ou de
terceiro, e para a tutela da saúde
</p>
</div>
</div>
</div>
</section>
<!-- Compartilhamento -->
<section class="card bg-base-100 mb-6 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4 text-2xl">5. Compartilhamento de Dados</h2>
<p class="text-base-content/80 mb-4">Os dados pessoais podem ser compartilhados com:</p>
<ul class="text-base-content/80 list-inside list-disc space-y-2">
<li>
<strong>Órgãos Públicos:</strong> Quando necessário para cumprimento de obrigações legais
ou execução de políticas públicas
</li>
<li>
<strong>Fornecedores de Serviços:</strong> Empresas contratadas para prestação de serviços
técnicos, sempre com garantias de proteção de dados
</li>
<li>
<strong>Autoridades Competentes:</strong> Quando exigido por determinação judicial ou legal
</li>
</ul>
<div class="alert alert-info mt-4">
<p class="text-sm">
Todos os compartilhamentos são realizados com base legal e com garantias de proteção dos
dados pessoais.
</p>
</div>
</div>
</section>
<!-- Segurança -->
<section class="card bg-base-100 mb-6 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4 text-2xl">6. Medidas de Segurança</h2>
<p class="text-base-content/80 mb-4">
Adotamos medidas técnicas e administrativas para proteger seus dados pessoais:
</p>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="bg-base-200 rounded-lg p-4">
<h3 class="mb-2 font-semibold">Medidas Técnicas</h3>
<ul class="text-base-content/70 space-y-1 text-sm">
<li>• Criptografia de dados sensíveis</li>
<li>• Controle de acesso por permissões</li>
<li>• Logs de auditoria</li>
<li>• Backup regular</li>
<li>• Monitoramento de segurança</li>
</ul>
</div>
<div class="bg-base-200 rounded-lg p-4">
<h3 class="mb-2 font-semibold">Medidas Administrativas</h3>
<ul class="text-base-content/70 space-y-1 text-sm">
<li>• Treinamento de equipe</li>
<li>• Políticas de acesso</li>
<li>• Procedimentos de segurança</li>
<li>• Gestão de incidentes</li>
<li>• Revisão periódica</li>
</ul>
</div>
</div>
</div>
</section>
<!-- Retenção -->
<section class="card bg-base-100 mb-6 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4 text-2xl">7. Prazo de Retenção</h2>
<p class="text-base-content/80 mb-4">
Os dados pessoais são mantidos pelo prazo necessário para:
</p>
<ul class="text-base-content/80 list-inside list-disc space-y-2">
<li>
<strong>Dados de Funcionários Ativos:</strong> Durante todo o período de vínculo empregatício/estatutário
</li>
<li>
<strong>Dados de Funcionários Inativos:</strong> Conforme prazo legal aplicável (em geral,
5 anos após desligamento)
</li>
<li>
<strong>Logs de Acesso:</strong> 2 anos, conforme recomendação da ANPD
</li>
<li>
<strong>Documentos Trabalhistas:</strong> Conforme legislação trabalhista aplicável
</li>
</ul>
<p class="text-base-content/80 mt-4">
Após o término do prazo de retenção, os dados são eliminados de forma segura, exceto
quando houver obrigação legal de manutenção.
</p>
</div>
</section>
<!-- Direitos do Titular -->
<section class="card bg-base-100 mb-6 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4 text-2xl">8. Direitos do Titular dos Dados</h2>
<p class="text-base-content/80 mb-4">
Conforme previsto no Art. 18 da LGPD, você possui os seguintes direitos:
</p>
<div class="space-y-3">
<div class="flex items-start gap-3">
<div class="badge badge-primary badge-lg">1</div>
<div>
<h3 class="font-semibold">Confirmação da Existência de Tratamento</h3>
<p class="text-base-content/70 text-sm">Confirmar se tratamos seus dados pessoais</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="badge badge-primary badge-lg">2</div>
<div>
<h3 class="font-semibold">Acesso aos Dados</h3>
<p class="text-base-content/70 text-sm">
Acessar seus dados pessoais tratados por nós
</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="badge badge-primary badge-lg">3</div>
<div>
<h3 class="font-semibold">Correção de Dados</h3>
<p class="text-base-content/70 text-sm">
Solicitar correção de dados incompletos, inexatos ou desatualizados
</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="badge badge-primary badge-lg">4</div>
<div>
<h3 class="font-semibold">Anonimização, Bloqueio ou Eliminação</h3>
<p class="text-base-content/70 text-sm">
Solicitar anonimização, bloqueio ou eliminação de dados desnecessários ou excessivos
</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="badge badge-primary badge-lg">5</div>
<div>
<h3 class="font-semibold">Portabilidade dos Dados</h3>
<p class="text-base-content/70 text-sm">
Solicitar a portabilidade dos dados a outro fornecedor de serviço ou produto
</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="badge badge-primary badge-lg">6</div>
<div>
<h3 class="font-semibold">Eliminação de Dados</h3>
<p class="text-base-content/70 text-sm">
Solicitar a eliminação dos dados pessoais tratados com base em consentimento
</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="badge badge-primary badge-lg">7</div>
<div>
<h3 class="font-semibold">Informação sobre Compartilhamento</h3>
<p class="text-base-content/70 text-sm">
Obter informações sobre compartilhamento de dados com terceiros
</p>
</div>
</div>
<div class="flex items-start gap-3">
<div class="badge badge-primary badge-lg">8</div>
<div>
<h3 class="font-semibold">Revogação de Consentimento</h3>
<p class="text-base-content/70 text-sm">
Revogar seu consentimento, quando aplicável
</p>
</div>
</div>
</div>
<div class="mt-6">
<a
href={resolve('/privacidade/meus-dados')}
class="btn btn-primary btn-lg w-full md:w-auto"
>
<FileText class="h-5 w-5" />
Solicitar Meus Direitos
</a>
</div>
</div>
</section>
<!-- Encarregado -->
<section class="card bg-base-100 mb-6 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4 text-2xl">9. Encarregado de Proteção de Dados (DPO)</h2>
<p class="text-base-content/80 mb-4">
Para exercer seus direitos ou esclarecer dúvidas sobre o tratamento de dados pessoais,
entre em contato com nosso Encarregado de Proteção de Dados:
</p>
<div class="bg-primary/5 space-y-3 rounded-lg p-6">
{#if encarregadoNome && encarregadoNome !== 'Encarregado de Proteção de Dados'}
<div class="flex items-center gap-3">
<FileText class="text-primary h-5 w-5" />
<div>
<p class="text-sm font-semibold">Nome</p>
<p class="text-base-content/70">{encarregadoNome}</p>
</div>
</div>
{/if}
<div class="flex items-center gap-3">
<Mail class="text-primary h-5 w-5" />
<div>
<p class="text-sm font-semibold">E-mail</p>
<p class="text-base-content/70">{encarregadoEmail}</p>
</div>
</div>
<div class="flex items-center gap-3">
<Phone class="text-primary h-5 w-5" />
<div>
<p class="text-sm font-semibold">Telefone</p>
<p class="text-base-content/70">{encarregadoTelefone}</p>
</div>
</div>
<div class="flex items-center gap-3">
<FileText class="text-primary h-5 w-5" />
<div>
<p class="text-sm font-semibold">Horário de Atendimento</p>
<p class="text-base-content/70">{encarregadoHorario}</p>
</div>
</div>
</div>
<div class="alert alert-info mt-4">
<p class="text-sm">
As solicitações serão respondidas em até {configLGPD?.data?.prazoRespostaPadrao || 15} (quinze)
dias, conforme previsto na LGPD.
</p>
</div>
</div>
</section>
<!-- Alterações -->
<section class="card bg-base-100 mb-6 shadow-xl">
<div class="card-body">
<h2 class="card-title mb-4 text-2xl">10. Alterações nesta Política</h2>
<p class="text-base-content/80">
Esta Política de Privacidade pode ser atualizada periodicamente. Recomendamos que você
revise esta página regularmente para estar ciente de quaisquer alterações. A data da
última atualização está indicada no topo desta página.
</p>
</div>
</section>
<!-- Ações -->
<div class="mt-8 flex flex-col gap-4 sm:flex-row">
<a href={resolve('/privacidade/meus-dados')} class="btn btn-primary btn-lg flex-1">
<FileText class="h-5 w-5" />
Solicitar Meus Direitos LGPD
</a>
<a href={resolve('/termo-consentimento')} class="btn btn-outline btn-lg flex-1">
<Shield class="h-5 w-5" />
Ver Termo de Consentimento
</a>
</div>
</div>
</div>

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,4 @@
export const load = async ({ parent }) => {
const { currentUser } = await parent();
console.log(currentUser);
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};

View File

@@ -0,0 +1,3 @@
export const load = async ({ parent }) => {
await parent();
};