/** * API Client para Edge Functions * Centraliza todas as chamadas para as Edge Functions do Supabase */ import axios from "axios"; import { API_CONFIG } from "./config"; const FUNCTIONS_BASE_URL = `${API_CONFIG.SUPABASE_URL}/functions/v1`; // Pegar token de autenticação function getAuthToken(): string | null { return localStorage.getItem(API_CONFIG.STORAGE_KEYS.ACCESS_TOKEN); } // Cliente configurado para Edge Functions const functionsClient = axios.create({ baseURL: FUNCTIONS_BASE_URL, headers: { "Content-Type": "application/json", apikey: API_CONFIG.SUPABASE_ANON_KEY, }, }); // Interceptor para adicionar token de auth functionsClient.interceptors.request.use((config) => { const token = getAuthToken(); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // Interceptor para tratar erros functionsClient.interceptors.response.use( (response) => response, (error) => { console.error( "[EdgeFunctions] Error:", error.response?.data || error.message ); return Promise.reject(error); } ); /** * Edge Functions API */ export const edgeFunctions = { // ============ USER ============ user: { info: () => functionsClient.get("/user-info"), updatePreferences: (data: { dark_mode?: boolean; high_contrast?: boolean; font_size?: string; dyslexia_font?: boolean; language?: string; }) => functionsClient.post("/user-update-preferences", data), }, // ============ AVAILABILITY ============ availability: { list: (params?: { external_doctor_id?: string; day_of_week?: number }) => functionsClient.get("/availability-list", { params }), create: (data: { external_doctor_id: string; day_of_week: number; start_time: string; end_time: string; slots_per_hour?: number; }) => functionsClient.post("/availability-create", data), update: (data: { id: string; start_time?: string; end_time?: string; slots_per_hour?: number; active?: boolean; }) => functionsClient.post("/availability-update", data), delete: (data: { id: string }) => functionsClient.post("/availability-delete", data), slots: (data: { external_doctor_id: string; date: string }) => functionsClient.post("/availability-slots", data), }, // ============ EXCEPTIONS ============ exceptions: { list: (params?: { external_doctor_id?: string; date_from?: string; date_to?: string; }) => functionsClient.get("/exceptions-list", { params }), create: (data: { external_doctor_id: string; exception_date: string; reason?: string; all_day?: boolean; }) => functionsClient.post("/exceptions-create", data), delete: (data: { id: string }) => functionsClient.post("/exceptions-delete", data), }, // ============ APPOINTMENTS ============ appointments: { list: (params?: { patient_id?: string; doctor_id?: string; status?: string; }) => functionsClient.get("/appointments", { params }), create: (data: { doctor_id: string; patient_id: string; appointment_date: string; appointment_time: string; duration_minutes?: number; type?: string; }) => functionsClient.post("/appointments-create", data), update: (data: { appointment_id: string; appointment_date?: string; appointment_time?: string; duration_minutes?: number; type?: string; status?: string; }) => functionsClient.post("/appointments-update", data), cancel: (data: { appointment_id: string; reason?: string }) => functionsClient.post("/appointments-cancel", data), suggestSlot: (data: { patient_id: string; doctor_id: string; preferred_dates?: string[]; preferred_times?: string[]; }) => functionsClient.post("/appointments-suggest-slot", data), reschedule: (data: { appointment_id: string; new_datetime: string; reason?: string; }) => functionsClient.post("/appointments-reschedule", data), confirm: (data: { token: string }) => functionsClient.post("/appointments-confirm", data), checkin: (data: { appointment_id: string; check_in_method: "manual" | "qr_code" | "nfc" | "app" | "kiosk"; }) => functionsClient.post("/appointments-checkin", data), markNoShow: (data: { appointment_id: string; reason?: string; automatic_detection?: boolean; }) => functionsClient.post("/appointments-no-show", data), }, // ============ WAITLIST ============ waitlist: { add: (data: { patient_id: string; doctor_id: string; desired_date?: string; desired_time?: string; }) => functionsClient.post("/waitlist", data), list: (params?: { doctor_id?: string; patient_id?: string; status?: string; }) => functionsClient.get("/waitlist", { params }), match: (data: { external_doctor_id: string; appointment_date: string; appointment_time: string; }) => functionsClient.post("/waitlist-match", data), remove: (data: { id: string }) => functionsClient.post("/waitlist-remove", data), }, // ============ VIRTUAL QUEUE ============ virtualQueue: { list: (doctorId: string) => functionsClient.get(`/virtual-queue/${doctorId}`), advance: (data: { doctor_id: string; completed: boolean; duration_minutes?: number; notes?: string; }) => functionsClient.post("/virtual-queue-advance", data), checkin: (data: { external_patient_id: string; external_doctor_id?: string; external_appointment_id: string; }) => functionsClient.post("/queue-checkin", data), }, // ============ NOTIFICATIONS ============ notifications: { send: (data: { type: "sms" | "email" | "whatsapp" | "push"; recipient_id: string; template?: string; data?: Record; scheduled_at?: string; }) => functionsClient.post("/notifications-send", data), confirm: (data: { notification_id: string; read_at?: string }) => functionsClient.post("/notifications-confirm", data), subscription: (data: { external_user_id: string; channel: "sms" | "email" | "whatsapp"; enabled: boolean; }) => functionsClient.post("/notifications-subscription", data), }, // ============ ANALYTICS ============ analytics: { summary: (params?: { start_date?: string; end_date?: string }) => functionsClient.get("/analytics", { params }), heatmap: (data: { doctor_id?: string; date_from?: string; date_to?: string; }) => functionsClient.post("/analytics-heatmap", data), demandCurve: (data: { days?: number }) => functionsClient.post("/analytics-demand-curve", data), rankingReasons: () => functionsClient.get("/analytics-ranking-reasons"), monthlyNoShow: (data: { months?: number }) => functionsClient.post("/analytics-monthly-no-show", data), specialtyHeatmap: () => functionsClient.get("/analytics-specialty-heatmap"), customReport: (data: { metrics: string[]; date_from?: string; date_to?: string; filters?: Record; }) => functionsClient.post("/analytics-custom-report", data), }, // ============ TELECONSULT ============ teleconsult: { start: (data: { appointment_id: string; provider?: string }) => functionsClient.post("/teleconsult-start", data), status: (sessionId: string) => functionsClient.get(`/teleconsult-status/${sessionId}`), end: (data: { session_id: string; duration_minutes?: number; recording_url?: string; }) => functionsClient.post("/teleconsult-end", data), }, // ============ GAMIFICATION ============ gamification: { doctorBadges: (doctorId: string) => functionsClient.get(`/gamification-doctor-badges/${doctorId}`), patientStreak: (patientId: string) => functionsClient.get(`/gamification-patient-streak/${patientId}`), addPoints: (data: { user_id: string; points: number; reason: string; category?: string; }) => functionsClient.post("/gamification-add-points", data), }, // ============ USER SYNC ============ userSync: { sync: (data: { external_user_id: string; external_email: string; external_name?: string; external_role?: string; }) => functionsClient.post("/user-sync", data), }, // ============ REPORTS ============ reports: { export: (data: { report_type: string; format: "csv" | "pdf" | "json" | "xlsx"; filters?: Record; }) => functionsClient.post("/reports-export", data), listExtended: (data: { patient_id?: string; doctor_id?: string; date_from?: string; date_to?: string; }) => functionsClient.post("/reports-list-extended", data), exportCsv: (data: { patient_id?: string; date_from?: string; date_to?: string; }) => functionsClient.post("/reports-export-csv", data), integrityCheck: (data: { external_report_id: string; content: string }) => functionsClient.post("/reports-integrity-check", data), }, // ============ DOCTOR ============ doctor: { summary: (data: { doctor_id: string }) => functionsClient.post("/doctor-summary", data), occupancy: (data: { external_doctor_id: string; date_from?: string; date_to?: string; }) => functionsClient.post("/doctor-occupancy", data), delaySuggestion: (data: { external_doctor_id: string }) => functionsClient.post("/doctor-delay-suggestion", data), }, // ============ PATIENTS ============ patients: { history: (data: { patient_id: string }) => functionsClient.post("/patients-history", data), preferences: (external_patient_id?: string) => functionsClient.get("/patients-preferences", { params: { external_patient_id }, }), updatePreferences: (data: { external_patient_id?: string; preferred_days?: string[]; preferred_times?: string[]; preferred_doctor_id?: string; communication_channel?: string; }) => functionsClient.post("/patients-preferences", data), portal: () => functionsClient.get("/patients-portal"), }, // ============ PRIVACY (LGPD) ============ privacy: { request: (action: "access" | "delete" | "export") => functionsClient.post("/privacy", { action }), }, // ============ FEATURE FLAGS ============ flags: { list: () => functionsClient.get("/flags"), update: (data: { key: string; enabled: boolean; config?: Record; }) => functionsClient.post("/flags", data), }, // ============ ACCESSIBILITY ============ accessibility: { preferences: () => functionsClient.get("/accessibility-preferences"), updatePreferences: (data: { dark_mode?: boolean; high_contrast?: boolean; font_size?: string; dyslexia_font?: boolean; }) => functionsClient.post("/accessibility-preferences", data), }, // ============ AUDIT ============ audit: { list: (params?: { entity_type?: string; entity_id?: string; action_type?: string; limit?: number; }) => functionsClient.get("/audit-list", { params }), }, // ============ SYSTEM ============ system: { healthCheck: () => functionsClient.get("/system-health-check"), cacheRebuild: () => functionsClient.post("/system-cache-rebuild", {}), cronRunner: (data: { job: string }) => functionsClient.post("/system-cron-runner", data), }, // ============ OFFLINE/PWA ============ offline: { agendaToday: (doctorId: string) => functionsClient.get(`/offline-agenda-today/${doctorId}`), patientBasic: (patientId: string) => functionsClient.get(`/offline-patient-basic/${patientId}`), }, }; export default edgeFunctions;