// 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; message?: string; pagination?: { current_page?: number; per_page?: number; total_pages?: number; total?: number; }; }; // ===== TIPOS COMUNS ===== export type Endereco = { cep?: string; logradouro?: string; numero?: string; complemento?: string; bairro?: string; cidade?: string; estado?: string; }; // ===== PACIENTES ===== 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; }; // ===== 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; }; // // Perfis de Usuário (Profiles) // export type UserProfile = { id: string; full_name?: string; email?: string; phone?: string; avatar_url?: string; disabled?: boolean; created_at?: string; updated_at?: string; }; export type UserProfileInput = { full_name?: string; email?: string; phone?: string; avatar_url?: string; disabled?: boolean; }; export async function listarPerfis(params?: { page?: number; limit?: number; q?: string }): Promise { const query = new URLSearchParams(); if (params?.page) query.set("page", String(params.page)); if (params?.limit) query.set("limit", String(params.limit)); if (params?.q) query.set("q", params.q); const url = `${API_BASE}/rest/v1/profiles${query.toString() ? `?${query.toString()}` : ""}`; const res = await fetch(url, { method: "GET", headers: headers("json") }); const data = await parse>(res); logAPI("listarPerfis", { url, result: data }); return data?.data ?? (data as any); } export async function buscarPerfilPorId(id: string | number): Promise { const url = `${API_BASE}/rest/v1/profiles?id=eq.${id}`; const res = await fetch(url, { method: "GET", headers: headers("json") }); // A API da Supabase/PostgREST retorna um array mesmo pedindo um ID, então pegamos o primeiro. const data = await parse(res); const profile = data[0]; logAPI("buscarPerfilPorId", { url, result: profile }); return profile; } export async function atualizarPerfil(id: string | number, input: UserProfileInput): Promise { const url = `${API_BASE}/rest/v1/profiles?id=eq.${id}`; const res = await fetch(url, { method: "PATCH", headers: headers("json"), body: JSON.stringify(input) }); // O método PATCH no PostgREST retorna um array vazio por padrão. Para retornar os dados, precisa de um header `Prefer: return=representation` // Por simplicidade, vamos assumir que se não deu erro, a operação foi um sucesso. // Se a API estiver configurada para retornar o objeto, o parse vai funcionar. const data = await parse>(res); logAPI("atualizarPerfil", { url, payload: input, result: data }); return data?.data ?? (data as any); } // ===== CONFIG ===== export const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? "https://yuanqfswhberkoevtmfr.supabase.co"; export const REST = `${API_BASE}/rest/v1`; // Token salvo no browser (aceita auth_token ou token) function getAuthToken(): string | null { if (typeof window === "undefined") return null; return ( localStorage.getItem("auth_token") || localStorage.getItem("token") || sessionStorage.getItem("auth_token") || sessionStorage.getItem("token") ); } // Cabeçalhos base export function baseHeaders(): Record { const h: Record = { apikey: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inl1YW5xZnN3aGJlcmtvZXZ0bWZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTQ5NTQzNjksImV4cCI6MjA3MDUzMDM2OX0.g8Fm4XAvtX46zifBZnYVH4tVuQkqUH6Ia9CXQj4DztQ", Accept: "application/json", }; const jwt = getAuthToken(); if (jwt) h.Authorization = `Bearer ${jwt}`; return h; } // Para POST/PATCH/DELETE e para GET com count export function withPrefer(h: Record, prefer: string) { return { ...h, Prefer: prefer }; } // Parse genérico export async function parse(res: Response): Promise { let json: any = null; try { json = await res.json(); } catch {} if (!res.ok) { console.error("[API ERROR]", res.url, res.status, json); const code = (json && (json.error?.code || json.code)) ?? res.status; const msg = (json && (json.error?.message || json.message)) ?? res.statusText; throw new Error(`${code}: ${msg}`); } return (json?.data ?? json) as T; } // Helper de paginação (Range/Range-Unit) 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" }; } // ===== CEP (usado nos formulários) ===== export async function buscarCepAPI(cep: string): Promise<{ logradouro?: string; bairro?: string; localidade?: string; uf?: string; erro?: boolean; }> { const clean = (cep || "").replace(/\D/g, ""); try { const res = await fetch(`https://viacep.com.br/ws/${clean}/json/`); const json = await res.json(); if (json?.erro) return { erro: true }; return { logradouro: json.logradouro ?? "", bairro: json.bairro ?? "", localidade: json.localidade ?? "", uf: json.uf ?? "", erro: false, }; } catch { return { erro: true }; } } // 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); } };