diff --git a/susconecta/app/profissional/page.tsx b/susconecta/app/profissional/page.tsx index 65f3fa5..dfe23d6 100644 --- a/susconecta/app/profissional/page.tsx +++ b/susconecta/app/profissional/page.tsx @@ -5,7 +5,9 @@ import SignatureCanvas from "react-signature-canvas"; import Link from "next/link"; import ProtectedRoute from "@/components/ProtectedRoute"; import { useAuth } from "@/hooks/useAuth"; -import { buscarPacientes } from "@/lib/api"; +import { buscarPacientes, listarPacientes, buscarPacientePorId, type Paciente } from "@/lib/api"; +import { useReports } from "@/hooks/useReports"; +import { CreateReportData, ReportFormData } from "@/types/report"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -145,11 +147,20 @@ const ProfissionalPage = () => { prognostico: "", tratamentosRealizados: "", recomendacoes: "", + cid: "", dataRelatorio: new Date().toISOString().split("T")[0], }); const [relatoriosMedicos, setRelatoriosMedicos] = useState([]); const [editandoRelatorio, setEditandoRelatorio] = useState(null); + // Estados para integração com API de Relatórios + const [pacientesReais, setPacientesReais] = useState([]); + const [carregandoPacientes, setCarregandoPacientes] = useState(false); + const [pacienteSelecionadoReport, setPacienteSelecionadoReport] = useState(null); + + // Hook personalizado para relatórios + const reportsApi = useReports(); + // Estados para funcionalidades do prontuário const [consultasRegistradas, setConsultasRegistradas] = useState([]); const [historicoMedico, setHistoricoMedico] = useState([]); @@ -349,7 +360,7 @@ const ProfissionalPage = () => { prognostico: "", tratamentosRealizados: "", recomendacoes: "", - dataRelatorio: new Date().toISOString().split("T")[0], + dataRelatorio: new Date().toISOString().split('T')[0] }); }; @@ -384,10 +395,270 @@ const ProfissionalPage = () => { prognostico: "", tratamentosRealizados: "", recomendacoes: "", - dataRelatorio: new Date().toISOString().split("T")[0], + dataRelatorio: new Date().toISOString().split('T')[0] }); }; + // ===== FUNÇÕES PARA INTEGRAÇÃO COM API DE RELATÓRIOS ===== + + // Carregar pacientes reais do Supabase + const carregarPacientesReais = async () => { + setCarregandoPacientes(true); + try { + console.log('📋 [REPORTS] Carregando pacientes do Supabase...'); + + // Tentar primeiro usando a função da API que já existe + try { + console.log('📋 [REPORTS] Tentando função listarPacientes...'); + const pacientes = await listarPacientes({ limit: 50 }); + console.log('✅ [REPORTS] Pacientes do Supabase via API:', pacientes); + + if (pacientes && pacientes.length > 0) { + setPacientesReais(pacientes); + console.log('✅ [REPORTS] Usando pacientes do Supabase:', pacientes.length); + return; + } + } catch (apiError) { + console.warn('⚠️ [REPORTS] Erro na função listarPacientes:', apiError); + } + + // Se a função da API falhar, tentar diretamente + console.log('📋 [REPORTS] Tentando buscar diretamente do Supabase...'); + const supabaseUrl = 'https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/patients'; + console.log('📋 [REPORTS] URL do Supabase:', supabaseUrl); + + // Verificar se há token de autenticação + const token = localStorage.getItem("auth_token") || localStorage.getItem("token") || + sessionStorage.getItem("auth_token") || sessionStorage.getItem("token"); + + console.log('🔑 [REPORTS] Token encontrado:', token ? 'SIM' : 'NÃO'); + + const headers: Record = { + 'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ', + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }; + + if (token) { + headers['Authorization'] = `Bearer ${token}`; + } + + const response = await fetch(supabaseUrl, { + method: 'GET', + headers + }); + + console.log('📡 [REPORTS] Status da resposta do Supabase:', response.status, response.statusText); + + if (!response.ok) { + const errorText = await response.text(); + console.error('❌ [REPORTS] Erro detalhado do Supabase:', errorText); + throw new Error(`Supabase HTTP ${response.status}: ${response.statusText} - ${errorText}`); + } + + const data = await response.json(); + console.log('✅ [REPORTS] Resposta completa do Supabase:', data); + console.log('✅ [REPORTS] Tipo da resposta:', Array.isArray(data) ? 'Array' : typeof data); + + let pacientes: Paciente[] = []; + + if (Array.isArray(data)) { + pacientes = data; + } else if (data.data && Array.isArray(data.data)) { + pacientes = data.data; + } else { + console.warn('⚠️ [REPORTS] Formato de resposta inesperado do Supabase:', data); + pacientes = []; + } + + console.log('✅ [REPORTS] Pacientes encontrados no Supabase:', pacientes.length); + if (pacientes.length > 0) { + console.log('✅ [REPORTS] Primeiro paciente:', pacientes[0]); + console.log('✅ [REPORTS] Últimos 3 pacientes:', pacientes.slice(-3)); + } + + setPacientesReais(pacientes); + + if (pacientes.length === 0) { + console.warn('⚠️ [REPORTS] Nenhum paciente encontrado no Supabase - verifique se há dados na tabela patients'); + } + } catch (error) { + console.error('❌ [REPORTS] Erro detalhado ao carregar pacientes:', { + error, + message: error instanceof Error ? error.message : String(error), + stack: error instanceof Error ? error.stack : undefined + }); + + setPacientesReais([]); + alert('Erro ao carregar pacientes do Supabase: ' + (error instanceof Error ? error.message : String(error))); + } finally { + setCarregandoPacientes(false); + } + }; + + // Calcular idade do paciente baseado na data de nascimento + const calcularIdade = (birthDate: string | null | undefined): string => { + if (!birthDate) return ''; + + const hoje = new Date(); + const nascimento = new Date(birthDate); + let idade = hoje.getFullYear() - nascimento.getFullYear(); + const mesAtual = hoje.getMonth(); + const mesNascimento = nascimento.getMonth(); + + if (mesAtual < mesNascimento || (mesAtual === mesNascimento && hoje.getDate() < nascimento.getDate())) { + idade--; + } + + return idade.toString(); + }; + + // Selecionar paciente para o relatório + const selecionarPacienteParaRelatorio = (paciente: Paciente) => { + setPacienteSelecionadoReport(paciente); + + // Atualizar o formulário de relatório com dados do paciente + setRelatorioMedico(prev => ({ + ...prev, + pacienteNome: paciente.full_name, + pacienteCpf: paciente.cpf || '', + pacienteIdade: calcularIdade(paciente.birth_date), + })); + + console.log('👤 [REPORTS] Paciente selecionado:', paciente); + }; + + // Salvar relatório usando a API + const salvarRelatorioAPI = async () => { + if (!pacienteSelecionadoReport) { + alert('Por favor, selecione um paciente.'); + return; + } + + if (!relatorioMedico.motivoRelatorio.trim()) { + alert('Por favor, preencha o motivo do relatório.'); + return; + } + + try { + console.log('💾 [REPORTS] Salvando relatório...'); + + // Dados para enviar à API + const reportData: CreateReportData = { + patient_id: pacienteSelecionadoReport.id, + doctor_id: user?.id || 'temp-doctor-id', // Usar ID do usuário logado + report_type: 'Relatório Médico', + chief_complaint: relatorioMedico.motivoRelatorio, + clinical_history: relatorioMedico.historicoClinico, + symptoms_and_signs: relatorioMedico.sinaisSintomas, + physical_examination: '', // Pode adicionar campo no formulário se necessário + complementary_exams: relatorioMedico.examesRealizados, + exam_results: relatorioMedico.resultadosExames, + diagnosis: relatorioMedico.diagnosticos, + prognosis: relatorioMedico.prognostico, + treatment_performed: relatorioMedico.tratamentosRealizados, + objective_recommendations: relatorioMedico.recomendacoes || '', + icd_code: relatorioMedico.cid, + report_date: relatorioMedico.dataRelatorio, + }; + + const novoRelatorio = await reportsApi.createNewReport(reportData); + + console.log('✅ [REPORTS] Relatório salvo com sucesso:', novoRelatorio); + + // Recarregar a lista de relatórios para garantir que está sincronizada + await reportsApi.loadReports(); + + alert('Relatório médico salvo com sucesso!'); + + // Limpar formulário + limparFormularioRelatorio(); + + } catch (error) { + console.error('❌ [REPORTS] Erro ao salvar relatório:', error); + alert('Erro ao salvar relatório: ' + error); + } + }; + + // Limpar formulário de relatório + const limparFormularioRelatorio = () => { + setRelatorioMedico({ + pacienteNome: "", + pacienteCpf: "", + pacienteIdade: "", + profissionalNome: medico.nome, + profissionalCrm: medico.identificacao, + motivoRelatorio: "", + historicoClinico: "", + sinaisSintomas: "", + examesRealizados: "", + resultadosExames: "", + diagnosticos: "", + prognostico: "", + tratamentosRealizados: "", + recomendacoes: "", + cid: "", + dataRelatorio: new Date().toISOString().split('T')[0] + }); + setPacienteSelecionadoReport(null); + }; + + // Carregar relatórios existentes + const carregarRelatorios = async () => { + try { + await reportsApi.loadReports(); + console.log('✅ [REPORTS] Relatórios carregados:', reportsApi.reports.length); + } catch (error) { + console.error('❌ [REPORTS] Erro ao carregar relatórios:', error); + } + }; + + + // useEffect para carregar dados iniciais + useEffect(() => { + if (activeSection === 'relatorios-medicos') { + console.log('🔄 [REPORTS] Seção de relatórios ativada - carregando dados...'); + carregarPacientesReais(); + carregarRelatorios(); + } + }, [activeSection]); + + // Buscar pacientes faltantes por patient_id após carregar relatórios e pacientes + useEffect(() => { + if (activeSection !== 'relatorios-medicos') return; + if (!reportsApi.reports || reportsApi.reports.length === 0) return; + + // IDs de pacientes já carregados + const idsPacientesReais = new Set(pacientesReais.map(p => String(p.id))); + // IDs de pacientes presentes nos relatórios + const idsRelatorios = Array.from(new Set(reportsApi.reports.map(r => String(r.patient_id)).filter(Boolean))); + // IDs que faltam + const idsFaltantes = idsRelatorios.filter(id => !idsPacientesReais.has(id)); + + if (idsFaltantes.length === 0) return; + + // Buscar pacientes faltantes individualmente, apenas se o ID for string/UUID + (async () => { + const novosPacientes: Paciente[] = []; + for (const id of idsFaltantes) { + // Só busca se for string e não for número + if (typeof id === 'string' && isNaN(Number(id))) { + try { + const paciente = await buscarPacientePorId(id); + if (paciente) novosPacientes.push(paciente); + } catch (e) { + console.warn('⚠️ [REPORTS] Paciente não encontrado para o relatório:', id); + } + } else { + console.warn('⚠️ [REPORTS] Ignorando busca de paciente por ID não-string/UUID:', id); + } + } + if (novosPacientes.length > 0) { + setPacientesReais(prev => ([...prev, ...novosPacientes])); + } + })(); + }, [activeSection, reportsApi.reports, pacientesReais]); + const handleDateClick = (argument: any) => { setSelectedDate(argument.dateStr); setNewEvent({ title: "", type: "", time: "", pacienteId: "" }); @@ -3812,42 +4083,38 @@ Nevo melanocítico benigno. Seguimento clínico recomendado. - {/* Identificação do Paciente */} + {/* Identificação do Paciente - USANDO API REAL */}
-

