132 lines
5.1 KiB
TypeScript
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)
|
|
}
|
|
}
|