import { v } from "convex/values"; import { mutation, query } from "./_generated/server"; import { registrarAtividade } from "./logsAtividades"; import { Doc } from "./_generated/dataModel"; /** * Listar todos os templates */ export const listarTemplates = query({ args: {}, handler: async (ctx) => { const templates = await ctx.db.query("templatesMensagens").collect(); return templates; }, }); /** * Obter template por código */ export const obterTemplatePorCodigo = query({ args: { codigo: v.string(), }, handler: async (ctx, args) => { const template = await ctx.db .query("templatesMensagens") .withIndex("by_codigo", (q) => q.eq("codigo", args.codigo)) .first(); return template; }, }); /** * Criar template customizado (apenas TI_MASTER) */ export const criarTemplate = mutation({ args: { codigo: v.string(), nome: v.string(), titulo: v.string(), corpo: v.string(), variaveis: v.optional(v.array(v.string())), criadoPorId: v.id("usuarios"), }, returns: v.union( v.object({ sucesso: v.literal(true), templateId: v.id("templatesMensagens") }), v.object({ sucesso: v.literal(false), erro: v.string() }) ), handler: async (ctx, args) => { // Verificar se código já existe const existente = await ctx.db .query("templatesMensagens") .withIndex("by_codigo", (q) => q.eq("codigo", args.codigo)) .first(); if (existente) { return { sucesso: false as const, erro: "Código de template já existe" }; } // Criar template const templateId = await ctx.db.insert("templatesMensagens", { codigo: args.codigo, nome: args.nome, tipo: "customizado", titulo: args.titulo, corpo: args.corpo, variaveis: args.variaveis, criadoPor: args.criadoPorId, criadoEm: Date.now(), }); // Log de atividade await registrarAtividade( ctx, args.criadoPorId, "criar", "templates", JSON.stringify({ templateId, codigo: args.codigo, nome: args.nome }), templateId ); return { sucesso: true as const, templateId }; }, }); /** * Editar template customizado (apenas TI_MASTER, não edita templates do sistema) */ export const editarTemplate = mutation({ args: { templateId: v.id("templatesMensagens"), nome: v.optional(v.string()), titulo: v.optional(v.string()), corpo: v.optional(v.string()), variaveis: v.optional(v.array(v.string())), editadoPorId: v.id("usuarios"), }, returns: v.union( v.object({ sucesso: v.literal(true) }), v.object({ sucesso: v.literal(false), erro: v.string() }) ), handler: async (ctx, args) => { const template = await ctx.db.get(args.templateId); if (!template) { return { sucesso: false as const, erro: "Template não encontrado" }; } // Não permite editar templates do sistema if (template.tipo === "sistema") { return { sucesso: false as const, erro: "Templates do sistema não podem ser editados" }; } // Atualizar template const updates: Partial> = {}; if (args.nome !== undefined) updates.nome = args.nome; if (args.titulo !== undefined) updates.titulo = args.titulo; if (args.corpo !== undefined) updates.corpo = args.corpo; if (args.variaveis !== undefined) updates.variaveis = args.variaveis; await ctx.db.patch(args.templateId, updates); // Log de atividade await registrarAtividade( ctx, args.editadoPorId, "editar", "templates", JSON.stringify(updates), args.templateId ); return { sucesso: true as const }; }, }); /** * Excluir template customizado (apenas TI_MASTER, não exclui templates do sistema) */ export const excluirTemplate = mutation({ args: { templateId: v.id("templatesMensagens"), excluidoPorId: v.id("usuarios"), }, returns: v.union( v.object({ sucesso: v.literal(true) }), v.object({ sucesso: v.literal(false), erro: v.string() }) ), handler: async (ctx, args) => { const template = await ctx.db.get(args.templateId); if (!template) { return { sucesso: false as const, erro: "Template não encontrado" }; } // Não permite excluir templates do sistema if (template.tipo === "sistema") { return { sucesso: false as const, erro: "Templates do sistema não podem ser excluídos" }; } // Excluir template await ctx.db.delete(args.templateId); // Log de atividade await registrarAtividade( ctx, args.excluidoPorId, "excluir", "templates", JSON.stringify({ templateId: args.templateId, codigo: template.codigo }), args.templateId ); return { sucesso: true as const }; }, }); /** * Renderizar template com variáveis */ export function renderizarTemplate(template: string, variaveis: Record): string { let resultado = template; for (const [chave, valor] of Object.entries(variaveis)) { const placeholder = `{{${chave}}}`; resultado = resultado.replace(new RegExp(placeholder, "g"), valor); } return resultado; } /** * Criar templates padrão do sistema (chamado no seed) */ export const criarTemplatesPadrao = mutation({ args: {}, handler: async (ctx) => { const templatesPadrao = [ { codigo: "USUARIO_BLOQUEADO", nome: "Usuário Bloqueado", titulo: "Sua conta foi bloqueada", corpo: "Sua conta no SGSE foi bloqueada.\n\nMotivo: {{motivo}}\n\nPara mais informações, entre em contato com a TI.", variaveis: ["motivo"], }, { codigo: "USUARIO_DESBLOQUEADO", nome: "Usuário Desbloqueado", titulo: "Sua conta foi desbloqueada", corpo: "Sua conta no SGSE foi desbloqueada e você já pode acessar o sistema normalmente.", variaveis: [], }, { codigo: "SENHA_RESETADA", nome: "Senha Resetada", titulo: "Sua senha foi resetada", corpo: "Sua senha foi resetada pela equipe de TI.\n\nNova senha temporária: {{senha}}\n\nPor favor, altere sua senha no próximo login.", variaveis: ["senha"], }, { codigo: "PERMISSAO_ALTERADA", nome: "Permissão Alterada", titulo: "Suas permissões foram atualizadas", corpo: "Suas permissões de acesso ao sistema foram atualizadas.\n\nPara verificar suas novas permissões, acesse o menu de perfil.", variaveis: [], }, { codigo: "AVISO_GERAL", nome: "Aviso Geral", titulo: "{{titulo}}", corpo: "{{mensagem}}", variaveis: ["titulo", "mensagem"], }, { codigo: "BEM_VINDO", nome: "Boas-vindas", titulo: "Bem-vindo ao SGSE", corpo: "Olá {{nome}},\n\nSeja bem-vindo ao Sistema de Gestão da Secretaria de Esportes!\n\nSuas credenciais de acesso:\nMatrícula: {{matricula}}\nSenha temporária: {{senha}}\n\nPor favor, altere sua senha no primeiro acesso.\n\nEquipe de TI", variaveis: ["nome", "matricula", "senha"], }, { codigo: "chat_mensagem", nome: "Nova Mensagem no Chat", titulo: "Nova mensagem de {{remetente}}", corpo: "" + "
" + "

Nova mensagem no chat

" + "

{{remetente}} enviou uma nova mensagem:

" + "
" + "

{{mensagem}}

" + "
" + "

" + "" + "Ver conversa" + "" + "

" + "

" + "Você está recebendo este email porque não estava online quando a mensagem foi enviada. " + "Você pode desativar essas notificações nas configurações da conversa." + "

" + "
", variaveis: ["remetente", "mensagem", "conversaId", "urlSistema"], }, { codigo: "chat_mencao", nome: "Menção no Chat", titulo: "{{remetente}} mencionou você", corpo: "" + "
" + "

Você foi mencionado!

" + "

{{remetente}} mencionou você em uma mensagem:

" + "
" + "

{{mensagem}}

" + "
" + "

" + "" + "Ver mensagem" + "" + "

" + "

" + "Você está recebendo este email porque foi mencionado em uma conversa. " + "Você pode desativar essas notificações nas configurações da conversa." + "

" + "
", variaveis: ["remetente", "mensagem", "conversaId", "urlSistema"], }, { codigo: "chamado_registrado", nome: "Chamado Registrado", titulo: "Chamado {{numeroTicket}} registrado", corpo: "" + "
" + "

Chamado registrado com sucesso!

" + "

Olá {{solicitante}},

" + "

Recebemos sua solicitação e iniciaremos o atendimento em breve.

" + "
" + "

Ticket: {{numeroTicket}}

" + "

Prioridade: {{prioridade}}

" + "

Categoria: {{categoria}}

" + "
" + "

" + "" + "Acompanhar chamado" + "" + "

" + "

" + "Central de Chamados SGSE" + "

" + "
", variaveis: ["solicitante", "numeroTicket", "prioridade", "categoria", "urlSistema"], }, { codigo: "chamado_atualizado", nome: "Atualização no Chamado", titulo: "Atualização no chamado {{numeroTicket}}", corpo: "" + "
" + "

Nova atualização no seu chamado

" + "

Olá {{solicitante}},

" + "

Há uma nova atualização no seu chamado:

" + "
" + "

Ticket: {{numeroTicket}}

" + "

Mensagem:

" + "

{{mensagem}}

" + "
" + "

" + "" + "Ver detalhes" + "" + "

" + "

" + "Central de Chamados SGSE" + "

" + "
", variaveis: ["solicitante", "numeroTicket", "mensagem", "urlSistema"], }, { codigo: "chamado_atribuido", nome: "Chamado Atribuído", titulo: "Chamado {{numeroTicket}} atribuído", corpo: "" + "
" + "

Chamado atribuído

" + "

Olá {{responsavel}},

" + "

Um novo chamado foi atribuído para você:

" + "
" + "

Ticket: {{numeroTicket}}

" + "

Solicitante: {{solicitante}}

" + "

Prioridade: {{prioridade}}

" + "

Descrição: {{descricao}}

" + "
" + "

" + "" + "Acessar chamado" + "" + "

" + "

" + "Central de Chamados SGSE" + "

" + "
", variaveis: ["responsavel", "numeroTicket", "solicitante", "prioridade", "descricao", "urlSistema"], }, { codigo: "chamado_alerta_prazo", nome: "Alerta de Prazo do Chamado", titulo: "⚠️ Alerta de prazo - Chamado {{numeroTicket}}", corpo: "" + "
" + "

⚠️ Alerta de prazo

" + "

Olá {{destinatario}},

" + "

O chamado abaixo está próximo do prazo de {{tipoPrazo}}:

" + "
" + "

Ticket: {{numeroTicket}}

" + "

Prazo de {{tipoPrazo}}: {{prazo}}

" + "

Status: {{status}}

" + "
" + "

" + "" + "Ver chamado" + "" + "

" + "

" + "Central de Chamados SGSE" + "

" + "
", variaveis: ["destinatario", "numeroTicket", "tipoPrazo", "prazo", "status", "urlSistema", "rotaAcesso"], }, ]; for (const template of templatesPadrao) { // Verificar se já existe const existente = await ctx.db .query("templatesMensagens") .withIndex("by_codigo", (q) => q.eq("codigo", template.codigo)) .first(); if (!existente) { await ctx.db.insert("templatesMensagens", { ...template, tipo: "sistema", criadoEm: Date.now(), }); } } return { sucesso: true }; }, });