- Identificação do Paciente -

+

Identificação do Paciente

@@ -3856,9 +4123,7 @@ Nevo melanocítico benigno. Seguimento clínico recomendado. - handleRelatorioChange("pacienteCpf", e.target.value) - } + onChange={(e) => handleRelatorioChange('pacienteCpf', e.target.value)} placeholder="000.000.000-00" />
@@ -3866,22 +4131,39 @@ Nevo melanocítico benigno. Seguimento clínico recomendado. - handleRelatorioChange("pacienteIdade", e.target.value) - } + onChange={(e) => handleRelatorioChange('pacienteIdade', e.target.value)} placeholder="Idade do paciente" />
+ + {/* Informações adicionais do paciente selecionado */} + {pacienteSelecionadoReport && ( +
+
Informações do Paciente Selecionado:
+
+
+ Nome Completo:
+ {pacienteSelecionadoReport.full_name} +
+
+ Email:
+ {pacienteSelecionadoReport.email || 'Não informado'} +
+
+ Telefone:
+ {pacienteSelecionadoReport.phone_mobile || 'Não informado'} +
+
+
+ )} {/* Informações do Relatório */}
-

- Informações do Relatório -

+

Informações do Relatório

@@ -3895,6 +4177,15 @@ Nevo melanocítico benigno. Seguimento clínico recomendado. rows={3} />
+
+ + handleRelatorioChange('cid', e.target.value)} + placeholder="Ex: A00, B20, C34..." + /> +
- +
- {/* Lista de Relatórios Existentes */} + {/* Lista de Relatórios da API */}
-

