Files
SIB/frontend/src/services/routesService.ts

132 lines
5.1 KiB
TypeScript

/** 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<Route[]> {
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<Route> {
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<BusStop[]> {
// 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<Route> {
// 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<Route> {
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<void> {
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<void> {
// 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<void> {
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<void> {
const { error } = await supabase
.from('route_stops')
.delete()
.match({ route_id: routeId, stop_id: stopId })
if (error) throw new Error(error.message)
}
}