/** Service for route-related API calls */ import { supabase } from '@/supabase' import type { Route, BusStop } from '@/types' export const routesService = { /** Get all routes with optional filtering */ async getAllRoutes(filters?: { originCity?: string, destinationCity?: string }): Promise { let query = supabase.from('routes').select('id, name, description, color, direction, origin_city, destination_city, distance_km, estimated_duration_minutes, average_speed_kmh, status, created_at, updated_at') if (filters?.originCity) { query = query.eq('origin_city', filters.originCity) } if (filters?.destinationCity) { query = query.eq('destination_city', filters.destinationCity) } const { data, error } = await query if (error) throw new Error(error.message) return data as Route[] }, /** Get a single route by ID */ async getRouteById(id: string): Promise { const { data, error } = await supabase.from('routes').select('id, name, description, color, direction, origin_city, destination_city, distance_km, estimated_duration_minutes, average_speed_kmh, status, created_at, updated_at').eq('id', id).single() if (error) throw new Error(error.message) return data as Route }, /** Get all stops for a route */ async getRouteStops(routeId: string): Promise { // Query the junction table to get the order, joined with the actual bus_stop table const { data, error } = await supabase .from('route_stops') .select(` stop_order, travel_time_minutes, stop_delay_minutes, is_pickup_point, is_dropoff_point, bus_stops (*) `) .eq('route_id', routeId) .order('stop_order', { ascending: true }) if (error) { console.error('getRouteStops Error:', error) throw new Error(error.message) } console.log('getRouteStops raw data:', data) // Map back to the expected plain array of BusStop with merged properties return (data || []).map((row: any) => { // Handle possibility of bus_stops being an array or object const busStopData = Array.isArray(row.bus_stops) ? row.bus_stops[0] : row.bus_stops; return { ...(busStopData || {}), stop_order: row.stop_order, travel_time_minutes: row.travel_time_minutes, stop_delay_minutes: row.stop_delay_minutes, is_pickup_point: row.is_pickup_point, is_dropoff_point: row.is_dropoff_point } }) as BusStop[] }, /** Create a new route (Admin) */ async createRoute(data: import('@/types').RouteCreate): Promise { // Pydantic automatically generated IDs in Python; we rely on Postgres default uuid_generate_v4() const { data: insertedRoute, error } = await supabase .from('routes') .insert([data]) .select() .single() if (error) throw new Error(error.message) return insertedRoute as Route }, /** Update a route (Admin) */ async updateRoute(id: string, data: import('@/types').RouteUpdate): Promise { const { data: updatedRoute, error } = await supabase .from('routes') .update(data) .eq('id', id) .select() .single() if (error) throw new Error(error.message) return updatedRoute as Route }, /** Delete a route (Admin) */ async deleteRoute(id: string): Promise { const { error } = await supabase.from('routes').delete().eq('id', id) if (error) throw new Error(error.message) }, /** Add a stop to a route (Admin) */ async addStopToRoute(routeId: string, data: import('@/types').RouteStopCreate): Promise { // The API allowed dynamic re-ordering of stops. // We will insert the new stop at the specified stop_order directly. // (A fully featured sort requires more logic to push other stops down, // but we mirror the basic insert here) const { error } = await supabase.from('route_stops').insert([{ route_id: routeId, ...data }]) if (error) throw new Error(error.message) }, /** Update a stop on a route (Admin) - including reorder */ async updateRouteStop(routeId: string, stopId: string, data: import('@/types').RouteStopUpdate): Promise { const { error } = await supabase .from('route_stops') .update(data) .match({ route_id: routeId, stop_id: stopId }) if (error) throw new Error(error.message) }, /** Remove a stop from a route (Admin) */ async removeStopFromRoute(routeId: string, stopId: string): Promise { const { error } = await supabase .from('route_stops') .delete() .match({ route_id: routeId, stop_id: stopId }) if (error) throw new Error(error.message) } }