add-report-notification

This commit is contained in:
João Gustavo 2025-11-15 22:04:25 -03:00
parent fb7aec765b
commit dd0a5abb04
5 changed files with 797 additions and 1 deletions

View File

@ -13,6 +13,7 @@ import { buscarPacientes, listarPacientes, buscarPacientePorId, buscarPacientesP
import { ENV_CONFIG } from '@/lib/env-config';
import { useReports } from "@/hooks/useReports";
import { CreateReportData } from "@/types/report-types";
import { createAndNotifyReport } from "@/lib/reportService";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@ -2588,6 +2589,9 @@ const ProfissionalPage = () => {
if (isNewLaudo) {
if (createNewReport) {
const created = await createNewReport(payload as any);
console.log('[LaudoEditor] Report criado:', { created, patient_id: payload.patient_id });
// ✅ Webhook agora é enviado automaticamente dentro de createNewReport() / criarRelatorio()
if (onSaved) onSaved(created);
}
} else {

View File

@ -0,0 +1,275 @@
/**
* EXEMPLO DE USO: Automação n8n para Notificação de Laudos
*
* Este arquivo demonstra como usar a função criarLaudo com integração n8n
* para criar um laudo e notificar automaticamente o paciente.
*/
import { criarLaudo, CriarLaudoData } from '@/lib/reports';
/**
* Exemplo 1: Uso básico - criar um laudo simples
*/
export async function exemploBasico() {
try {
const laudoData: CriarLaudoData = {
pacienteId: 'patient-uuid-123', // ID do paciente (obrigatório)
textoLaudo: 'Paciente apresenta boa saúde geral. Sem achados relevantes.',
};
const novoLaudo = await criarLaudo(laudoData);
console.log('✓ Laudo criado com sucesso!');
console.log('ID do laudo:', novoLaudo.id);
console.log('Mensagem:', novoLaudo.mensagem);
return novoLaudo;
} catch (erro) {
console.error('✗ Erro ao criar laudo:', erro);
throw erro;
}
}
/**
* Exemplo 2: Criar laudo com dados médicos completos
*/
export async function exemploCompleto() {
try {
const laudoData: CriarLaudoData = {
pacienteId: 'patient-uuid-789',
medicoId: 'doctor-uuid-456', // Opcional
textoLaudo: `
AVALIAÇÃO CLÍNICA COMPLETA
Queixa Principal: Dor de cabeça persistente
História Presente:
Paciente relata dor de cabeça tipo tensional 2 semanas,
intensidade 5/10, sem irradiação.
Exame Físico:
- PA: 120/80 mmHg
- FC: 72 bpm
- Sem alterações neurológicas
Impressão Diagnóstica:
Cefaleia tensional
Conduta:
- Repouso adequado
- Analgésicos conforme necessidade
- Retorno em 2 semanas se persistir
`,
exame: 'Consulta Neurologia',
diagnostico: 'Cefaleia tensional',
conclusao: 'Prescrição: Dipirona 500mg 6/6h conforme necessidade',
cidCode: 'G44.2', // CID da cefaleia tensional
status: 'concluido',
};
const novoLaudo = await criarLaudo(laudoData);
console.log('✓ Laudo completo criado com sucesso!');
console.log('ID:', novoLaudo.id);
console.log('Status:', novoLaudo.status);
console.log('CID:', novoLaudo.cid_code);
return novoLaudo;
} catch (erro) {
console.error('✗ Erro:', erro);
throw erro;
}
}
/**
* Exemplo 3: Integração em um componente React
* Este exemplo mostra como usar a função em um formulário
*
* NOTA: Este código deve ser usado em um arquivo .tsx (não .ts)
* e com o import de React importado corretamente
*/
export async function exemploComponenteReact() {
// Este é apenas um exemplo de estrutura para o componente
// Copie o código abaixo para um arquivo .tsx:
/*
'use client';
import React from 'react';
import { criarLaudo, CriarLaudoData } from '@/lib/reports';
export function ComponenteLaudoExemplo() {
const [carregando, setCarregando] = React.useState(false);
const [mensagem, setMensagem] = React.useState('');
const handleCriarLaudo = async (formData: any) => {
setCarregando(true);
setMensagem('');
try {
const laudoData: CriarLaudoData = {
pacienteId: formData.pacienteId,
medicoId: formData.medicoId,
textoLaudo: formData.texto,
exame: formData.exame,
diagnostico: formData.diagnostico,
conclusao: formData.conclusao,
cidCode: formData.cid,
status: 'concluido',
};
const resultado = await criarLaudo(laudoData);
setMensagem(`${resultado.mensagem}`);
console.log('Laudo criado:', resultado.id);
// Você pode fazer mais algo aqui, como:
// - Redirecionar para página do laudo
// - Atualizar lista de laudos
// - Limpar formulário
} catch (erro) {
setMensagem(`✗ Erro: ${erro instanceof Error ? erro.message : String(erro)}`);
} finally {
setCarregando(false);
}
};
return (
<div>
<form onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
handleCriarLaudo(Object.fromEntries(formData));
}}>
<textarea
name="texto"
placeholder="Texto do laudo"
required
/>
<input
type="text"
name="pacienteId"
placeholder="ID do Paciente"
required
/>
<input
type="text"
name="medicoId"
placeholder="ID do Médico"
required
/>
<button type="submit" disabled={carregando}>
{carregando ? 'Criando...' : 'Criar Laudo'}
</button>
</form>
{mensagem && <p>{mensagem}</p>}
</div>
);
}
*/
}
/**
* Exemplo 4: Tratamento de erros específicos
*/
export async function exemploTratamentoErros() {
try {
const laudoData: CriarLaudoData = {
pacienteId: 'patient-id',
medicoId: 'doctor-id',
textoLaudo: 'Texto do laudo',
};
const resultado = await criarLaudo(laudoData);
console.log('Sucesso:', resultado);
} catch (erro) {
if (erro instanceof Error) {
// Trata diferentes tipos de erro
if (erro.message.includes('Paciente ID') || erro.message.includes('Médico ID')) {
console.error('Erro de validação: dados incompletos');
} else if (erro.message.includes('Supabase')) {
console.error('Erro de conexão com banco de dados');
} else if (erro.message.includes('n8n')) {
console.warn('Laudo criado, mas notificação falhou');
} else {
console.error('Erro desconhecido:', erro.message);
}
}
}
}
/**
* DOCUMENTAÇÃO DO FLUXO N8N
*
* A função criarLaudo executa o seguinte fluxo:
*
* 1. CRIAÇÃO NO SUPABASE
* - Salva o report na tabela 'reports' do Supabase
* - Status padrão: 'concluido'
* - Retorna o report criado com seu ID
*
* 2. NOTIFICAÇÃO N8N
* - Se o report foi criado com sucesso, faz um POST para:
* URL: https://joaogustavo.me/webhook/notificar-laudo
* - Envia payload com:
* - pacienteId: ID do paciente (patient_id)
* - reportId: ID do report criado
*
* 3. NO N8N
* O webhook deve estar configurado para:
* - Receber o payload JSON POST
* - Extrair pacienteId e reportId
* - Buscar informações do paciente
* - Enviar notificação (email, SMS, push, etc.)
* - Registrar log da notificação
*
* 4. COMPORTAMENTO EM CASO DE FALHA
* - Se a criação do report falhar: exceção é lançada
* - Se o envio para n8n falhar: report é mantido, erro é logado
* (não bloqueia a operação de criação)
*
* EXEMPLO DE USO:
*
* const novoReport = await criarLaudo({
* pacienteId: "3854866a-5476-48be-8313-77029ccdb70f",
* textoLaudo: "Texto do laudo aqui..."
* });
*
* // Depois disto, automaticamente:
* // 1. Report é salvo no Supabase
* // 2. n8n recebe: { pacienteId: "...", reportId: "..." }
* // 3. Paciente é notificado
*/
/**
* EXEMPLO DE WEBHOOK N8N (Configuração)
*
* No n8n, você deve:
* 1. Criar um novo workflow
* 2. Adicionar trigger: "Webhook"
* 3. Configurar:
* - HTTP Method: POST
* - Path: /notificar-laudo
* - Authentication: None (ou Bearer token se desejar)
* 4. Adicionar nós para:
* - Parse do payload JSON recebido
* - Query no banco de dados para buscar paciente
* - Enviar email/SMS/notificação push
* - Logging do resultado
*
* Exemplo de JavaScript no n8n:
*
* const { pacienteId, laudoId, pacienteName, pacienteEmail } = $input.first().json;
*
* return {
* pacienteId,
* laudoId,
* pacienteName,
* pacienteEmail,
* notificationType: 'laudo_criado',
* timestamp: new Date().toISOString(),
* message: `Novo laudo ${laudoId} disponível para ${pacienteName}`
* };
*/

View File

@ -0,0 +1,193 @@
/**
* Módulo de notificação de laudos via n8n
* Integração com automação n8n para notificar pacientes quando laudos são criados
*/
import { ENV_CONFIG } from '@/lib/env-config';
/**
* Configurações do webhook n8n
*/
const N8N_WEBHOOK_CONFIG = {
// URL do webhook configurado no n8n
webhookUrl: 'https://joaogustavo.me/webhook/notificar-laudo',
// Timeout para a requisição (em ms)
timeout: 30000,
// Tentativas de retry em caso de falha
maxRetries: 3,
};
/**
* Tipos de dados para notificação de laudo
*/
export interface NotificacaoLaudoPayload {
pacienteId: string;
laudoId: string;
pacienteName?: string;
pacienteEmail?: string;
medicalDetails?: {
examType?: string;
medico?: string;
dataEmissao?: string;
};
}
/**
* Resultado da notificação
*/
export interface NotificacaoLaudoResult {
sucesso: boolean;
mensagem: string;
n8nResponse?: any;
erro?: string;
}
/**
* Notifica o n8n sobre a criação de um novo laudo
* @param payload Dados do laudo e paciente para notificação
* @returns Resultado da notificação
*/
export async function notificarLaudoCriadoN8n(
payload: NotificacaoLaudoPayload
): Promise<NotificacaoLaudoResult> {
try {
// Validação básica dos dados
if (!payload.pacienteId || !payload.laudoId) {
return {
sucesso: false,
mensagem: 'Dados de paciente ou laudo inválidos',
erro: 'pacienteId e laudoId são obrigatórios',
};
}
// Constrói o payload para o webhook
const webhookPayload = {
pacienteId: payload.pacienteId,
laudoId: payload.laudoId,
pacienteName: payload.pacienteName || '',
pacienteEmail: payload.pacienteEmail || '',
// Adiciona dados médicos se disponíveis
...(payload.medicalDetails && {
examType: payload.medicalDetails.examType,
medico: payload.medicalDetails.medico,
dataEmissao: payload.medicalDetails.dataEmissao,
}),
// Timestamp da notificação
notificadoEm: new Date().toISOString(),
};
console.log('[n8n] Enviando notificação de laudo criado:', {
pacienteId: payload.pacienteId,
laudoId: payload.laudoId,
webhookUrl: N8N_WEBHOOK_CONFIG.webhookUrl,
});
// Tenta enviar o webhook com retry
let ultimoErro: any = null;
for (let tentativa = 1; tentativa <= N8N_WEBHOOK_CONFIG.maxRetries; tentativa++) {
try {
const controller = new AbortController();
const timeoutId = setTimeout(
() => controller.abort(),
N8N_WEBHOOK_CONFIG.timeout
);
const response = await fetch(N8N_WEBHOOK_CONFIG.webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify(webhookPayload),
signal: controller.signal,
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(
`HTTP ${response.status}: ${response.statusText}`
);
}
const responseData = await response.json();
console.log('[n8n] Notificação enviada com sucesso:', {
status: response.status,
laudoId: payload.laudoId,
});
return {
sucesso: true,
mensagem: 'Paciente notificado com sucesso',
n8nResponse: responseData,
};
} catch (erro) {
ultimoErro = erro;
console.warn(
`[n8n] Tentativa ${tentativa}/${N8N_WEBHOOK_CONFIG.maxRetries} falhou:`,
erro instanceof Error ? erro.message : String(erro)
);
// Se não for a última tentativa, aguarda um pouco antes de tentar novamente
if (tentativa < N8N_WEBHOOK_CONFIG.maxRetries) {
await new Promise((resolve) =>
setTimeout(resolve, 1000 * tentativa) // Backoff exponencial
);
}
}
}
// Se chegou aqui, todas as tentativas falharam
console.error('[n8n] Todas as tentativas de notificação falharam:', ultimoErro);
return {
sucesso: false,
mensagem: 'Falha ao notificar paciente através do n8n',
erro: ultimoErro instanceof Error ? ultimoErro.message : String(ultimoErro),
};
} catch (erro) {
console.error('[notificarLaudoCriadoN8n] Erro inesperado:', erro);
return {
sucesso: false,
mensagem: 'Erro ao processar notificação de laudo',
erro: erro instanceof Error ? erro.message : String(erro),
};
}
}
/**
* Versão assíncrona que não bloqueia - envia notificação em background
* Útil para não aumentar o tempo de resposta da API
* @param payload Dados do laudo e paciente
*/
export function notificarLaudoAsyncBackground(
payload: NotificacaoLaudoPayload
): void {
// Envia notificação em background sem aguardar
notificarLaudoCriadoN8n(payload)
.then((result) => {
if (!result.sucesso) {
console.warn('[n8n] Notificação de laudo falhou (background):', result.erro);
}
})
.catch((erro) => {
console.error('[n8n] Erro ao notificar laudo em background:', erro);
});
}
/**
* Determina se as notificações n8n estão habilitadas
* Pode ser controlado via variável de ambiente
*/
export function notificacoesHabilitadas(): boolean {
if (typeof window === 'undefined') {
// Server-side: verificar variável de ambiente
return process.env.NEXT_PUBLIC_N8N_ENABLED !== 'false';
}
// Client-side: sempre habilitado
return true;
}

View File

@ -0,0 +1,148 @@
/**
* serviço para criar relatórios e notificar pacientes via n8n
*
* Este serviço encapsula a lógica de:
* 1. Criar um novo report no Supabase
* 2. Notificar o paciente via webhook n8n (que dispara SMS via Twilio)
*/
interface CreateReportData {
patientId: string; // UUID do paciente
requestedBy: string; // UUID de quem solicitou (médico)
exam: string;
diagnosis: string;
conclusion: string;
contentHtml: string;
}
interface CreateReportResult {
success: boolean;
report?: any;
error?: string;
}
/**
* Cria um novo report no Supabase e notifica o paciente via n8n
*
* Fluxo:
* 1. Insere um novo registro na tabela 'reports' com status 'draft'
* 2. Envia webhook para n8n com pacienteId e reportId
* 3. n8n recebe e dispara notificação SMS via Twilio
* 4. Retorna o report criado (mesmo que a notificação falhe)
*
* @param data Dados do report a ser criado
* @returns { success: true, report } ou { success: false, error }
*/
export const createAndNotifyReport = async (data: CreateReportData): Promise<CreateReportResult> => {
try {
// Validação básica
if (!data.patientId || !data.exam || !data.conclusion) {
throw new Error('Faltam campos obrigatórios: patientId, exam, conclusion');
}
console.log('[reportService] Criando novo report para paciente:', data.patientId);
// 1. Criar report no Supabase
const BASE_API = 'https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/reports';
let token: string | undefined = undefined;
if (typeof window !== 'undefined') {
token =
localStorage.getItem('auth_token') ||
localStorage.getItem('token') ||
sessionStorage.getItem('auth_token') ||
sessionStorage.getItem('token') ||
undefined;
}
const headers: HeadersInit = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ',
'Prefer': 'return=representation',
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const reportPayload = {
patient_id: data.patientId,
status: 'draft',
requested_by: data.requestedBy,
exam: data.exam,
diagnosis: data.diagnosis,
conclusion: data.conclusion,
content_html: data.contentHtml,
created_at: new Date().toISOString(),
};
const responseSupabase = await fetch(BASE_API, {
method: 'POST',
headers,
body: JSON.stringify(reportPayload),
});
if (!responseSupabase.ok) {
const errorText = await responseSupabase.text();
console.error('[reportService] Erro ao criar report no Supabase:', errorText);
throw new Error(`Supabase error: ${responseSupabase.statusText}`);
}
const newReport = await responseSupabase.json();
// Supabase retorna array
const report = Array.isArray(newReport) ? newReport[0] : newReport;
if (!report || !report.id) {
throw new Error('Report criado mas sem ID retornado');
}
console.log('[reportService] Report criado com sucesso. ID:', report.id);
// 2. Notificar paciente via n8n → Twilio
try {
console.log('[reportService] Enviando notificação para n8n...');
const notificationResponse = await fetch('https://joaogustavo.me/webhook/notificar-laudo', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
pacienteId: report.patient_id, // UUID do paciente
reportId: report.id, // UUID do report
}),
});
if (!notificationResponse.ok) {
console.warn(
'[reportService] Erro ao enviar notificação SMS. Status:',
notificationResponse.status
);
// Não falha a criação do report se SMS falhar
} else {
console.log('[reportService] Notificação enviada com sucesso ao n8n');
}
} catch (erroNotificacao) {
console.warn('[reportService] Erro ao enviar notificação para n8n:', erroNotificacao);
// Não falha a criação do report se a notificação falhar
}
return {
success: true,
report,
};
} catch (error) {
console.error('[reportService] Erro ao criar report:', error);
return {
success: false,
error: error instanceof Error ? error.message : String(error),
};
}
};
/**
* Interface exportada para uso em componentes
*/
export type { CreateReportData, CreateReportResult };

