// Serviço para comunicação com o backend const API_BASE_URL = import.meta.env.VITE_API_URL || "http://localhost:3000/api"; interface ApiResponse { data: T | null; error: string | null; isBackendDown: boolean; } // Função auxiliar para fazer requisições async function fetchFromBackend(endpoint: string): Promise> { try { const response = await fetch(`${API_BASE_URL}${endpoint}`, { method: "GET", headers: { "Content-Type": "application/json", }, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return { data, error: null, isBackendDown: false, }; } catch (error) { console.error(`Error fetching ${endpoint}:`, error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } // Funções específicas para cada endpoint /** * Busca as funções profissionais disponíveis */ export async function getProfessionalRoles(): Promise> { return fetchFromBackend("/professional-roles"); } /** * Busca as empresas disponíveis */ export async function getCompanies(): Promise< ApiResponse< Array<{ id: string; nome: string; }> > > { return fetchFromBackend("/api/empresas"); } /** * Busca as funções profissionais disponíveis do backend */ export async function getFunctions(): Promise< ApiResponse< Array<{ id: string; nome: string; }> > > { return fetchFromBackend("/api/funcoes"); } /** * Cria um novo perfil profissional */ export async function createProfessional(data: any, token?: string): Promise> { try { const headers: any = { "Content-Type": "application/json", }; if (token) { headers["Authorization"] = `Bearer ${token}`; } const response = await fetch(`${API_BASE_URL}/api/profissionais`, { method: "POST", headers: headers, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || `HTTP error! status: ${response.status}`); } const responseData = await response.json(); return { data: responseData, error: null, isBackendDown: false, }; } catch (error) { console.error("Error creating professional:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } /** * Atualiza um profissional existente */ export async function updateProfessional(id: string, data: any, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/profissionais/${id}`, { method: "PUT", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || `HTTP error! status: ${response.status}`); } const responseData = await response.json(); return { data: responseData, error: null, isBackendDown: false, }; } catch (error) { console.error("Error updating professional:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } /** * Remove um profissional */ export async function deleteProfessional(id: string, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/profissionais/${id}`, { method: "DELETE", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || `HTTP error! status: ${response.status}`); } return { data: null, error: null, isBackendDown: false, }; } catch (error) { console.error("Error deleting professional:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } /** * Busca um profissional pelo ID */ export async function getProfessionalById(id: string, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/profissionais/${id}`, { method: "GET", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return { data, error: null, isBackendDown: false, }; } catch (error) { console.error("Error fetching professional by id:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } /** * Busca a lista de profissionais */ export async function getProfessionals(token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/profissionais`, { method: "GET", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return { data, error: null, isBackendDown: false, }; } catch (error) { console.error("Error fetching professionals:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } export interface EventTypeResponse { id: string; nome: string; precos: any[]; } /** * Busca os tipos de eventos disponíveis */ export async function getEventTypes(): Promise< ApiResponse > { return fetchFromBackend("/api/tipos-eventos"); } /** * Busca os cursos/turmas disponíveis */ export async function getCourses(): Promise< ApiResponse< Array<{ id: string; name: string; institution: string; year: number; }> > > { return fetchFromBackend("/courses"); } /** * Busca as instituições/empresas disponíveis */ export async function getInstitutions(): Promise< ApiResponse< Array<{ id: string; name: string; }> > > { return fetchFromBackend("/institutions"); } /** * Busca os anos de formatura disponíveis */ export async function getGraduationYears(): Promise>> { return fetchFromBackend>("/api/anos-formaturas"); } /** * Busca os cursos disponíveis */ export async function getAvailableCourses(): Promise>> { return fetchFromBackend>("/api/cursos"); } /** * Busca a listagem de Cadastro FOT */ /** * Busca a listagem de Cadastro FOT */ export async function getCadastroFot(token: string, empresaId?: string): Promise> { try { let url = `${API_BASE_URL}/api/cadastro-fot`; if (empresaId) { url += `?empresa_id=${empresaId}`; } const response = await fetch(url, { method: "GET", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return { data, error: null, isBackendDown: false, }; } catch (error) { console.error("Error fetching cadastro fot:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } /** * Cria um novo cadastro FOT */ export async function createCadastroFot(data: any, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/cadastro-fot`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || `HTTP error! status: ${response.status}`); } const responseData = await response.json(); return { data: responseData, error: null, isBackendDown: false, }; } catch (error) { console.error("Error creating cadastro fot:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } /** * Atualiza um cadastro FOT existente */ export async function updateCadastroFot(id: string, data: any, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/cadastro-fot/${id}`, { method: "PUT", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || `HTTP error! status: ${response.status}`); } const responseData = await response.json(); return { data: responseData, error: null, isBackendDown: false, }; } catch (error) { console.error("Error updating cadastro fot:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } /** * Remove um cadastro FOT */ export async function deleteCadastroFot(id: string, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/cadastro-fot/${id}`, { method: "DELETE", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || `HTTP error! status: ${response.status}`); } return { data: null, error: null, isBackendDown: false, }; } catch (error) { console.error("Error deleting cadastro fot:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } /** * Busca os níveis educacionais disponíveis (EF I / EF II) */ export async function getEducationLevels(): Promise< ApiResponse< Array<{ id: string; nome: string; }> > > { return fetchFromBackend("/api/niveis-educacionais"); } /** * Busca as universidades cadastradas */ export async function getUniversities(): Promise< ApiResponse< Array<{ id: string; nome: string; }> > > { return fetchFromBackend("/api/universidades"); } // Agenda export const createAgenda = async (token: string, data: any) => { try { const response = await fetch(`${API_BASE_URL}/api/agenda`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || `HTTP error! status: ${response.status}`); } const responseData = await response.json(); return { data: responseData, error: null }; } catch (error: any) { console.error("Erro ao criar agenda:", error); return { data: null, error: error.message || "Erro ao criar agenda" }; } }; // Agenda export const getAgendas = async (token: string): Promise> => { try { const response = await fetch(`${API_BASE_URL}/api/agenda`, { method: "GET", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return { data, error: null, isBackendDown: false }; } catch (error: any) { console.error("Erro ao buscar agendas:", error); return { data: null, error: error.message || "Erro ao buscar agendas", isBackendDown: true }; } }; export const updateAssignmentStatus = async (token: string, eventId: string, professionalId: string, status: string, reason?: string) => { try { const response = await fetch(`${API_BASE_URL}/api/agenda/${eventId}/professionals/${professionalId}/status`, { method: "PATCH", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, body: JSON.stringify({ status, reason }), }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); return { error: errorData.error || "Failed to update assignment status" }; } const data = await response.json(); return { data }; } catch (error) { console.error("API updateAssignmentStatus error:", error); return { error: "Network error" }; } }; /** * Busca usuários pendentes de aprovação */ export async function getPendingUsers(token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/admin/users/pending`, { method: "GET", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return { data, error: null, isBackendDown: false, }; } catch (error) { console.error("Error fetching pending users:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } /** * Aprova um usuário */ export async function approveUser(userId: string, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/admin/users/${userId}/approve`, { method: "PATCH", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return { data, error: null, isBackendDown: false, }; } catch (error) { console.error("Error approving user:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } /** * Rejeita um usuário */ export async function rejectUser(userId: string, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/admin/users/${userId}/reject`, { method: "PATCH", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, // body: JSON.stringify({ reason }) // Future improvement }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return { data, error: null, isBackendDown: false, }; } catch (error) { console.error("Error rejecting user:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } /** * Atribui um profissional a um evento */ export async function assignProfessional(token: string, eventId: string, professionalId: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/agenda/${eventId}/professionals`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, body: JSON.stringify({ professional_id: professionalId }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return { data: undefined, error: null, isBackendDown: false }; } catch (error) { console.error("Error assigning professional:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true }; } } /** * Remove um profissional de um evento */ export async function removeProfessional(token: string, eventId: string, professionalId: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/agenda/${eventId}/professionals/${professionalId}`, { method: "DELETE", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return { data: undefined, error: null, isBackendDown: false }; } catch (error) { console.error("Error removing professional:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true }; } } /** * Busca profissionais de um evento */ export async function getEventProfessionals(token: string, eventId: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/agenda/${eventId}/professionals`, { method: "GET", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return { data, error: null, isBackendDown: false }; } catch (error) { console.error("Error fetching event professionals:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true }; } } /** * Atualiza o status de um evento */ export async function updateEventStatus(token: string, eventId: string, status: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/agenda/${eventId}/status`, { method: "PATCH", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, body: JSON.stringify({ status }) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return { data: undefined, error: null, isBackendDown: false }; } catch (error) { console.error("Error updating event status:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true }; } } /** * Cria um usuário pela interface administrativa */ export async function adminCreateUser(data: any, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/admin/users`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || `HTTP error! status: ${response.status}`); } const responseData = await response.json(); return { data: responseData, error: null, isBackendDown: false, }; } catch (error) { console.error("Error creating admin user:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } /** * Obtém URL pré-assinada para upload de arquivo */ export async function getUploadURL(filename: string, contentType: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/auth/upload-url`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ filename, content_type: contentType }), }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return { data, error: null, isBackendDown: false, }; } catch (error) { console.error("Error getting upload URL:", error); return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true, }; } } // Access Codes export async function createAccessCode(token: string, data: { codigo: string; descricao?: string; validade_dias: number }) { return mutationFetch(`${API_BASE_URL}/api/codigos-acesso`, "POST", data, token); } export async function listAccessCodes(token: string) { return fetchFromBackendAuthenticated(`${API_BASE_URL}/api/codigos-acesso`, token); } export async function deleteAccessCode(token: string, id: string) { return mutationFetch(`${API_BASE_URL}/api/codigos-acesso/${id}`, "DELETE", {}, token); } // Helpers for unified fetch async function fetchFromBackendAuthenticated(url: string, token: string) { try { const res = await fetch(url, { headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" } }); if (!res.ok) throw new Error(res.statusText); const data = await res.json(); return { data, error: null }; } catch (e: any) { return { data: null, error: e.message }; } } async function mutationFetch(url: string, method: string, body: any, token: string) { try { const res = await fetch(url, { method, headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }, body: JSON.stringify(body) }); if (!res.ok) { const err = await res.json().catch(() => ({})); throw new Error(err.error || res.statusText); } const data = await res.json(); return { data, error: null }; } catch (e: any) { return { data: null, error: e.message }; } } /** * Realiza o upload do arquivo para a URL pré-assinada */ export async function uploadFileToSignedUrl(uploadUrl: string, file: File): Promise { const response = await fetch(uploadUrl, { method: "PUT", headers: { "Content-Type": file.type, }, body: file, }); if (!response.ok) { throw new Error(`Failed to upload file to S3. Status: ${response.status}`); } } // --- Escalas / Scheduling --- export interface EscalaInput { agenda_id: string; profissional_id: string; data_hora_inicio: string; // ISO String data_hora_fim: string; // ISO String funcao_especifica?: string; } export async function createEscala(data: EscalaInput, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/escalas`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || `HTTP error! status: ${response.status}`); } const responseData = await response.json(); return { data: responseData, error: null, isBackendDown: false }; } catch (error) { return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true }; } } export async function listEscalas(agendaId: string, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/escalas?agenda_id=${agendaId}`, { headers: { "Authorization": `Bearer ${token}` }, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || `HTTP error! status: ${response.status}`); } const responseData = await response.json(); return { data: responseData, error: null, isBackendDown: false }; } catch (error) { return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true }; } } export async function deleteEscala(id: string, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/escalas/${id}`, { method: "DELETE", headers: { "Authorization": `Bearer ${token}` }, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || `HTTP error! status: ${response.status}`); } return { data: { message: "deleted" }, error: null, isBackendDown: false }; } catch (error) { return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true }; } } export async function updateEscala(id: string, data: Partial, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/escalas/${id}`, { method: "PUT", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, body: JSON.stringify(data), }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.error || `HTTP error! status: ${response.status}`); } return { data: { message: "updated" }, error: null, isBackendDown: false }; } catch (error) { return { data: null, error: error instanceof Error ? error.message : "Erro desconhecido", isBackendDown: true }; } } // --- Logistica (Carros/Passageiros) --- export interface CarroInput { agenda_id: string; motorista_id?: string; nome_motorista?: string; horario_chegada?: string; observacoes?: string; } export async function createCarro(data: CarroInput, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/logistica/carros`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${token}` }, body: JSON.stringify(data), }); const resData = await response.json(); if (!response.ok) throw new Error(resData.error || "Erro ao criar carro"); return { data: resData, error: null, isBackendDown: false }; } catch (err: any) { return { data: null, error: err.message, isBackendDown: true }; } } export async function listCarros(agendaId: string, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/logistica/carros?agenda_id=${agendaId}`, { headers: { "Authorization": `Bearer ${token}` }, }); const resData = await response.json(); if (!response.ok) throw new Error(resData.error || "Erro ao listar carros"); return { data: resData, error: null, isBackendDown: false }; } catch (err: any) { return { data: null, error: err.message, isBackendDown: true }; } } export async function deleteCarro(id: string, token: string): Promise> { try { const response = await fetch(`${API_BASE_URL}/api/logistica/carros/${id}`, { method: "DELETE", headers: { "Authorization": `Bearer ${token}` }, }); if (!response.ok) throw new Error("Erro ao deletar carro"); return { data: { message: "deleted" }, error: null, isBackendDown: false }; } catch (err: any) { return { data: null, error: err.message, isBackendDown: true }; } } export async function addPassenger(carroId: string, profissionalId: string, token: string) { try { const response = await fetch(`${API_BASE_URL}/api/logistica/carros/${carroId}/passageiros`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ profissional_id: profissionalId }) }); if (!response.ok) throw new Error("Erro ao adicionar passageiro"); return { error: null }; } catch (err: any) { return { error: err.message }; } } export async function removePassenger(carroId: string, profissionalId: string, token: string) { try { const response = await fetch(`${API_BASE_URL}/api/logistica/carros/${carroId}/passageiros/${profissionalId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }); if (!response.ok) throw new Error("Erro ao remover passageiro"); return { error: null }; } catch (err: any) { return { error: err.message }; } } export async function listPassengers(carroId: string, token: string) { try { const response = await fetch(`${API_BASE_URL}/api/logistica/carros/${carroId}/passageiros`, { headers: { 'Authorization': `Bearer ${token}` } }); const data = await response.json(); if (!response.ok) throw new Error("Erro ao listar passageiros"); return { data, error: null }; } catch (err: any) { return { data: null, error: err.message }; } } /** * Verifica se um código de acesso é válido */ export async function verifyAccessCode(code: string): Promise> { return fetchFromBackend<{ valid: boolean; error?: string }>(`/api/public/codigos-acesso/verificar?code=${encodeURIComponent(code)}`); }