// src/utils/apiUtils.js import axios from 'axios'; /* ------------------------------------------------------------------ Single authority for “baseURL + path” so we never worry about trailing slashes again. ------------------------------------------------------------------*/ const BASE = ( import.meta.env.VITE_API_BASE || process.env.REACT_APP_API_URL || '' ).replace(/\/+$/, ''); // trim *all* trailing “/” export const api = (path = '') => `${BASE}${path.startsWith('/') ? '' : '/'}${path}`; /* ------------------------------------------------------------------ Fetch areas-by-state (static JSON in public/ or served by nginx) ------------------------------------------------------------------*/ export const fetchAreasByState = async (state) => { try { // NOTE: if Institution_data.json is in /public, nginx serves it const res = await fetch(api('/Institution_data.json')); if (!res.ok) throw new Error(`HTTP ${res.status}`); // Adjust this part if your JSON structure is different const json = await res.json(); return json[state]?.areas || []; } catch (err) { console.error('Error fetching areas:', err.message); return []; } }; /* ------------------------------------------------------------------ Client-side Google Maps geocode ------------------------------------------------------------------*/ export async function clientGeocodeZip(zip) { const apiKey = import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? process.env.REACT_APP_GOOGLE_MAPS_API_KEY; const url = `https://maps.googleapis.com/maps/api/geocode/json` + `?address=${encodeURIComponent(zip)}&key=${apiKey}`; const resp = await axios.get(url); const { status, results } = resp.data; if (status === 'OK' && results.length) { return results[0].geometry.location; // { lat, lng } } throw new Error('Geocoding failed.'); } /* ------------------------------------------------------------------ Haversine distance helper (miles) ------------------------------------------------------------------*/ export function haversineDistance(lat1, lon1, lat2, lon2) { const R = 3959; // earth radius in miles const toRad = (v) => (v * Math.PI) / 180; const dLat = toRad(lat2 - lat1); const dLon = toRad(lon2 - lon1); const a = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2; return 2 * R * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); } /* ------------------------------------------------------------------ Fetch schools for one or many CIP prefixes ------------------------------------------------------------------*/ export async function fetchSchools(cipCodes) { try { // 1) Ensure array-ness, then join with commas const codes = Array.isArray(cipCodes) ? cipCodes : [cipCodes]; const cipParam = codes.join(','); // 2) Hit backend const res = await axios.get(api('/api/schools'), { params: { cipCodes: cipParam }, }); return res.data; } catch (err) { console.error('Error fetching schools:', err.message); return []; } }