diff --git a/susconecta/lib/api.ts b/susconecta/lib/api.ts index cdcf047..b8f34f5 100644 --- a/susconecta/lib/api.ts +++ b/susconecta/lib/api.ts @@ -1,5 +1,11 @@ // lib/api.ts +// Re-exporta as funções e tipos dos módulos específicos +export * from "./api/pacientes"; +export * from "./api/medicos"; + +// Mantenha aqui apenas o código base da API que é compartilhado + export type ApiOk = { success?: boolean; data: T; @@ -175,9 +181,9 @@ export async function atualizarPerfil(id: string | number, input: UserProfileInp // ===== CONFIG ===== -const API_BASE = +export const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? "https://yuanqfswhberkoevtmfr.supabase.co"; -const REST = `${API_BASE}/rest/v1`; +export const REST = `${API_BASE}/rest/v1`; // Token salvo no browser (aceita auth_token ou token) function getAuthToken(): string | null { @@ -191,7 +197,7 @@ function getAuthToken(): string | null { } // Cabeçalhos base -function baseHeaders(): Record { +export function baseHeaders(): Record { const h: Record = { apikey: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ", @@ -203,12 +209,12 @@ function baseHeaders(): Record { } // Para POST/PATCH/DELETE e para GET com count -function withPrefer(h: Record, prefer: string) { +export function withPrefer(h: Record, prefer: string) { return { ...h, Prefer: prefer }; } // Parse genérico -async function parse(res: Response): Promise { +export async function parse(res: Response): Promise { let json: any = null; try { json = await res.json(); @@ -223,139 +229,13 @@ async function parse(res: Response): Promise { } // Helper de paginação (Range/Range-Unit) -function rangeHeaders(page?: number, limit?: number): Record { +export function rangeHeaders(page?: number, limit?: number): Record { if (!page || !limit) return {}; const start = (page - 1) * limit; const end = start + limit - 1; return { Range: `${start}-${end}`, "Range-Unit": "items" }; } -// ===== PACIENTES (CRUD) ===== -export async function listarPacientes(params?: { - page?: number; - limit?: number; - q?: string; -}): Promise { - const qs = new URLSearchParams(); - if (params?.q) qs.set("q", params.q); - - const url = `${REST}/patients${qs.toString() ? `?${qs.toString()}` : ""}`; - const res = await fetch(url, { - method: "GET", - headers: { - ...baseHeaders(), - ...rangeHeaders(params?.page, params?.limit), - }, - }); - return await parse(res); -} - -export async function buscarPacientePorId(id: string | number): Promise { - const url = `${REST}/patients?id=eq.${id}`; - const res = await fetch(url, { method: "GET", headers: baseHeaders() }); - const arr = await parse(res); - if (!arr?.length) throw new Error("404: Paciente não encontrado"); - return arr[0]; -} - -export async function criarPaciente(input: PacienteInput): Promise { - const url = `${REST}/patients`; - const res = await fetch(url, { - method: "POST", - headers: withPrefer({ ...baseHeaders(), "Content-Type": "application/json" }, "return=representation"), - body: JSON.stringify(input), - }); - const arr = await parse(res); - return Array.isArray(arr) ? arr[0] : (arr as Paciente); -} - -export async function atualizarPaciente(id: string | number, input: PacienteInput): Promise { - const url = `${REST}/patients?id=eq.${id}`; - const res = await fetch(url, { - method: "PATCH", - headers: withPrefer({ ...baseHeaders(), "Content-Type": "application/json" }, "return=representation"), - body: JSON.stringify(input), - }); - const arr = await parse(res); - return Array.isArray(arr) ? arr[0] : (arr as Paciente); -} - -export async function excluirPaciente(id: string | number): Promise { - const url = `${REST}/patients?id=eq.${id}`; - const res = await fetch(url, { method: "DELETE", headers: baseHeaders() }); - await parse(res); -} -// ===== PACIENTES (Extra: verificação de CPF duplicado) ===== -export async function verificarCpfDuplicado(cpf: string): Promise { - const clean = (cpf || "").replace(/\D/g, ""); - const url = `${API_BASE}/rest/v1/patients?cpf=eq.${clean}&select=id`; - - const res = await fetch(url, { - method: "GET", - headers: baseHeaders(), - }); - - const data = await res.json().catch(() => []); - return Array.isArray(data) && data.length > 0; -} - - -// ===== MÉDICOS (CRUD) ===== -export async function listarMedicos(params?: { - page?: number; - limit?: number; - q?: string; -}): Promise { - const qs = new URLSearchParams(); - if (params?.q) qs.set("q", params.q); - - const url = `${REST}/doctors${qs.toString() ? `?${qs.toString()}` : ""}`; - const res = await fetch(url, { - method: "GET", - headers: { - ...baseHeaders(), - ...rangeHeaders(params?.page, params?.limit), - }, - }); - return await parse(res); -} - -export async function buscarMedicoPorId(id: string | number): Promise { - const url = `${REST}/doctors?id=eq.${id}`; - const res = await fetch(url, { method: "GET", headers: baseHeaders() }); - const arr = await parse(res); - if (!arr?.length) throw new Error("404: Médico não encontrado"); - return arr[0]; -} - -export async function criarMedico(input: MedicoInput): Promise { - const url = `${REST}/doctors`; - const res = await fetch(url, { - method: "POST", - headers: withPrefer({ ...baseHeaders(), "Content-Type": "application/json" }, "return=representation"), - body: JSON.stringify(input), - }); - const arr = await parse(res); - return Array.isArray(arr) ? arr[0] : (arr as Medico); -} - -export async function atualizarMedico(id: string | number, input: MedicoInput): Promise { - const url = `${REST}/doctors?id=eq.${id}`; - const res = await fetch(url, { - method: "PATCH", - headers: withPrefer({ ...baseHeaders(), "Content-Type": "application/json" }, "return=representation"), - body: JSON.stringify(input), - }); - const arr = await parse(res); - return Array.isArray(arr) ? arr[0] : (arr as Medico); -} - -export async function excluirMedico(id: string | number): Promise { - const url = `${REST}/doctors?id=eq.${id}`; - const res = await fetch(url, { method: "DELETE", headers: baseHeaders() }); - await parse(res); -} - // ===== CEP (usado nos formulários) ===== export async function buscarCepAPI(cep: string): Promise<{ logradouro?: string; @@ -381,14 +261,9 @@ export async function buscarCepAPI(cep: string): Promise<{ } } -// ===== Stubs pra não quebrar imports dos forms (sem rotas de storage na doc) ===== -export async function listarAnexos(_id: string | number): Promise { return []; } -export async function adicionarAnexo(_id: string | number, _file: File): Promise { return {}; } -export async function removerAnexo(_id: string | number, _anexoId: string | number): Promise {} -export async function uploadFotoPaciente(_id: string | number, _file: File): Promise<{ foto_url?: string; thumbnail_url?: string }> { return {}; } -export async function removerFotoPaciente(_id: string | number): Promise {} -export async function listarAnexosMedico(_id: string | number): Promise { return []; } -export async function adicionarAnexoMedico(_id: string | number, _file: File): Promise { return {}; } -export async function removerAnexoMedico(_id: string | number, _anexoId: string | number): Promise {} -export async function uploadFotoMedico(_id: string | number, _file: File): Promise<{ foto_url?: string; thumbnail_url?: string }> { return {}; } -export async function removerFotoMedico(_id: string | number): Promise {} +// Funções de log e outras utilidades podem ser mantidas aqui se necessário +export const logAPI = (name: string, details: any) => { + if (process.env.NODE_ENV === 'development') { + console.log(`[API Call: ${name}]`, details); + } +}; \ No newline at end of file diff --git a/susconecta/lib/api/medicos.ts b/susconecta/lib/api/medicos.ts index 3ae4724..6e14c6d 100644 --- a/susconecta/lib/api/medicos.ts +++ b/susconecta/lib/api/medicos.ts @@ -1 +1,129 @@ -// Arquivo reservado para as APIs de Médicos +// lib/api/medicos.ts +import { REST, baseHeaders, rangeHeaders, withPrefer, parse } from "../api"; + +// ===== TIPOS DE MÉDICOS ===== +export type FormacaoAcademica = { + instituicao: string; + curso: string; + ano_conclusao: string; +}; + +export type DadosBancarios = { + banco: string; + agencia: string; + conta: string; + tipo_conta: string; +}; + +export type Medico = { + id: string; + nome?: string; + nome_social?: string | null; + cpf?: string; + rg?: string | null; + sexo?: string | null; + data_nascimento?: string | null; + telefone?: string; + celular?: string; + contato_emergencia?: string; + email?: string; + crm?: string; + estado_crm?: string; + rqe?: string; + formacao_academica?: FormacaoAcademica[]; + curriculo_url?: string | null; + especialidade?: string; + observacoes?: string | null; + foto_url?: string | null; + tipo_vinculo?: string; + dados_bancarios?: DadosBancarios; + agenda_horario?: string; + valor_consulta?: number | string; +}; + +export type MedicoInput = { + nome: string; + nome_social?: string | null; + cpf?: string | null; + rg?: string | null; + sexo?: string | null; + data_nascimento?: string | null; + telefone?: string | null; + celular?: string | null; + contato_emergencia?: string | null; + email?: string | null; + crm: string; + estado_crm?: string | null; + rqe?: string | null; + formacao_academica?: FormacaoAcademica[]; + curriculo_url?: string | null; + especialidade: string; + observacoes?: string | null; + tipo_vinculo?: string | null; + dados_bancarios?: DadosBancarios | null; + agenda_horario?: string | null; + valor_consulta?: number | string | null; +}; + +// ===== MÉDICOS (CRUD) ===== +export async function listarMedicos(params?: { + page?: number; + limit?: number; + q?: string; +}): Promise { + const qs = new URLSearchParams(); + if (params?.q) qs.set("q", params.q); + + const url = `${REST}/doctors${qs.toString() ? `?${qs.toString()}` : ""}`; + const res = await fetch(url, { + method: "GET", + headers: { + ...baseHeaders(), + ...rangeHeaders(params?.page, params?.limit), + }, + }); + return await parse(res); +} + +export async function buscarMedicoPorId(id: string | number): Promise { + const url = `${REST}/doctors?id=eq.${id}`; + const res = await fetch(url, { method: "GET", headers: baseHeaders() }); + const arr = await parse(res); + if (!arr?.length) throw new Error("404: Médico não encontrado"); + return arr[0]; +} + +export async function criarMedico(input: MedicoInput): Promise { + const url = `${REST}/doctors`; + const res = await fetch(url, { + method: "POST", + headers: withPrefer({ ...baseHeaders(), "Content-Type": "application/json" }, "return=representation"), + body: JSON.stringify(input), + }); + const arr = await parse(res); + return Array.isArray(arr) ? arr[0] : (arr as Medico); +} + +export async function atualizarMedico(id: string | number, input: MedicoInput): Promise { + const url = `${REST}/doctors?id=eq.${id}`; + const res = await fetch(url, { + method: "PATCH", + headers: withPrefer({ ...baseHeaders(), "Content-Type": "application/json" }, "return=representation"), + body: JSON.stringify(input), + }); + const arr = await parse(res); + return Array.isArray(arr) ? arr[0] : (arr as Medico); +} + +export async function excluirMedico(id: string | number): Promise { + const url = `${REST}/doctors?id=eq.${id}`; + const res = await fetch(url, { method: "DELETE", headers: baseHeaders() }); + await parse(res); +} + +// ===== Stubs para upload de arquivos de médico ===== +export async function listarAnexosMedico(_id: string | number): Promise { return []; } +export async function adicionarAnexoMedico(_id: string | number, _file: File): Promise { return {}; } +export async function removerAnexoMedico(_id: string | number, _anexoId: string | number): Promise {} +export async function uploadFotoMedico(_id: string | number, _file: File): Promise<{ foto_url?: string; thumbnail_url?: string }> { return {}; } +export async function removerFotoMedico(_id: string | number): Promise {} \ No newline at end of file diff --git a/susconecta/lib/api/pacientes.ts b/susconecta/lib/api/pacientes.ts index 461e86a..24fc181 100644 --- a/susconecta/lib/api/pacientes.ts +++ b/susconecta/lib/api/pacientes.ts @@ -1 +1,118 @@ -// Arquivo reservado para as APIs de Pacientes +// lib/api/pacientes.ts +import { API_BASE, REST, baseHeaders, rangeHeaders, withPrefer, parse } from "../api"; + +// ===== TIPOS DE PACIENTES ===== +export type Endereco = { + cep?: string; + logradouro?: string; + numero?: string; + complemento?: string; + bairro?: string; + cidade?: string; + estado?: string; +}; + +export type Paciente = { + id: string; + nome?: string; + nome_social?: string | null; + cpf?: string; + rg?: string | null; + sexo?: string | null; + data_nascimento?: string | null; + telefone?: string; + email?: string; + endereco?: Endereco; + observacoes?: string | null; + foto_url?: string | null; +}; + +export type PacienteInput = { + nome: string; + nome_social?: string | null; + cpf: string; + rg?: string | null; + sexo?: string | null; + data_nascimento?: string | null; + telefone?: string | null; + email?: string | null; + endereco?: Endereco; + observacoes?: string | null; +}; + +// ===== PACIENTES (CRUD) ===== +export async function listarPacientes(params?: { + page?: number; + limit?: number; + q?: string; +}): Promise { + const qs = new URLSearchParams(); + if (params?.q) qs.set("q", params.q); + + const url = `${REST}/patients${qs.toString() ? `?${qs.toString()}` : ""}`; + const res = await fetch(url, { + method: "GET", + headers: { + ...baseHeaders(), + ...rangeHeaders(params?.page, params?.limit), + }, + }); + return await parse(res); +} + +export async function buscarPacientePorId(id: string | number): Promise { + const url = `${REST}/patients?id=eq.${id}`; + const res = await fetch(url, { method: "GET", headers: baseHeaders() }); + const arr = await parse(res); + if (!arr?.length) throw new Error("404: Paciente não encontrado"); + return arr[0]; +} + +export async function criarPaciente(input: PacienteInput): Promise { + const url = `${REST}/patients`; + const res = await fetch(url, { + method: "POST", + headers: withPrefer({ ...baseHeaders(), "Content-Type": "application/json" }, "return=representation"), + body: JSON.stringify(input), + }); + const arr = await parse(res); + return Array.isArray(arr) ? arr[0] : (arr as Paciente); +} + +export async function atualizarPaciente(id: string | number, input: PacienteInput): Promise { + const url = `${REST}/patients?id=eq.${id}`; + const res = await fetch(url, { + method: "PATCH", + headers: withPrefer({ ...baseHeaders(), "Content-Type": "application/json" }, "return=representation"), + body: JSON.stringify(input), + }); + const arr = await parse(res); + return Array.isArray(arr) ? arr[0] : (arr as Paciente); +} + +export async function excluirPaciente(id: string | number): Promise { + const url = `${REST}/patients?id=eq.${id}`; + const res = await fetch(url, { method: "DELETE", headers: baseHeaders() }); + await parse(res); +} + +// ===== PACIENTES (Extra: verificação de CPF duplicado) ===== +export async function verificarCpfDuplicado(cpf: string): Promise { + const clean = (cpf || "").replace(/\D/g, ""); + const url = `${API_BASE}/rest/v1/patients?cpf=eq.${clean}&select=id`; + + const res = await fetch(url, { + method: "GET", + headers: baseHeaders(), + }); + + const data = await res.json().catch(() => []); + return Array.isArray(data) && data.length > 0; +} + +// ===== Stubs para upload de arquivos de paciente ===== +export async function listarAnexos(_id: string | number): Promise { return []; } +export async function adicionarAnexo(_id: string | number, _file: File): Promise { return {}; } +export async function removerAnexo(_id: string | number, _anexoId: string | number): Promise {} +export async function uploadFotoPaciente(_id: string | number, _file: File): Promise<{ foto_url?: string; thumbnail_url?: string }> { return {}; } +export async function removerFotoPaciente(_id: string | number): Promise {} \ No newline at end of file