Ajustes gerais #57
@@ -46,7 +46,7 @@
|
||||
} from '$lib/utils/chamados';
|
||||
import { useConvexWithAuth } from '$lib/hooks/useConvexWithAuth';
|
||||
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();
|
||||
// @ts-expect-error - Convex types issue with getCurrentUser
|
||||
@@ -128,6 +128,9 @@
|
||||
const funcionarioIdDisponivel = $derived(currentUser?.data?.funcionarioId ?? 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
|
||||
const usuarioAutenticado = $derived(
|
||||
currentUser?.data !== null && currentUser?.data !== undefined
|
||||
@@ -818,8 +821,8 @@
|
||||
<FileCheck class="h-5 w-5" strokeWidth={2} />
|
||||
Meus Chamados
|
||||
</button>
|
||||
|
||||
{#if ehGestor}
|
||||
{#if isFuncionario}
|
||||
<!-- Funcionário: solicitar férias -->
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
@@ -830,6 +833,7 @@
|
||||
Minhas Férias
|
||||
</button>
|
||||
|
||||
<!-- Funcionário: solicitar ausências -->
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
@@ -839,41 +843,42 @@
|
||||
<Clock class="h-5 w-5" strokeWidth={2} />
|
||||
Minhas Ausências
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if ehGestor}
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
class={`tab tab-lg gap-2 font-semibold transition-all duration-300 ${abaAtiva === 'aprovar-ferias' ? 'tab-active scale-105 bg-gradient-to-r from-green-600 to-emerald-600 text-white shadow-lg' : 'hover:bg-base-100'}`}
|
||||
onclick={() => (abaAtiva = 'aprovar-ferias')}
|
||||
>
|
||||
<CheckCircle2 class="h-5 w-5" strokeWidth={2} />
|
||||
Aprovar Férias
|
||||
{#if (solicitacoesSubordinados || []).filter((s) => s.status === 'aguardando_aprovacao').length > 0}
|
||||
<span class="badge badge-error badge-sm ml-1 animate-pulse">
|
||||
{(solicitacoesSubordinados || []).filter(
|
||||
(s) => s.status === 'aguardando_aprovacao'
|
||||
).length}
|
||||
</span>
|
||||
{/if}
|
||||
</button>
|
||||
{#if ehGestor}
|
||||
<!-- Gestor: aprovar férias -->
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
class={`tab tab-lg gap-2 font-semibold transition-all duration-300 ${abaAtiva === 'aprovar-ferias' ? 'tab-active scale-105 bg-gradient-to-r from-green-600 to-emerald-600 text-white shadow-lg' : 'hover:bg-base-100'}`}
|
||||
onclick={() => (abaAtiva = 'aprovar-ferias')}
|
||||
>
|
||||
<CheckCircle2 class="h-5 w-5" strokeWidth={2} />
|
||||
Aprovar Férias
|
||||
{#if (solicitacoesSubordinados || []).filter((s) => s.status === 'aguardando_aprovacao').length > 0}
|
||||
<span class="badge badge-error badge-sm ml-1 animate-pulse">
|
||||
{(solicitacoesSubordinados || []).filter((s) => s.status === 'aguardando_aprovacao')
|
||||
.length}
|
||||
</span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
class={`tab tab-lg gap-2 font-semibold transition-all duration-300 ${abaAtiva === 'aprovar-ausencias' ? 'tab-active scale-105 bg-gradient-to-r from-orange-600 to-amber-600 text-white shadow-lg' : 'hover:bg-base-100'}`}
|
||||
onclick={() => (abaAtiva = 'aprovar-ausencias')}
|
||||
>
|
||||
<Clock class="h-5 w-5" strokeWidth={2} />
|
||||
Aprovar Ausências
|
||||
{#if (ausenciasSubordinados || []).filter((a) => a.status === 'aguardando_aprovacao').length > 0}
|
||||
<span class="badge badge-error badge-sm ml-1 animate-pulse">
|
||||
{(ausenciasSubordinados || []).filter((a) => a.status === 'aguardando_aprovacao')
|
||||
.length}
|
||||
</span>
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
<!-- Gestor: aprovar ausências -->
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
class={`tab tab-lg gap-2 font-semibold transition-all duration-300 ${abaAtiva === 'aprovar-ausencias' ? 'tab-active scale-105 bg-gradient-to-r from-orange-600 to-amber-600 text-white shadow-lg' : 'hover:bg-base-100'}`}
|
||||
onclick={() => (abaAtiva = 'aprovar-ausencias')}
|
||||
>
|
||||
<Clock class="h-5 w-5" strokeWidth={2} />
|
||||
Aprovar Ausências
|
||||
{#if (ausenciasSubordinados || []).filter((a) => a.status === 'aguardando_aprovacao').length > 0}
|
||||
<span class="badge badge-error badge-sm ml-1 animate-pulse">
|
||||
{(ausenciasSubordinados || []).filter((a) => a.status === 'aguardando_aprovacao')
|
||||
.length}
|
||||
</span>
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<button
|
||||
@@ -1217,7 +1222,7 @@
|
||||
>
|
||||
{#if setoresQuery?.data && setoresQuery.data.length > 0}
|
||||
<div class="mt-2 flex flex-wrap gap-2">
|
||||
{#each setoresQuery.data as setor}
|
||||
{#each setoresQuery.data as setor (setor._id)}
|
||||
<div
|
||||
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);"
|
||||
@@ -1229,8 +1234,6 @@
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else if setoresQuery?.isLoading}
|
||||
<p class="text-base-content/50 mt-1 text-sm">Carregando...</p>
|
||||
{:else}
|
||||
<p class="text-base-content/50 mt-1 text-sm">Nenhum setor atribuído</p>
|
||||
{/if}
|
||||
|
||||
@@ -22,18 +22,19 @@
|
||||
import { ptBR } from 'date-fns/locale';
|
||||
import { toast } from 'svelte-sonner';
|
||||
|
||||
type StatusFiltro = 'pendente' | 'em_analise' | 'concluida' | 'rejeitada' | null;
|
||||
type StatusFiltro = '' | 'pendente' | 'em_analise' | 'concluida' | 'rejeitada';
|
||||
type TipoFiltro =
|
||||
| ''
|
||||
| 'acesso'
|
||||
| 'correcao'
|
||||
| 'exclusao'
|
||||
| 'portabilidade'
|
||||
| 'revogacao_consentimento'
|
||||
| 'informacao_compartilhamento'
|
||||
| null;
|
||||
| 'informacao_compartilhamento';
|
||||
|
||||
let statusFiltro = $state<StatusFiltro>(null);
|
||||
let tipoFiltro = $state<TipoFiltro>(null);
|
||||
// '' = Todos (sem filtro)
|
||||
let statusFiltro = $state<StatusFiltro>('');
|
||||
let tipoFiltro = $state<TipoFiltro>('');
|
||||
let termoBusca = $state('');
|
||||
|
||||
const client = useConvexClient();
|
||||
@@ -221,7 +222,7 @@
|
||||
<span class="label-text font-semibold">Status</span>
|
||||
</label>
|
||||
<select bind:value={statusFiltro} class="select select-bordered">
|
||||
<option value={null}>Todos</option>
|
||||
<option value="">Todos</option>
|
||||
<option value="pendente">Pendente</option>
|
||||
<option value="em_analise">Em Análise</option>
|
||||
<option value="concluida">Concluída</option>
|
||||
@@ -234,7 +235,7 @@
|
||||
<span class="label-text font-semibold">Tipo</span>
|
||||
</label>
|
||||
<select bind:value={tipoFiltro} class="select select-bordered">
|
||||
<option value={null}>Todos</option>
|
||||
<option value="">Todos</option>
|
||||
<option value="acesso">Acesso</option>
|
||||
<option value="correcao">Correção</option>
|
||||
<option value="exclusao">Exclusão</option>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { getCurrentUserFunction } from './auth';
|
||||
import { Id, Doc } from './_generated/dataModel';
|
||||
import type { QueryCtx, MutationCtx } from './_generated/server';
|
||||
import { registrarAtividade } from './logsAtividades';
|
||||
import { api } from './_generated/api';
|
||||
|
||||
/**
|
||||
* Verificar se usuário aceitou o termo de consentimento
|
||||
@@ -275,6 +276,43 @@ export const criarSolicitacao = mutation({
|
||||
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 };
|
||||
}
|
||||
});
|
||||
@@ -586,6 +624,7 @@ export const responderSolicitacao = mutation({
|
||||
throw new Error('Solicitação não encontrada');
|
||||
}
|
||||
|
||||
// Atualizar resposta da solicitação
|
||||
await ctx.db.patch(args.solicitacaoId, {
|
||||
status: args.status,
|
||||
resposta: args.resposta,
|
||||
@@ -594,6 +633,48 @@ export const responderSolicitacao = mutation({
|
||||
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
|
||||
await registrarAtividade(
|
||||
ctx,
|
||||
@@ -604,6 +685,107 @@ export const responderSolicitacao = mutation({
|
||||
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 };
|
||||
}
|
||||
});
|
||||
|
||||
@@ -549,6 +549,107 @@ export const criarTemplatesPadrao = mutation({
|
||||
categoria: 'email' as const,
|
||||
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',
|
||||
nome: 'Ausência Solicitada',
|
||||
|
||||
Reference in New Issue
Block a user