Ajustes gerais #57
@@ -46,7 +46,7 @@
|
|||||||
} from '$lib/utils/chamados';
|
} from '$lib/utils/chamados';
|
||||||
import { useConvexWithAuth } from '$lib/hooks/useConvexWithAuth';
|
import { useConvexWithAuth } from '$lib/hooks/useConvexWithAuth';
|
||||||
import type { Doc } from '@sgse-app/backend/convex/_generated/dataModel';
|
import type { Doc } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||||
import { temasDisponiveis, aplicarTema, type Tema } from '$lib/utils/temas';
|
import { temasDisponiveis, aplicarTema } from '$lib/utils/temas';
|
||||||
|
|
||||||
const client = useConvexClient();
|
const client = useConvexClient();
|
||||||
// @ts-expect-error - Convex types issue with getCurrentUser
|
// @ts-expect-error - Convex types issue with getCurrentUser
|
||||||
@@ -128,6 +128,9 @@
|
|||||||
const funcionarioIdDisponivel = $derived(currentUser?.data?.funcionarioId ?? null);
|
const funcionarioIdDisponivel = $derived(currentUser?.data?.funcionarioId ?? null);
|
||||||
const gestorIdDisponivel = $derived(currentUser?.data?._id ?? null);
|
const gestorIdDisponivel = $derived(currentUser?.data?._id ?? null);
|
||||||
|
|
||||||
|
// Qualquer usuário com funcionarioId é considerado funcionário
|
||||||
|
const isFuncionario = $derived(!!funcionarioIdDisponivel);
|
||||||
|
|
||||||
// Verificar autenticação antes de executar queries
|
// Verificar autenticação antes de executar queries
|
||||||
const usuarioAutenticado = $derived(
|
const usuarioAutenticado = $derived(
|
||||||
currentUser?.data !== null && currentUser?.data !== undefined
|
currentUser?.data !== null && currentUser?.data !== undefined
|
||||||
@@ -818,8 +821,8 @@
|
|||||||
<FileCheck class="h-5 w-5" strokeWidth={2} />
|
<FileCheck class="h-5 w-5" strokeWidth={2} />
|
||||||
Meus Chamados
|
Meus Chamados
|
||||||
</button>
|
</button>
|
||||||
|
{#if isFuncionario}
|
||||||
{#if ehGestor}
|
<!-- Funcionário: solicitar férias -->
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
role="tab"
|
role="tab"
|
||||||
@@ -830,6 +833,7 @@
|
|||||||
Minhas Férias
|
Minhas Férias
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- Funcionário: solicitar ausências -->
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
role="tab"
|
role="tab"
|
||||||
@@ -839,8 +843,10 @@
|
|||||||
<Clock class="h-5 w-5" strokeWidth={2} />
|
<Clock class="h-5 w-5" strokeWidth={2} />
|
||||||
Minhas Ausências
|
Minhas Ausências
|
||||||
</button>
|
</button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if ehGestor}
|
{#if ehGestor}
|
||||||
|
<!-- Gestor: aprovar férias -->
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
role="tab"
|
role="tab"
|
||||||
@@ -851,13 +857,13 @@
|
|||||||
Aprovar Férias
|
Aprovar Férias
|
||||||
{#if (solicitacoesSubordinados || []).filter((s) => s.status === 'aguardando_aprovacao').length > 0}
|
{#if (solicitacoesSubordinados || []).filter((s) => s.status === 'aguardando_aprovacao').length > 0}
|
||||||
<span class="badge badge-error badge-sm ml-1 animate-pulse">
|
<span class="badge badge-error badge-sm ml-1 animate-pulse">
|
||||||
{(solicitacoesSubordinados || []).filter(
|
{(solicitacoesSubordinados || []).filter((s) => s.status === 'aguardando_aprovacao')
|
||||||
(s) => s.status === 'aguardando_aprovacao'
|
.length}
|
||||||
).length}
|
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- Gestor: aprovar ausências -->
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
role="tab"
|
role="tab"
|
||||||
@@ -874,7 +880,6 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -1217,7 +1222,7 @@
|
|||||||
>
|
>
|
||||||
{#if setoresQuery?.data && setoresQuery.data.length > 0}
|
{#if setoresQuery?.data && setoresQuery.data.length > 0}
|
||||||
<div class="mt-2 flex flex-wrap gap-2">
|
<div class="mt-2 flex flex-wrap gap-2">
|
||||||
{#each setoresQuery.data as setor}
|
{#each setoresQuery.data as setor (setor._id)}
|
||||||
<div
|
<div
|
||||||
class="badge badge-lg font-semibold shadow-sm"
|
class="badge badge-lg font-semibold shadow-sm"
|
||||||
style="background-color: rgba(20, 184, 166, 0.1); border-color: rgba(20, 184, 166, 0.3); color: rgb(15, 118, 110);"
|
style="background-color: rgba(20, 184, 166, 0.1); border-color: rgba(20, 184, 166, 0.3); color: rgb(15, 118, 110);"
|
||||||
@@ -1229,8 +1234,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{:else if setoresQuery?.isLoading}
|
|
||||||
<p class="text-base-content/50 mt-1 text-sm">Carregando...</p>
|
|
||||||
{:else}
|
{:else}
|
||||||
<p class="text-base-content/50 mt-1 text-sm">Nenhum setor atribuído</p>
|
<p class="text-base-content/50 mt-1 text-sm">Nenhum setor atribuído</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -22,18 +22,19 @@
|
|||||||
import { ptBR } from 'date-fns/locale';
|
import { ptBR } from 'date-fns/locale';
|
||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
|
|
||||||
type StatusFiltro = 'pendente' | 'em_analise' | 'concluida' | 'rejeitada' | null;
|
type StatusFiltro = '' | 'pendente' | 'em_analise' | 'concluida' | 'rejeitada';
|
||||||
type TipoFiltro =
|
type TipoFiltro =
|
||||||
|
| ''
|
||||||
| 'acesso'
|
| 'acesso'
|
||||||
| 'correcao'
|
| 'correcao'
|
||||||
| 'exclusao'
|
| 'exclusao'
|
||||||
| 'portabilidade'
|
| 'portabilidade'
|
||||||
| 'revogacao_consentimento'
|
| 'revogacao_consentimento'
|
||||||
| 'informacao_compartilhamento'
|
| 'informacao_compartilhamento';
|
||||||
| null;
|
|
||||||
|
|
||||||
let statusFiltro = $state<StatusFiltro>(null);
|
// '' = Todos (sem filtro)
|
||||||
let tipoFiltro = $state<TipoFiltro>(null);
|
let statusFiltro = $state<StatusFiltro>('');
|
||||||
|
let tipoFiltro = $state<TipoFiltro>('');
|
||||||
let termoBusca = $state('');
|
let termoBusca = $state('');
|
||||||
|
|
||||||
const client = useConvexClient();
|
const client = useConvexClient();
|
||||||
@@ -221,7 +222,7 @@
|
|||||||
<span class="label-text font-semibold">Status</span>
|
<span class="label-text font-semibold">Status</span>
|
||||||
</label>
|
</label>
|
||||||
<select bind:value={statusFiltro} class="select select-bordered">
|
<select bind:value={statusFiltro} class="select select-bordered">
|
||||||
<option value={null}>Todos</option>
|
<option value="">Todos</option>
|
||||||
<option value="pendente">Pendente</option>
|
<option value="pendente">Pendente</option>
|
||||||
<option value="em_analise">Em Análise</option>
|
<option value="em_analise">Em Análise</option>
|
||||||
<option value="concluida">Concluída</option>
|
<option value="concluida">Concluída</option>
|
||||||
@@ -234,7 +235,7 @@
|
|||||||
<span class="label-text font-semibold">Tipo</span>
|
<span class="label-text font-semibold">Tipo</span>
|
||||||
</label>
|
</label>
|
||||||
<select bind:value={tipoFiltro} class="select select-bordered">
|
<select bind:value={tipoFiltro} class="select select-bordered">
|
||||||
<option value={null}>Todos</option>
|
<option value="">Todos</option>
|
||||||
<option value="acesso">Acesso</option>
|
<option value="acesso">Acesso</option>
|
||||||
<option value="correcao">Correção</option>
|
<option value="correcao">Correção</option>
|
||||||
<option value="exclusao">Exclusão</option>
|
<option value="exclusao">Exclusão</option>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { getCurrentUserFunction } from './auth';
|
|||||||
import { Id, Doc } from './_generated/dataModel';
|
import { Id, Doc } from './_generated/dataModel';
|
||||||
import type { QueryCtx, MutationCtx } from './_generated/server';
|
import type { QueryCtx, MutationCtx } from './_generated/server';
|
||||||
import { registrarAtividade } from './logsAtividades';
|
import { registrarAtividade } from './logsAtividades';
|
||||||
|
import { api } from './_generated/api';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verificar se usuário aceitou o termo de consentimento
|
* Verificar se usuário aceitou o termo de consentimento
|
||||||
@@ -275,6 +276,43 @@ export const criarSolicitacao = mutation({
|
|||||||
solicitacaoId.toString()
|
solicitacaoId.toString()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Notificações (email + opcional chat) para o titular
|
||||||
|
if (usuario.email) {
|
||||||
|
let urlSistema = process.env.FRONTEND_URL || 'http://localhost:5173';
|
||||||
|
if (!urlSistema.match(/^https?:\/\//i)) {
|
||||||
|
urlSistema = `http://${urlSistema}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tipoSolicitacaoLabelMap: Record<string, string> = {
|
||||||
|
acesso: 'Acesso aos Dados',
|
||||||
|
correcao: 'Correção de Dados',
|
||||||
|
exclusao: 'Exclusão de Dados',
|
||||||
|
portabilidade: 'Portabilidade dos Dados',
|
||||||
|
revogacao_consentimento: 'Revogação de Consentimento',
|
||||||
|
informacao_compartilhamento: 'Informação sobre Compartilhamento'
|
||||||
|
};
|
||||||
|
|
||||||
|
const tipoSolicitacaoLabel = tipoSolicitacaoLabelMap[args.tipo] ?? args.tipo;
|
||||||
|
|
||||||
|
// Email usando template LGPD
|
||||||
|
try {
|
||||||
|
await ctx.scheduler.runAfter(0, api.email.enviarEmailComTemplate, {
|
||||||
|
destinatario: usuario.email,
|
||||||
|
destinatarioId: usuario._id,
|
||||||
|
templateCodigo: 'lgpd_solicitacao_criada',
|
||||||
|
variaveis: {
|
||||||
|
nomeTitular: usuario.nome,
|
||||||
|
tipoSolicitacaoLabel,
|
||||||
|
prazoResposta: new Date(prazoResposta).toLocaleDateString('pt-BR'),
|
||||||
|
urlPortalLGPD: `${urlSistema}/privacidade/meus-dados`
|
||||||
|
},
|
||||||
|
enviadoPor: usuario._id
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao agendar email lgpd_solicitacao_criada:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return { sucesso: true, solicitacaoId };
|
return { sucesso: true, solicitacaoId };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -586,6 +624,7 @@ export const responderSolicitacao = mutation({
|
|||||||
throw new Error('Solicitação não encontrada');
|
throw new Error('Solicitação não encontrada');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Atualizar resposta da solicitação
|
||||||
await ctx.db.patch(args.solicitacaoId, {
|
await ctx.db.patch(args.solicitacaoId, {
|
||||||
status: args.status,
|
status: args.status,
|
||||||
resposta: args.resposta,
|
resposta: args.resposta,
|
||||||
@@ -594,6 +633,48 @@ export const responderSolicitacao = mutation({
|
|||||||
respondidoEm: Date.now()
|
respondidoEm: Date.now()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Se for uma solicitação de "Revogar Consentimento" concluída,
|
||||||
|
// revogar todos os consentimentos ativos do titular que fez a solicitação.
|
||||||
|
if (solicitacao.tipo === 'revogacao_consentimento' && args.status === 'concluida') {
|
||||||
|
// Garantir que temos o titular associado
|
||||||
|
if (!solicitacao.usuarioId) {
|
||||||
|
throw new Error(
|
||||||
|
'Solicitação de revogação de consentimento sem usuário associado. Verifique os dados.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buscar consentimentos ativos do usuário
|
||||||
|
const consentimentosAtivos = await ctx.db
|
||||||
|
.query('consentimentos')
|
||||||
|
.withIndex('by_usuario', (q) => q.eq('usuarioId', solicitacao.usuarioId))
|
||||||
|
.filter((q) => q.eq(q.field('aceito'), true))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for (const consentimento of consentimentosAtivos) {
|
||||||
|
// Pular consentimentos já revogados por segurança
|
||||||
|
if (consentimento.revogadoEm) continue;
|
||||||
|
|
||||||
|
await ctx.db.patch(consentimento._id, {
|
||||||
|
revogadoEm: Date.now(),
|
||||||
|
revogadoPor: usuario._id
|
||||||
|
});
|
||||||
|
|
||||||
|
// Registrar atividade individual por consentimento revogado
|
||||||
|
await registrarAtividade(
|
||||||
|
ctx,
|
||||||
|
usuario._id,
|
||||||
|
'revogar_consentimento_por_solicitacao',
|
||||||
|
'consentimentos',
|
||||||
|
JSON.stringify({
|
||||||
|
tipo: consentimento.tipo,
|
||||||
|
origem: 'solicitacao_lgpd',
|
||||||
|
solicitacaoId: args.solicitacaoId
|
||||||
|
}),
|
||||||
|
consentimento._id.toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Log de atividade
|
// Log de atividade
|
||||||
await registrarAtividade(
|
await registrarAtividade(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -604,6 +685,107 @@ export const responderSolicitacao = mutation({
|
|||||||
args.solicitacaoId.toString()
|
args.solicitacaoId.toString()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Notificações para o titular (email + chat)
|
||||||
|
const usuarioTitular = await ctx.db.get(solicitacao.usuarioId);
|
||||||
|
if (usuarioTitular) {
|
||||||
|
let urlSistema = process.env.FRONTEND_URL || 'http://localhost:5173';
|
||||||
|
if (!urlSistema.match(/^https?:\/\//i)) {
|
||||||
|
urlSistema = `http://${urlSistema}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tipoSolicitacaoLabelMap: Record<string, string> = {
|
||||||
|
acesso: 'Acesso aos Dados',
|
||||||
|
correcao: 'Correção de Dados',
|
||||||
|
exclusao: 'Exclusão de Dados',
|
||||||
|
portabilidade: 'Portabilidade dos Dados',
|
||||||
|
revogacao_consentimento: 'Revogação de Consentimento',
|
||||||
|
informacao_compartilhamento: 'Informação sobre Compartilhamento'
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusLabelMap: Record<string, string> = {
|
||||||
|
concluida: 'Concluída',
|
||||||
|
rejeitada: 'Rejeitada',
|
||||||
|
em_analise: 'Em Análise'
|
||||||
|
};
|
||||||
|
|
||||||
|
const tipoSolicitacaoLabel = tipoSolicitacaoLabelMap[solicitacao.tipo] ?? solicitacao.tipo;
|
||||||
|
const statusLabel = statusLabelMap[args.status] ?? args.status;
|
||||||
|
const resumoResposta = args.resposta.length > 500 ? `${args.resposta.slice(0, 500)}...` : args.resposta;
|
||||||
|
|
||||||
|
// Escolher template conforme o tipo
|
||||||
|
const tipoToTemplate: Record<string, string> = {
|
||||||
|
acesso: 'lgpd_resposta_acesso',
|
||||||
|
correcao: 'lgpd_resposta_correcao',
|
||||||
|
exclusao: 'lgpd_resposta_exclusao',
|
||||||
|
portabilidade: 'lgpd_resposta_portabilidade',
|
||||||
|
revogacao_consentimento: 'lgpd_resposta_revogacao_consentimento',
|
||||||
|
informacao_compartilhamento: 'lgpd_resposta_informacao_compartilhamento'
|
||||||
|
};
|
||||||
|
|
||||||
|
const templateCodigo = tipoToTemplate[solicitacao.tipo] ?? 'lgpd_resposta_acesso';
|
||||||
|
|
||||||
|
// Email para o titular
|
||||||
|
if (usuarioTitular.email) {
|
||||||
|
try {
|
||||||
|
await ctx.scheduler.runAfter(0, api.email.enviarEmailComTemplate, {
|
||||||
|
destinatario: usuarioTitular.email,
|
||||||
|
destinatarioId: usuarioTitular._id,
|
||||||
|
templateCodigo,
|
||||||
|
variaveis: {
|
||||||
|
nomeTitular: usuarioTitular.nome,
|
||||||
|
tipoSolicitacaoLabel,
|
||||||
|
statusLabel,
|
||||||
|
resumoResposta,
|
||||||
|
urlPortalLGPD: `${urlSistema}/privacidade/meus-dados`
|
||||||
|
},
|
||||||
|
enviadoPor: usuario._id
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Erro ao agendar email ${templateCodigo}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mensagem simples no chat entre TI (respondente) e o titular
|
||||||
|
try {
|
||||||
|
// Buscar conversa individual existente
|
||||||
|
const conversas = await ctx.db
|
||||||
|
.query('conversas')
|
||||||
|
.filter((q) => q.eq(q.field('tipo'), 'individual'))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let conversaId: Id<'conversas'> | null = null;
|
||||||
|
for (const conversa of conversas) {
|
||||||
|
if (
|
||||||
|
conversa.participantes.length === 2 &&
|
||||||
|
conversa.participantes.includes(usuario._id) &&
|
||||||
|
conversa.participantes.includes(usuarioTitular._id)
|
||||||
|
) {
|
||||||
|
conversaId = conversa._id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!conversaId) {
|
||||||
|
conversaId = await ctx.db.insert('conversas', {
|
||||||
|
tipo: 'individual',
|
||||||
|
participantes: [usuario._id, usuarioTitular._id],
|
||||||
|
criadoPor: usuario._id,
|
||||||
|
criadoEm: Date.now()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.db.insert('mensagens', {
|
||||||
|
conversaId,
|
||||||
|
remetenteId: usuario._id,
|
||||||
|
tipo: 'texto',
|
||||||
|
conteudo: `Respondi sua solicitação LGPD (${tipoSolicitacaoLabel}) com status ${statusLabel}. Resumo: ${resumoResposta}`,
|
||||||
|
enviadaEm: Date.now()
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao criar mensagem de chat para resposta LGPD:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return { sucesso: true };
|
return { sucesso: true };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -549,6 +549,107 @@ export const criarTemplatesPadrao = mutation({
|
|||||||
categoria: 'email' as const,
|
categoria: 'email' as const,
|
||||||
tags: ['monitoramento', 'alerta', 'sistema', 'ti']
|
tags: ['monitoramento', 'alerta', 'sistema', 'ti']
|
||||||
},
|
},
|
||||||
|
// ===================== LGPD =====================
|
||||||
|
{
|
||||||
|
codigo: 'lgpd_solicitacao_criada',
|
||||||
|
nome: 'LGPD - Solicitação Criada',
|
||||||
|
titulo: 'Recebemos sua solicitação LGPD ({{tipoSolicitacaoLabel}})',
|
||||||
|
corpo:
|
||||||
|
'Olá {{nomeTitular}},\n\n' +
|
||||||
|
'Recebemos sua solicitação LGPD do tipo "{{tipoSolicitacaoLabel}}".\n\n' +
|
||||||
|
'Prazo estimado para resposta: até {{prazoResposta}}.\n\n' +
|
||||||
|
'Você pode acompanhar o andamento acessando: {{urlPortalLGPD}}.\n\n' +
|
||||||
|
'Equipe de Proteção de Dados / TI.',
|
||||||
|
variaveis: ['nomeTitular', 'tipoSolicitacaoLabel', 'prazoResposta', 'urlPortalLGPD'],
|
||||||
|
categoria: 'email' as const,
|
||||||
|
tags: ['lgpd', 'solicitacao', 'dados_pessoais']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
codigo: 'lgpd_resposta_acesso',
|
||||||
|
nome: 'LGPD - Resposta Acesso',
|
||||||
|
titulo: 'Resposta à sua solicitação LGPD - Acesso aos Dados',
|
||||||
|
corpo:
|
||||||
|
'Olá {{nomeTitular}},\n\n' +
|
||||||
|
'Sua solicitação LGPD de Acesso aos Dados foi marcada como {{statusLabel}}.\n\n' +
|
||||||
|
'Resumo da resposta:\n{{resumoResposta}}\n\n' +
|
||||||
|
'Para mais detalhes, acesse: {{urlPortalLGPD}}.\n\n' +
|
||||||
|
'Equipe de Proteção de Dados / TI.',
|
||||||
|
variaveis: ['nomeTitular', 'statusLabel', 'resumoResposta', 'urlPortalLGPD'],
|
||||||
|
categoria: 'email' as const,
|
||||||
|
tags: ['lgpd', 'acesso', 'dados_pessoais']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
codigo: 'lgpd_resposta_correcao',
|
||||||
|
nome: 'LGPD - Resposta Correção',
|
||||||
|
titulo: 'Resposta à sua solicitação LGPD - Correção de Dados',
|
||||||
|
corpo:
|
||||||
|
'Olá {{nomeTitular}},\n\n' +
|
||||||
|
'Sua solicitação LGPD de Correção de Dados foi marcada como {{statusLabel}}.\n\n' +
|
||||||
|
'Resumo da resposta:\n{{resumoResposta}}\n\n' +
|
||||||
|
'Para mais detalhes, acesse: {{urlPortalLGPD}}.\n\n' +
|
||||||
|
'Equipe de Proteção de Dados / TI.',
|
||||||
|
variaveis: ['nomeTitular', 'statusLabel', 'resumoResposta', 'urlPortalLGPD'],
|
||||||
|
categoria: 'email' as const,
|
||||||
|
tags: ['lgpd', 'correcao', 'dados_pessoais']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
codigo: 'lgpd_resposta_exclusao',
|
||||||
|
nome: 'LGPD - Resposta Exclusão',
|
||||||
|
titulo: 'Resposta à sua solicitação LGPD - Exclusão de Dados',
|
||||||
|
corpo:
|
||||||
|
'Olá {{nomeTitular}},\n\n' +
|
||||||
|
'Sua solicitação LGPD de Exclusão de Dados foi marcada como {{statusLabel}}.\n\n' +
|
||||||
|
'Resumo da resposta:\n{{resumoResposta}}\n\n' +
|
||||||
|
'Para mais detalhes, acesse: {{urlPortalLGPD}}.\n\n' +
|
||||||
|
'Equipe de Proteção de Dados / TI.',
|
||||||
|
variaveis: ['nomeTitular', 'statusLabel', 'resumoResposta', 'urlPortalLGPD'],
|
||||||
|
categoria: 'email' as const,
|
||||||
|
tags: ['lgpd', 'exclusao', 'dados_pessoais']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
codigo: 'lgpd_resposta_portabilidade',
|
||||||
|
nome: 'LGPD - Resposta Portabilidade',
|
||||||
|
titulo: 'Resposta à sua solicitação LGPD - Portabilidade dos Dados',
|
||||||
|
corpo:
|
||||||
|
'Olá {{nomeTitular}},\n\n' +
|
||||||
|
'Sua solicitação LGPD de Portabilidade dos Dados foi marcada como {{statusLabel}}.\n\n' +
|
||||||
|
'Resumo da resposta:\n{{resumoResposta}}\n\n' +
|
||||||
|
'Caso tenha recebido um arquivo anexo, ele contém os dados em formato portável.\n\n' +
|
||||||
|
'Para mais detalhes, acesse: {{urlPortalLGPD}}.\n\n' +
|
||||||
|
'Equipe de Proteção de Dados / TI.',
|
||||||
|
variaveis: ['nomeTitular', 'statusLabel', 'resumoResposta', 'urlPortalLGPD'],
|
||||||
|
categoria: 'email' as const,
|
||||||
|
tags: ['lgpd', 'portabilidade', 'dados_pessoais']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
codigo: 'lgpd_resposta_revogacao_consentimento',
|
||||||
|
nome: 'LGPD - Resposta Revogação de Consentimento',
|
||||||
|
titulo: 'Confirmação de Revogação de Consentimento',
|
||||||
|
corpo:
|
||||||
|
'Olá {{nomeTitular}},\n\n' +
|
||||||
|
'Sua solicitação LGPD de Revogação de Consentimento foi marcada como {{statusLabel}}.\n\n' +
|
||||||
|
'Resumo da resposta:\n{{resumoResposta}}\n\n' +
|
||||||
|
'Todos os consentimentos ativos associados à sua conta foram marcados como revogados a partir desta data.\n\n' +
|
||||||
|
'Para mais detalhes, acesse: {{urlPortalLGPD}}.\n\n' +
|
||||||
|
'Equipe de Proteção de Dados / TI.',
|
||||||
|
variaveis: ['nomeTitular', 'statusLabel', 'resumoResposta', 'urlPortalLGPD'],
|
||||||
|
categoria: 'email' as const,
|
||||||
|
tags: ['lgpd', 'revogacao_consentimento', 'dados_pessoais']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
codigo: 'lgpd_resposta_informacao_compartilhamento',
|
||||||
|
nome: 'LGPD - Resposta Informação sobre Compartilhamento',
|
||||||
|
titulo: 'Resposta à sua solicitação LGPD - Informação sobre Compartilhamento',
|
||||||
|
corpo:
|
||||||
|
'Olá {{nomeTitular}},\n\n' +
|
||||||
|
'Sua solicitação LGPD de Informação sobre Compartilhamento foi marcada como {{statusLabel}}.\n\n' +
|
||||||
|
'Resumo da resposta:\n{{resumoResposta}}\n\n' +
|
||||||
|
'Para mais detalhes, acesse: {{urlPortalLGPD}}.\n\n' +
|
||||||
|
'Equipe de Proteção de Dados / TI.',
|
||||||
|
variaveis: ['nomeTitular', 'statusLabel', 'resumoResposta', 'urlPortalLGPD'],
|
||||||
|
categoria: 'email' as const,
|
||||||
|
tags: ['lgpd', 'informacao_compartilhamento', 'dados_pessoais']
|
||||||
|
},
|
||||||
{
|
{
|
||||||
codigo: 'ausencia_solicitada',
|
codigo: 'ausencia_solicitada',
|
||||||
nome: 'Ausência Solicitada',
|
nome: 'Ausência Solicitada',
|
||||||
|
|||||||
Reference in New Issue
Block a user