- Relatórios Médicos Salvos -

- +

Relatórios Médicos Salvos

+ {relatoriosMedicos.length === 0 ? (
@@ -4080,44 +4366,31 @@ Nevo melanocítico benigno. Seguimento clínico recomendado. ) : (
{relatoriosMedicos.map((relatorio) => ( -
+
-

- {relatorio.pacienteNome} -

-

- CPF: {relatorio.pacienteCpf} • Idade:{" "} - {relatorio.pacienteIdade} anos -

-

- Data do relatório:{" "} - {new Date(relatorio.dataRelatorio).toLocaleDateString( - "pt-BR", - )} -

-

- Gerado em: {relatorio.dataGeracao} -

+

{relatorio.pacienteNome}

+

CPF: {relatorio.pacienteCpf} • Idade: {relatorio.pacienteIdade} anos

+

Data do relatório: {new Date(relatorio.dataRelatorio).toLocaleDateString('pt-BR')}

+

Gerado em: {relatorio.dataGeracao}

- ))} + ); + })}
)}
diff --git a/susconecta/hooks/useReports.ts b/susconecta/hooks/useReports.ts new file mode 100644 index 0000000..6dcbc2c --- /dev/null +++ b/susconecta/hooks/useReports.ts @@ -0,0 +1,219 @@ +// hooks/useReports.ts + +import { useState, useEffect, useCallback } from 'react'; +import { + Report, + CreateReportData, + UpdateReportData, + ApiError +} from '@/types/report-types'; +import { + listarRelatorios, + buscarRelatorioPorId, + criarRelatorio, + atualizarRelatorio, + deletarRelatorio, + listarRelatoriosPorPaciente, + listarRelatoriosPorMedico +} from '@/lib/reports'; + +interface UseReportsReturn { + // Estados + reports: Report[]; + selectedReport: Report | null; + loading: boolean; + error: string | null; + + // Ações + loadReports: () => Promise; + loadReportById: (id: string) => Promise; + createNewReport: (data: CreateReportData) => Promise; + updateExistingReport: (id: string, data: UpdateReportData) => Promise; + deleteExistingReport: (id: string) => Promise; + loadReportsByPatient: (patientId: string) => Promise; + loadReportsByDoctor: (doctorId: string) => Promise; + clearError: () => void; + clearSelectedReport: () => void; +} + +export function useReports(): UseReportsReturn { + // Estados + const [reports, setReports] = useState([]); + const [selectedReport, setSelectedReport] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + // Função para tratar erros + const handleError = useCallback((error: any) => { + console.error('❌ [useReports] Erro:', error); + + if (error && typeof error === 'object' && 'message' in error) { + setError(error.message); + } else if (typeof error === 'string') { + setError(error); + } else { + setError('Ocorreu um erro inesperado'); + } + }, []); + + // Carregar todos os relatórios + const loadReports = useCallback(async () => { + setLoading(true); + setError(null); + + try { + const data = await listarRelatorios(); + setReports(data); + } catch (err) { + handleError(err); + } finally { + setLoading(false); + } + }, [handleError]); + + // Carregar um relatório específico + const loadReportById = useCallback(async (id: string) => { + setLoading(true); + setError(null); + + try { + const report = await buscarRelatorioPorId(id); + setSelectedReport(report); + } catch (err) { + handleError(err); + } finally { + setLoading(false); + } + }, [handleError]); + + // Criar novo relatório + const createNewReport = useCallback(async (data: CreateReportData): Promise => { + setLoading(true); + setError(null); + + try { + const newReport = await criarRelatorio(data); + + // Adicionar o novo relatório à lista + setReports(prev => [newReport, ...prev]); + + return newReport; + } catch (err) { + handleError(err); + throw err; + } finally { + setLoading(false); + } + }, [handleError]); + + // Atualizar relatório existente + const updateExistingReport = useCallback(async (id: string, data: UpdateReportData): Promise => { + setLoading(true); + setError(null); + + try { + const updatedReport = await atualizarRelatorio(id, data); + + // Atualizar na lista + setReports(prev => + prev.map(report => + report.id === id ? updatedReport : report + ) + ); + + // Atualizar o selecionado se for o mesmo + if (selectedReport?.id === id) { + setSelectedReport(updatedReport); + } + + return updatedReport; + } catch (err) { + handleError(err); + throw err; + } finally { + setLoading(false); + } + }, [handleError, selectedReport]); + + // Deletar relatório + const deleteExistingReport = useCallback(async (id: string): Promise => { + setLoading(true); + setError(null); + + try { + await deletarRelatorio(id); + + // Remover da lista + setReports(prev => prev.filter(report => report.id !== id)); + + // Limpar seleção se for o mesmo + if (selectedReport?.id === id) { + setSelectedReport(null); + } + } catch (err) { + handleError(err); + throw err; + } finally { + setLoading(false); + } + }, [handleError, selectedReport]); + + // Carregar relatórios por paciente + const loadReportsByPatient = useCallback(async (patientId: string) => { + setLoading(true); + setError(null); + + try { + const data = await listarRelatoriosPorPaciente(patientId); + setReports(data); + } catch (err) { + handleError(err); + } finally { + setLoading(false); + } + }, [handleError]); + + // Carregar relatórios por médico + const loadReportsByDoctor = useCallback(async (doctorId: string) => { + setLoading(true); + setError(null); + + try { + const data = await listarRelatoriosPorMedico(doctorId); + setReports(data); + } catch (err) { + handleError(err); + } finally { + setLoading(false); + } + }, [handleError]); + + // Limpar erro + const clearError = useCallback(() => { + setError(null); + }, []); + + // Limpar relatório selecionado + const clearSelectedReport = useCallback(() => { + setSelectedReport(null); + }, []); + + return { + // Estados + reports, + selectedReport, + loading, + error, + + // Ações + loadReports, + loadReportById, + createNewReport, + updateExistingReport, + deleteExistingReport, + loadReportsByPatient, + loadReportsByDoctor, + clearError, + clearSelectedReport, + }; +} \ No newline at end of file diff --git a/susconecta/lib/report.ts b/susconecta/lib/report.ts deleted file mode 100644 index e69de29..0000000 diff --git a/susconecta/lib/reports.ts b/susconecta/lib/reports.ts new file mode 100644 index 0000000..fcde57e --- /dev/null +++ b/susconecta/lib/reports.ts @@ -0,0 +1,289 @@ +/** + * Atualiza um relatório existente (edição) + * @param id ID do relatório a ser atualizado + * @param dados Dados a serem atualizados no relatório + */ +export async function editarRelatorio(id: string, dados: Partial<{ + patient_id: string; + order_number: string; + exam: string; + diagnosis: string; + conclusion: string; + cid_code: string; + content_html: string; + content_json: any; + status: string; + requested_by: string; + due_at: string; + hide_date: boolean; + hide_signature: boolean; +}>): Promise { + const url = `${BASE_API_RELATORIOS}/${id}`; + const cabecalhos: HeadersInit = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ', + }; + if (typeof window !== 'undefined') { + const token = localStorage.getItem('token'); + if (token) { + cabecalhos['Authorization'] = `Bearer ${token}`; + } + } + const resposta = await fetch(url, { + method: 'PATCH', + headers: cabecalhos, + body: JSON.stringify(dados), + }); + if (!resposta.ok) throw new Error('Erro ao atualizar relatório'); + return resposta.json(); +} +// services/reports.ts + +import { + Report, + CreateReportData, + UpdateReportData, + ReportsResponse, + ReportResponse, + ApiError +} from '@/types/report-types'; + +// URL base da API Mock +const BASE_API_RELATORIOS = 'https://mock.apidog.com/m1/1053378-0-default/rest/v1/reports'; + +// Cabeçalhos base para as requisições +function obterCabecalhos(): HeadersInit { + const cabecalhos: HeadersInit = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ', + }; + + // Adiciona token de autenticação do localStorage se disponível + if (typeof window !== 'undefined') { + const token = localStorage.getItem('token'); + if (token) { + cabecalhos['Authorization'] = `Bearer ${token}`; + } + } + + return cabecalhos; +} + +// Função para tratar erros da API +async function tratarRespostaApi(resposta: Response): Promise { + if (!resposta.ok) { + let mensagemErro = `HTTP ${resposta.status}: ${resposta.statusText}`; + try { + const dadosErro = await resposta.json(); + mensagemErro = dadosErro.message || dadosErro.error || mensagemErro; + } catch (e) { + // Se não conseguir parsear como JSON, usa a mensagem de status HTTP + } + const erro: ApiError = { + message: mensagemErro, + code: resposta.status.toString(), + }; + throw erro; + } + const dados = await resposta.json(); + return dados; +} + +// ===== SERVIÇOS DE RELATÓRIOS MÉDICOS ===== + +/** + * Lista relatórios médicos com filtros opcionais (patient_id, status) + */ +export async function listarRelatorios(filtros?: { patient_id?: string; status?: string }): Promise { + // Monta query string se houver filtros + let url = BASE_API_RELATORIOS; + if (filtros && (filtros.patient_id || filtros.status)) { + const params = new URLSearchParams(); + if (filtros.patient_id) params.append('patient_id', filtros.patient_id); + if (filtros.status) params.append('status', filtros.status); + url += `?${params.toString()}`; + } + + // Monta cabeçalhos conforme cURL + const cabecalhos: HeadersInit = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'apikey': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ', + }; + if (typeof window !== 'undefined') { + const token = localStorage.getItem('token'); + if (token) { + cabecalhos['Authorization'] = `Bearer ${token}`; + } + } + + const resposta = await fetch(url, { + method: 'GET', + headers: cabecalhos, + }); + if (!resposta.ok) throw new Error('Erro ao buscar relatórios'); + const dados = await resposta.json(); + if (Array.isArray(dados)) return dados; + if (dados && Array.isArray(dados.data)) return dados.data; + for (const chave in dados) { + if (Array.isArray(dados[chave])) return dados[chave]; + } + return []; +} + +/** + * Busca um relatório específico por ID + */ +export async function buscarRelatorioPorId(id: string): Promise { + try { + console.log('🔍 [API RELATÓRIOS] Buscando relatório ID:', id); + const resposta = await fetch(`${BASE_API_RELATORIOS}/${id}`, { + method: 'GET', + headers: obterCabecalhos(), + }); + const resultado = await tratarRespostaApi(resposta); + console.log('✅ [API RELATÓRIOS] Relatório encontrado:', resultado.data); + return resultado.data; + } catch (erro) { + console.error('❌ [API RELATÓRIOS] Erro ao buscar relatório:', erro); + throw erro; + } +} + +/** + * Cria um novo relatório médico + */ +export async function criarRelatorio(dadosRelatorio: CreateReportData): Promise { + try { + console.log('📝 [API RELATÓRIOS] Criando novo relatório...'); + console.log('📤 [API RELATÓRIOS] Dados enviados:', dadosRelatorio); + const resposta = await fetch(BASE_API_RELATORIOS, { + method: 'POST', + headers: obterCabecalhos(), + body: JSON.stringify(dadosRelatorio), + }); + console.log('📝 [API RELATÓRIOS] Status da criação:', resposta.status); + console.log('📝 [API RELATÓRIOS] Response OK:', resposta.ok); + console.log('📝 [API RELATÓRIOS] Response URL:', resposta.url); + if (!resposta.ok) { + let mensagemErro = `HTTP ${resposta.status}: ${resposta.statusText}`; + try { + const dadosErro = await resposta.json(); + mensagemErro = dadosErro.message || dadosErro.error || mensagemErro; + console.log('📝 [API RELATÓRIOS] Erro da API:', dadosErro); + } catch (e) { + console.log('📝 [API RELATÓRIOS] Não foi possível parsear erro como JSON'); + } + const erro: ApiError = { + message: mensagemErro, + code: resposta.status.toString(), + }; + throw erro; + } + const resultadoBruto = await resposta.json(); + console.log('📝 [API RELATÓRIOS] Resposta bruta da criação:', resultadoBruto); + console.log('📝 [API RELATÓRIOS] Tipo da resposta:', typeof resultadoBruto); + console.log('📝 [API RELATÓRIOS] Chaves da resposta:', Object.keys(resultadoBruto || {})); + let relatorioCriado: Report; + // Verifica formato da resposta similar ao listarRelatorios + if (resultadoBruto && resultadoBruto.data) { + relatorioCriado = resultadoBruto.data; + } else if (resultadoBruto && resultadoBruto.id) { + relatorioCriado = resultadoBruto; + } else if (Array.isArray(resultadoBruto) && resultadoBruto.length > 0) { + relatorioCriado = resultadoBruto[0]; + } else { + console.warn('📝 [API RELATÓRIOS] Formato de resposta inesperado, criando relatório local'); + relatorioCriado = { + id: 'local-' + Date.now() + '-' + Math.random().toString(36).substr(2, 5), + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + ...dadosRelatorio + }; + } + console.log('✅ [API RELATÓRIOS] Relatório processado:', relatorioCriado); + return relatorioCriado; + } catch (erro) { + console.error('❌ [API RELATÓRIOS] Erro ao criar relatório:', erro); + throw erro; + } +} + +/** + * Atualiza um relatório existente + */ +export async function atualizarRelatorio(id: string, dadosRelatorio: UpdateReportData): Promise { + try { + console.log('📝 [API RELATÓRIOS] Atualizando relatório ID:', id); + console.log('📤 [API RELATÓRIOS] Dados:', dadosRelatorio); + const resposta = await fetch(`${BASE_API_RELATORIOS}/${id}`, { + method: 'PATCH', + headers: obterCabecalhos(), + body: JSON.stringify(dadosRelatorio), + }); + const resultado = await tratarRespostaApi(resposta); + console.log('✅ [API RELATÓRIOS] Relatório atualizado:', resultado.data); + return resultado.data; + } catch (erro) { + console.error('❌ [API RELATÓRIOS] Erro ao atualizar relatório:', erro); + throw erro; + } +} + +/** + * Deleta um relatório + */ +export async function deletarRelatorio(id: string): Promise { + try { + console.log('🗑️ [API RELATÓRIOS] Deletando relatório ID:', id); + const resposta = await fetch(`${BASE_API_RELATORIOS}/${id}`, { + method: 'DELETE', + headers: obterCabecalhos(), + }); + await tratarRespostaApi(resposta); + console.log('✅ [API RELATÓRIOS] Relatório deletado com sucesso'); + } catch (erro) { + console.error('❌ [API RELATÓRIOS] Erro ao deletar relatório:', erro); + throw erro; + } +} + +/** + * Lista relatórios de um paciente específico + */ +export async function listarRelatoriosPorPaciente(idPaciente: string): Promise { + try { + console.log('👤 [API RELATÓRIOS] Buscando relatórios do paciente:', idPaciente); + const resposta = await fetch(`${BASE_API_RELATORIOS}?patient_id=${idPaciente}`, { + method: 'GET', + headers: obterCabecalhos(), + }); + const resultado = await tratarRespostaApi(resposta); + console.log('✅ [API RELATÓRIOS] Relatórios do paciente encontrados:', resultado.data?.length || 0); + return resultado.data || []; + } catch (erro) { + console.error('❌ [API RELATÓRIOS] Erro ao buscar relatórios do paciente:', erro); + throw erro; + } +} + +/** + * Lista relatórios de um médico específico + */ +export async function listarRelatoriosPorMedico(idMedico: string): Promise { + try { + console.log('👨‍⚕️ [API RELATÓRIOS] Buscando relatórios do médico:', idMedico); + const resposta = await fetch(`${BASE_API_RELATORIOS}?doctor_id=${idMedico}`, { + method: 'GET', + headers: obterCabecalhos(), + }); + const resultado = await tratarRespostaApi(resposta); + console.log('✅ [API RELATÓRIOS] Relatórios do médico encontrados:', resultado.data?.length || 0); + return resultado.data || []; + } catch (erro) { + console.error('❌ [API RELATÓRIOS] Erro ao buscar relatórios do médico:', erro); + throw erro; + } +} \ No newline at end of file diff --git a/susconecta/types/report-types.ts b/susconecta/types/report-types.ts new file mode 100644 index 0000000..ae1de48 --- /dev/null +++ b/susconecta/types/report-types.ts @@ -0,0 +1,107 @@ +// Tipo de erro padrão para respostas de API +export interface ApiError { + message: string; + code?: string; +} +// Este arquivo foi renomeado de report.ts para report-types.ts para evitar confusão com outros arquivos de lógica. +// Tipos para o endpoint de Relatórios Médicos +export interface Report { + id: string; + patient_id: string; + doctor_id: string; + report_type: string; + chief_complaint: string; + clinical_history: string; + symptoms_and_signs: string; + physical_examination: string; + complementary_exams: string; + exam_results: string; + diagnosis: string; + prognosis?: string; + treatment_performed: string; + objective_recommendations: string; + icd_code?: string; + report_date: string; + created_at: string; + updated_at: string; + + // Dados expandidos (quando incluir dados relacionados) + patient?: { + id: string; + full_name: string; + cpf?: string; + birth_date?: string; + }; + + doctor?: { + id: string; + full_name: string; + crm?: string; + specialty?: string; + }; +} + +// Dados para criar um novo relatório +export interface CreateReportData { + patient_id: string; + doctor_id: string; + report_type: string; + chief_complaint: string; + clinical_history: string; + symptoms_and_signs: string; + physical_examination: string; + complementary_exams: string; + exam_results: string; + diagnosis: string; + prognosis?: string; + treatment_performed: string; + objective_recommendations: string; + icd_code?: string; + report_date: string; +} + +// Dados para atualizar um relatório existente +export interface UpdateReportData extends Partial { + updated_at?: string; +} + +// Resposta da API ao listar relatórios +export interface ReportsResponse { + data: Report[]; + success: boolean; + message?: string; +} + +// Resposta da API ao criar/atualizar um relatório +export interface ReportResponse { + data: Report; + success: boolean; + message?: string; +} + +// Dados do formulário (adaptado para a estrutura do front-end existente) +export interface ReportFormData { + // Identificação do Profissional + profissionalNome: string; + profissionalCrm: string; + + // Identificação do Paciente + pacienteId: string; + pacienteNome: string; + pacienteCpf: string; + pacienteIdade: string; + + // Informações do Relatório + motivoRelatorio: string; + cid?: string; + dataRelatorio: string; + + // Histórico Clínico + historicoClinico: string; + + // Sinais, Sintomas e Exames + sinaisSintomas: string; + examesRealizados: string; + resultadosExames: string; + // ...restante do código... +