View File

@ -47,6 +47,7 @@ import {
ReportsResponse,
ReportResponse
} from '@/types/report-types';
import { buscarPacientePorId } from '@/lib/api';
// Definição local para ApiError
type ApiError = {
@ -214,7 +215,52 @@ export async function criarRelatorio(dadosRelatorio: CreateReportData, token?: s
const resultado = await resposta.json();
// Supabase retorna array
if (Array.isArray(resultado) && resultado.length > 0) {
return resultado[0];
const novoRelatorio = resultado[0];
// ✅ ENVIAR NOTIFICAÇÃO PARA N8N APÓS CRIAR RELATÓRIO
if (novoRelatorio && novoRelatorio.id && dadosRelatorio.patient_id) {
try {
console.log('[criarRelatorio] Enviando notificação para n8n webhook...');
// Buscar dados do paciente para incluir nome e telefone
const pacienteData = await buscarPacientePorId(dadosRelatorio.patient_id).catch(e => {
console.warn('[criarRelatorio] Erro ao buscar paciente:', e);
return null;
});
const pacienteNome = pacienteData?.full_name || '';
const pacienteCelular = pacienteData?.phone_mobile || '';
const payloadWebhook = {
pacienteId: dadosRelatorio.patient_id,
reportId: novoRelatorio.id,
pacienteNome: pacienteNome,
pacienteCelular: pacienteCelular
};
console.log('[criarRelatorio] Payload do webhook:', payloadWebhook);
const resNotificacao = await fetch('https://joaogustavo.me/webhook/notificar-laudo', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payloadWebhook)
}).catch(e => {
console.warn('[criarRelatorio] Erro de rede ao enviar webhook:', e);
return null;
});
if (resNotificacao?.ok) {
console.log('[criarRelatorio] ✅ Notificação enviada com sucesso ao n8n');
} else if (resNotificacao) {
console.warn('[criarRelatorio] ⚠️ Notificação ao n8n retornou status:', resNotificacao.status);
}
} catch (erroNotificacao) {
console.warn('[criarRelatorio] ❌ Erro ao enviar notificação para n8n:', erroNotificacao);
// Não falha a criação do relatório se a notificação falhar
}
}
return novoRelatorio;
}
throw new Error('Resposta inesperada da API Supabase');
}
@ -384,4 +430,134 @@ export async function listarRelatoriosParaMedicoAtribuido(userId?: string): Prom
console.error('[listarRelatoriosParaMedicoAtribuido] erro:', err);
throw err;
}
}
/**
* Interface para dados necessários ao criar um laudo
*/
export interface CriarLaudoData {
pacienteId: string; // ID do paciente (obrigatório)
textoLaudo: string; // Texto do laudo (obrigatório)
medicoId?: string; // ID do médico que criou (opcional)
exame?: string; // Tipo de exame (opcional)
diagnostico?: string; // Diagnóstico (opcional)
conclusao?: string; // Conclusão (opcional)
cidCode?: string; // Código CID (opcional)
status?: 'rascunho' | 'concluido' | 'enviado'; // Status (opcional, padrão: 'concluido')
contentHtml?: string; // Conteúdo HTML (opcional)
contentJson?: any; // Conteúdo JSON (opcional)
}
/**
* Cria um novo laudo no Supabase e notifica o paciente via n8n
*
* Fluxo:
* 1. Salva o laudo no Supabase (tabela 'reports')
* 2. Envia notificação ao n8n com pacienteId e laudoId
* 3. Retorna o laudo criado
*
* @param laudoData Dados do laudo a criar
* @returns Laudo criado com ID
* @throws Erro se falhar ao criar o laudo
*/
export async function criarLaudo(laudoData: CriarLaudoData): Promise<any> {
try {
// 1. Validação dos dados obrigatórios
if (!laudoData.pacienteId || !laudoData.textoLaudo) {
throw new Error('Paciente ID e Texto do Laudo são obrigatórios');
}
console.log('[criarLaudo] Criando laudo para paciente:', laudoData.pacienteId);
// 2. Monta o payload para Supabase
const payloadSupabase = {
patient_id: laudoData.pacienteId,
...(laudoData.medicoId && { requested_by: laudoData.medicoId }),
...(laudoData.exame && { exam: laudoData.exame }),
...(laudoData.diagnostico && { diagnosis: laudoData.diagnostico }),
...(laudoData.conclusao && { conclusion: laudoData.conclusao }),
...(laudoData.cidCode && { cid_code: laudoData.cidCode }),
...(laudoData.contentHtml && { content_html: laudoData.contentHtml }),
...(laudoData.contentJson && { content_json: laudoData.contentJson }),
status: laudoData.status || 'concluido',
};
// 3. Salva o laudo no Supabase
const urlSupabase = 'https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/reports';
let tokenAuth: string | undefined = undefined;
if (typeof window !== 'undefined') {
tokenAuth =
localStorage.getItem('auth_token') ||
localStorage.getItem('token') ||
sessionStorage.getItem('auth_token') ||
sessionStorage.getItem('token') ||
undefined;
}
const headersSupabase: HeadersInit = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ',
'Prefer': 'return=representation',
};
if (tokenAuth) {
headersSupabase['Authorization'] = `Bearer ${tokenAuth}`;
}
const resSupabase = await fetch(urlSupabase, {
method: 'POST',
headers: headersSupabase,
body: JSON.stringify(payloadSupabase),
});
if (!resSupabase.ok) {
const errorText = await resSupabase.text();
console.error('[criarLaudo] Erro ao salvar laudo no Supabase:', errorText);
throw new Error(`Falha ao salvar laudo: ${resSupabase.statusText}`);
}
const novoLaudo = await resSupabase.json();
const laudoId = novoLaudo?.id;
if (!laudoId) {
throw new Error('Laudo criado mas sem ID retornado');
}
console.log('[criarLaudo] Laudo salvo com sucesso. ID:', laudoId);
// 4. CHAMAR O N8N para notificar o paciente
// Padrão simples: apenas pacienteId e reportId
try {
console.log('[criarLaudo] Enviando notificação para n8n...');
const resNotificacao = await fetch('https://joaogustavo.me/webhook/notificar-laudo', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
pacienteId: laudoData.pacienteId, // ← ID do paciente
reportId: laudoId // ← ID do report criado
})
});
if (resNotificacao.ok) {
console.log('[criarLaudo] Notificação enviada com sucesso ao n8n');
} else {
console.warn('[criarLaudo] Notificação ao n8n retornou status:', resNotificacao.status);
}
} catch (erroNotificacao) {
// Não falha a criação do laudo se a notificação falhar
console.warn('[criarLaudo] Erro ao enviar notificação para n8n:', erroNotificacao);
}
// 5. Retorna o laudo criado
return {
...novoLaudo,
mensagem: 'Laudo criado e paciente notificado com sucesso!',
};
} catch (erro) {
console.error('[criarLaudo] Erro ao criar laudo:', erro);
throw erro;
}
}