// Example usage of Institute Geocoder functions // This file demonstrates how to integrate the geocoding functions in your frontend import { createClient } from '@supabase/supabase-js' // Initialize Supabase client const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL! const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! const supabase = createClient(supabaseUrl, supabaseAnonKey) // Types for institute data interface Institute { id: string name: string address: { street?: string town?: string county?: string postcode?: string country?: string } geo_coordinates?: { latitude: number longitude: number boundingbox: string[] search_query: string geocoded_at: string } } interface GeocodingResult { success: boolean message: string coordinates?: { latitude: number longitude: number boundingbox: string[] } error?: string } // 1. Geocode a single institute export async function geocodeInstitute(instituteId: string): Promise { try { const { data, error } = await supabase.functions.invoke('institute-geocoder', { body: { institute_id: instituteId } }) if (error) { throw new Error(error.message) } return data } catch (error) { console.error('Geocoding failed:', error) return { success: false, message: 'Geocoding failed', error: error instanceof Error ? error.message : 'Unknown error' } } } // 2. Batch geocode multiple institutes export async function batchGeocodeInstitutes( limit: number = 10, forceRefresh: boolean = false ): Promise { try { const { data, error } = await supabase.functions.invoke('institute-geocoder/batch', { body: { limit, force_refresh: forceRefresh } }) if (error) { throw new Error(error.message) } return data } catch (error) { console.error('Batch geocoding failed:', error) throw error } } // 3. Get institutes that need geocoding export async function getInstitutesNeedingGeocoding(): Promise { try { const { data, error } = await supabase .from('institutes') .select('id, name, address, geo_coordinates') .or('geo_coordinates.is.null,geo_coordinates.eq.{}') .not('import_id', 'is', null) if (error) { throw new Error(error.message) } return data || [] } catch (error) { console.error('Failed to fetch institutes:', error) return [] } } // 4. Display institute on a map (example with Leaflet) export function displayInstituteOnMap( institute: Institute, mapElement: HTMLElement ): void { if (!institute.geo_coordinates) { console.warn('Institute has no coordinates:', institute.name) return } // This is a placeholder - you'd need to implement actual map rendering // For example, using Leaflet, Mapbox, or Google Maps const { latitude, longitude } = institute.geo_coordinates console.log(`Displaying ${institute.name} at ${latitude}, ${longitude}`) // Example map implementation: // const map = L.map(mapElement).setView([latitude, longitude], 13) // L.marker([latitude, longitude]).addTo(map).bindPopup(institute.name) } // 5. React component example export function InstituteGeocoder() { const [institutes, setInstitutes] = useState([]) const [loading, setLoading] = useState(false) const [geocodingProgress, setGeocodingProgress] = useState(0) // Load institutes that need geocoding useEffect(() => { loadInstitutes() }, []) async function loadInstitutes() { const data = await getInstitutesNeedingGeocoding() setInstitutes(data) } // Geocode all institutes async function geocodeAllInstitutes() { setLoading(true) setGeocodingProgress(0) try { const result = await batchGeocodeInstitutes(institutes.length, false) if (result.success) { setGeocodingProgress(100) // Reload institutes to show updated coordinates await loadInstitutes() } } catch (error) { console.error('Batch geocoding failed:', error) } finally { setLoading(false) } } // Geocode single institute async function geocodeSingleInstitute(instituteId: string) { try { const result = await geocodeInstitute(instituteId) if (result.success) { // Reload institutes to show updated coordinates await loadInstitutes() } } catch (error) { console.error('Single geocoding failed:', error) } } return (

Institute Geocoding

{loading && (
)}
{institutes.map(institute => (

{institute.name}

{institute.address.street && `${institute.address.street}, `} {institute.address.town && `${institute.address.town}, `} {institute.address.county && `${institute.address.county}, `} {institute.address.postcode}

{institute.geo_coordinates ? (
📍 {institute.geo_coordinates.latitude}, {institute.geo_coordinates.longitude} Geocoded: {new Date(institute.geo_coordinates.geocoded_at).toLocaleDateString()}
) : ( )}
))}
) } // 6. Utility functions for working with coordinates export class CoordinateUtils { // Calculate distance between two points (Haversine formula) static calculateDistance( lat1: number, lon1: number, lat2: number, lon2: number ): number { const R = 6371 // Earth's radius in kilometers const dLat = this.toRadians(lat2 - lat1) const dLon = this.toRadians(lon2 - lon1) const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(this.toRadians(lat1)) * Math.cos(this.toRadians(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2) const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) return R * c } // Convert degrees to radians private static toRadians(degrees: number): number { return degrees * (Math.PI / 180) } // Check if coordinates are within a bounding box static isWithinBounds( lat: number, lon: number, bounds: [number, number, number, number] // [minLat, maxLat, minLon, maxLon] ): boolean { return lat >= bounds[0] && lat <= bounds[1] && lon >= bounds[2] && lon <= bounds[3] } // Format coordinates for display static formatCoordinates(lat: number, lon: number): string { const latDir = lat >= 0 ? 'N' : 'S' const lonDir = lon >= 0 ? 'E' : 'W' return `${Math.abs(lat).toFixed(6)}°${latDir}, ${Math.abs(lon).toFixed(6)}°${lonDir}` } } // 7. Example of using coordinates in Neo4j queries export const neo4jQueries = { // Create institute node with location createInstituteWithLocation: ` CREATE (i:Institute { id: $institute_id, name: $name, location: point({latitude: $latitude, longitude: $longitude}) }) RETURN i `, // Find institutes within radius findInstitutesWithinRadius: ` MATCH (i:Institute) WHERE distance(i.location, point({latitude: $centerLat, longitude: $centerLon})) < $radiusMeters RETURN i, distance(i.location, point({latitude: $centerLat, longitude: $centerLon})) as distance ORDER BY distance `, // Find institutes in bounding box findInstitutesInBounds: ` MATCH (i:Institute) WHERE i.location.latitude >= $minLat AND i.location.latitude <= $maxLat AND i.location.longitude >= $minLon AND i.location.longitude <= $maxLon RETURN i ` } export default { geocodeInstitute, batchGeocodeInstitutes, getInstitutesNeedingGeocoding, displayInstituteOnMap, InstituteGeocoder, CoordinateUtils, neo4jQueries }