@@ -1,12 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { useQuery, useConvexClient } from 'convex-svelte';
|
||||
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||
import type { FunctionReference } from 'convex/server';
|
||||
import { format } from 'date-fns';
|
||||
import { ptBR } from 'date-fns/locale';
|
||||
import type { Id, Doc } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
|
||||
// Tipos para agendamentos
|
||||
type TipoAgendamento = 'email' | 'chat';
|
||||
type StatusAgendamento = 'agendado' | 'enviado' | 'cancelado';
|
||||
|
||||
interface AgendamentoEmail {
|
||||
@@ -43,7 +42,7 @@
|
||||
| { tipo: 'chat'; dados: AgendamentoChat };
|
||||
|
||||
const client = useConvexClient();
|
||||
const currentUser = useQuery(api.auth.getCurrentUser, {});
|
||||
const currentUser = useQuery(api.auth.getCurrentUser as FunctionReference<'query'>);
|
||||
|
||||
// Queries
|
||||
const templatesQuery = useQuery(api.templatesMensagens.listarTemplates, {});
|
||||
@@ -57,10 +56,9 @@
|
||||
Array.from(emailIdsRastreados).map((id) => id as Id<'notificacoesEmail'>)
|
||||
);
|
||||
// Usar função para evitar execução quando array está vazio
|
||||
const emailsStatusQuery = $derived.by(() => {
|
||||
if (emailIdsArray.length === 0) return null;
|
||||
return useQuery(api.email.buscarEmailsPorIds, { emailIds: emailIdsArray });
|
||||
});
|
||||
const emailsStatusQuery = useQuery(api.email.buscarEmailsPorIds, () =>
|
||||
emailIdsArray.length === 0 ? 'skip' : { emailIds: emailIdsArray }
|
||||
);
|
||||
|
||||
// Queries para agendamentos
|
||||
const agendamentosEmailQuery = useQuery(api.email.listarAgendamentosEmail, {});
|
||||
@@ -101,8 +99,8 @@
|
||||
const carregandoTemplates = $derived(templatesQuery === undefined || templatesQuery === null);
|
||||
const carregandoUsuarios = $derived(usuariosQuery === undefined || usuariosQuery === null);
|
||||
|
||||
// Verificar erros de forma mais robusta
|
||||
const erroTemplates = $derived.by(() => {
|
||||
// Verificar erros de forma mais robusta (código mantido mas variáveis não utilizadas removidas para lint)
|
||||
/* const erroTemplates = $derived.by(() => {
|
||||
if (templatesQuery === undefined || templatesQuery === null) return false;
|
||||
// Verificar se é um objeto com propriedade error
|
||||
if (typeof templatesQuery === 'object' && 'error' in templatesQuery) {
|
||||
@@ -117,7 +115,7 @@
|
||||
return usuariosQuery.error !== undefined && usuariosQuery.error !== null;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}); */
|
||||
|
||||
// Log para debug (remover depois se necessário)
|
||||
$effect(() => {
|
||||
@@ -566,7 +564,7 @@
|
||||
titulo: tituloTemplate.trim(),
|
||||
corpo: corpoTemplate.trim(),
|
||||
variaveis: variaveis.length > 0 ? variaveis : undefined,
|
||||
criadoPorId: currentUser.data._id as Id<'usuarios'>
|
||||
criadoPorId: currentUser.data!._id as Id<'usuarios'>
|
||||
});
|
||||
|
||||
if (resultado.sucesso) {
|
||||
@@ -592,6 +590,11 @@
|
||||
}
|
||||
|
||||
async function enviarNotificacao() {
|
||||
if (!currentUser?.data) {
|
||||
mostrarMensagem('error', 'Você precisa estar autenticado para enviar notificações.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!enviarParaTodos && !destinatarioId) {
|
||||
mostrarMensagem('error', "Selecione um destinatário ou marque 'Enviar para todos'");
|
||||
return;
|
||||
@@ -622,7 +625,7 @@
|
||||
return;
|
||||
}
|
||||
agendadaPara = dataHora.getTime();
|
||||
} catch (error) {
|
||||
} catch {
|
||||
mostrarMensagem('error', 'Data ou hora inválida');
|
||||
return;
|
||||
}
|
||||
@@ -743,9 +746,9 @@
|
||||
templateCodigo: template.codigo,
|
||||
variaveis: {
|
||||
nome: destinatario.nome,
|
||||
matricula: destinatario.matricula
|
||||
matricula: destinatario.matricula || ''
|
||||
},
|
||||
enviadoPor: currentUser.data._id as Id<'usuarios'>,
|
||||
enviadoPor: currentUser.data!._id as Id<'usuarios'>,
|
||||
agendadaPara: agendadaPara
|
||||
});
|
||||
if (emailId) {
|
||||
@@ -783,7 +786,7 @@
|
||||
destinatarioId: destinatario._id as Id<'usuarios'>,
|
||||
assunto: 'Notificação do Sistema',
|
||||
corpo: mensagemPersonalizada,
|
||||
enviadoPor: currentUser.data._id as Id<'usuarios'>,
|
||||
enviadoPor: currentUser.data!._id as Id<'usuarios'>,
|
||||
agendadaPara: agendadaPara
|
||||
});
|
||||
if (emailId) {
|
||||
@@ -946,7 +949,7 @@
|
||||
nome: destinatario.nome,
|
||||
matricula: destinatario.matricula || ''
|
||||
},
|
||||
enviadoPor: currentUser.data._id as Id<'usuarios'>,
|
||||
enviadoPor: currentUser.data!._id as Id<'usuarios'>,
|
||||
agendadaPara: agendadaPara
|
||||
});
|
||||
if (emailId) {
|
||||
@@ -992,11 +995,10 @@
|
||||
destinatarioId: destinatario._id as Id<'usuarios'>,
|
||||
assunto: 'Notificação do Sistema',
|
||||
corpo: mensagemPersonalizada,
|
||||
enviadoPor: currentUser.data?._id as Id<'usuarios'>,
|
||||
enviadoPor: currentUser.data!._id as Id<'usuarios'>,
|
||||
agendadaPara: agendadaPara
|
||||
});
|
||||
if (emailId) {
|
||||
resultadoEmail = { sucesso: true, emailId };
|
||||
if (agendadaPara) {
|
||||
const dataFormatada = format(
|
||||
new Date(agendadaPara),
|
||||
@@ -1203,7 +1205,7 @@
|
||||
{#if carregandoUsuarios}
|
||||
<option disabled>Carregando usuários...</option>
|
||||
{:else if usuarios.length > 0}
|
||||
{#each usuarios as usuario}
|
||||
{#each usuarios as usuario (usuario._id)}
|
||||
<option value={usuario._id}>
|
||||
{usuario.nome} ({usuario.matricula})
|
||||
</option>
|
||||
@@ -1213,11 +1215,11 @@
|
||||
{/if}
|
||||
</select>
|
||||
{#if enviarParaTodos}
|
||||
<label class="label">
|
||||
<div class="label">
|
||||
<span class="label-text-alt text-warning">
|
||||
⚠️ A notificação será enviada para todos os {usuarios.length} usuários do sistema
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1280,7 +1282,7 @@
|
||||
{#if carregandoTemplates}
|
||||
<option disabled>Carregando templates...</option>
|
||||
{:else if templates.length > 0}
|
||||
{#each templates as template}
|
||||
{#each templates as template (template._id)}
|
||||
<option value={template._id}>
|
||||
{template.nome}
|
||||
</option>
|
||||
@@ -1440,9 +1442,9 @@
|
||||
<!-- Terminal de Status -->
|
||||
<div class="mt-4">
|
||||
<div class="mb-2 flex items-center justify-between">
|
||||
<label class="label">
|
||||
<div class="label pl-0">
|
||||
<span class="label-text font-medium">Terminal de Status</span>
|
||||
</label>
|
||||
</div>
|
||||
{#if logsEnvio.length > 0}
|
||||
<button type="button" class="btn btn-sm btn-ghost" onclick={limparLogs}>
|
||||
<svg
|
||||
@@ -1471,7 +1473,7 @@
|
||||
{#if logsEnvio.length === 0}
|
||||
<div class="text-neutral-content/60 italic">Aguardando envio de notificação...</div>
|
||||
{:else}
|
||||
{#each logsEnvio as log}
|
||||
{#each logsEnvio as log, i (i)}
|
||||
<div class="mb-1">
|
||||
<span class="text-neutral-content/60">[{formatarTimestamp(log.timestamp)}]</span>
|
||||
<span
|
||||
@@ -1529,7 +1531,7 @@
|
||||
{:else if templates.length > 0}
|
||||
<!-- Mostrar templates se existirem -->
|
||||
<div class="max-h-[600px] space-y-3 overflow-y-auto">
|
||||
{#each templates as template}
|
||||
{#each templates as template (template._id)}
|
||||
<div class="card bg-base-200 compact">
|
||||
<div class="card-body">
|
||||
<div class="flex items-start justify-between">
|
||||
@@ -1731,17 +1733,11 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each agendamentosFiltrados as agendamento}
|
||||
{#each agendamentosFiltrados as agendamento (agendamento.dados._id)}
|
||||
{@const status = obterStatusAgendamento(agendamento)}
|
||||
{@const nomeDestinatario = obterNomeDestinatario(agendamento)}
|
||||
{@const dataFormatada = formatarDataAgendamento(agendamento)}
|
||||
{@const podeCancelar = status === 'agendado'}
|
||||
{@const templateNome =
|
||||
agendamento.tipo === 'email' && agendamento.dados.templateInfo
|
||||
? agendamento.dados.templateInfo.nome
|
||||
: agendamento.tipo === 'email' && agendamento.dados.templateId
|
||||
? 'Template removido'
|
||||
: '-'}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -1898,18 +1894,19 @@
|
||||
<div class="space-y-4">
|
||||
<!-- Código -->
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<label class="label" for="codigo-template">
|
||||
<span class="label-text font-medium">Código *</span>
|
||||
<span class="label-text-alt">Ex: AVISO_IMPORTANTE</span>
|
||||
</label>
|
||||
<input
|
||||
id="codigo-template"
|
||||
type="text"
|
||||
bind:value={codigoTemplate}
|
||||
placeholder="CODIGO_TEMPLATE"
|
||||
class="input input-bordered"
|
||||
maxlength="50"
|
||||
/>
|
||||
<label class="label">
|
||||
<label class="label" for="codigo-template">
|
||||
<span class="label-text-alt"
|
||||
>Código único para identificar o template (será convertido para MAIÚSCULAS)</span
|
||||
>
|
||||
@@ -1918,34 +1915,36 @@
|
||||
|
||||
<!-- Nome -->
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<label class="label" for="nome-template">
|
||||
<span class="label-text font-medium">Nome *</span>
|
||||
</label>
|
||||
<input
|
||||
id="nome-template"
|
||||
type="text"
|
||||
bind:value={nomeTemplate}
|
||||
placeholder="Nome do Template"
|
||||
class="input input-bordered"
|
||||
maxlength="100"
|
||||
/>
|
||||
<label class="label">
|
||||
<label class="label" for="nome-template">
|
||||
<span class="label-text-alt">Nome exibido na lista de templates</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Título -->
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<label class="label" for="titulo-template">
|
||||
<span class="label-text font-medium">Título *</span>
|
||||
</label>
|
||||
<input
|
||||
id="titulo-template"
|
||||
type="text"
|
||||
bind:value={tituloTemplate}
|
||||
placeholder="Título da Mensagem"
|
||||
class="input input-bordered"
|
||||
maxlength="200"
|
||||
/>
|
||||
<label class="label">
|
||||
<label class="label" for="titulo-template">
|
||||
<span class="label-text-alt"
|
||||
>Título usado no assunto do email ou cabeçalho da mensagem</span
|
||||
>
|
||||
@@ -1954,35 +1953,37 @@
|
||||
|
||||
<!-- Corpo -->
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<label class="label" for="corpo-template">
|
||||
<span class="label-text font-medium">Corpo da Mensagem *</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="corpo-template"
|
||||
bind:value={corpoTemplate}
|
||||
placeholder="Digite o conteúdo da mensagem..."
|
||||
class="textarea textarea-bordered h-32"
|
||||
maxlength="2000"
|
||||
></textarea>
|
||||
<label class="label">
|
||||
<label class="label" for="corpo-template">
|
||||
<span class="label-text-alt"
|
||||
>Use {'{{'}variavel{'}}'} para variáveis dinâmicas (ex: {'{{'}nome{'}}'},
|
||||
{'{{'}data{'}}'})</span
|
||||
>Use {{variavel}} para variáveis dinâmicas (ex: {{nome}},
|
||||
{{data}})</span
|
||||
>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Variáveis -->
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<label class="label" for="variaveis-template">
|
||||
<span class="label-text font-medium">Variáveis (opcional)</span>
|
||||
</label>
|
||||
<input
|
||||
id="variaveis-template"
|
||||
type="text"
|
||||
bind:value={variaveisTemplate}
|
||||
placeholder="nome, data, valor (separadas por vírgula)"
|
||||
class="input input-bordered"
|
||||
/>
|
||||
<label class="label">
|
||||
<label class="label" for="variaveis-template">
|
||||
<span class="label-text-alt"
|
||||
>Liste as variáveis que podem ser substituídas no template (separadas por vírgula ou
|
||||
espaço)</span
|
||||
@@ -2019,6 +2020,6 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-backdrop" onclick={fecharModalNovoTemplate}></div>
|
||||
<button class="modal-backdrop" onclick={fecharModalNovoTemplate}>fechar</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user