88 lines
3.1 KiB
JavaScript
88 lines
3.1 KiB
JavaScript
// 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 [];
|
|
}
|
|
}
|