| import { useState, useEffect, useCallback } from 'react'; |
| import { eq, desc, and, inArray } from 'drizzle-orm'; |
| import { useDatabase } from './useDatabase'; |
| import { rides } from '../db/schema'; |
|
|
| |
|
|
| type RideStatus = 'searching' | 'matched' | 'in_progress' | 'completed' | 'cancelled'; |
|
|
| interface RideData { |
| id: string; |
| userId: string; |
| originAddress: string; |
| originLatitude: number; |
| originLongitude: number; |
| destinationAddress: string; |
| destinationLatitude: number; |
| destinationLongitude: number; |
| routePolyline: string | null; |
| scheduledTime: string | null; |
| status: RideStatus; |
| seatPrice: number | null; |
| totalDistance: number | null; |
| estimatedDuration: number | null; |
| createdAt: string | null; |
| updatedAt: string | null; |
| } |
|
|
| interface NewRide { |
| id: string; |
| userId: string; |
| originAddress: string; |
| originLatitude: number; |
| originLongitude: number; |
| destinationAddress: string; |
| destinationLatitude: number; |
| destinationLongitude: number; |
| routePolyline?: string; |
| scheduledTime?: string; |
| seatPrice?: number; |
| totalDistance?: number; |
| estimatedDuration?: number; |
| } |
|
|
| interface UseRidesReturn { |
| rides: RideData[]; |
| activeRide: RideData | null; |
| loading: boolean; |
| createRide: (data: NewRide) => Promise<RideData | null>; |
| updateRideStatus: (rideId: string, status: RideStatus) => Promise<void>; |
| getRideById: (rideId: string) => Promise<RideData | null>; |
| refresh: () => Promise<void>; |
| } |
|
|
| |
|
|
| export function useRides(statusFilter?: RideStatus[]): UseRidesReturn { |
| const { db } = useDatabase(); |
| const [ridesList, setRidesList] = useState<RideData[]>([]); |
| const [loading, setLoading] = useState(true); |
|
|
| |
|
|
| const loadRides = useCallback(async () => { |
| try { |
| setLoading(true); |
|
|
| const activeStatuses: RideStatus[] = ['searching', 'matched', 'in_progress']; |
|
|
| |
| const allRides = await db |
| .select() |
| .from(rides) |
| .orderBy(desc(rides.createdAt)) |
| .all(); |
|
|
| let filtered: typeof allRides = allRides; |
|
|
| if (statusFilter && statusFilter.length > 0) { |
| filtered = allRides.filter((r) => statusFilter.includes(r.status as RideStatus)); |
| } |
|
|
| setRidesList(filtered as RideData[]); |
| } catch (error) { |
| console.error('[useRides] Failed to load rides:', error); |
| setRidesList([]); |
| } finally { |
| setLoading(false); |
| } |
| }, [db, statusFilter]); |
|
|
| useEffect(() => { |
| loadRides(); |
| }, [loadRides]); |
|
|
| |
|
|
| const activeRide = |
| ridesList.find( |
| (r) => r.status === 'searching' || r.status === 'matched' || r.status === 'in_progress', |
| ) ?? null; |
|
|
| |
|
|
| const createRide = useCallback( |
| async (data: NewRide): Promise<RideData | null> => { |
| try { |
| await db.insert(rides).values({ |
| id: data.id, |
| userId: data.userId, |
| originAddress: data.originAddress, |
| originLatitude: data.originLatitude, |
| originLongitude: data.originLongitude, |
| destinationAddress: data.destinationAddress, |
| destinationLatitude: data.destinationLatitude, |
| destinationLongitude: data.destinationLongitude, |
| routePolyline: data.routePolyline ?? null, |
| scheduledTime: data.scheduledTime ?? null, |
| seatPrice: data.seatPrice ?? null, |
| totalDistance: data.totalDistance ?? null, |
| estimatedDuration: data.estimatedDuration ?? null, |
| }).run(); |
|
|
| await loadRides(); |
|
|
| const created = ridesList.find((r) => r.id === data.id); |
| return (created as RideData) ?? null; |
| } catch (error) { |
| console.error('[useRides] Failed to create ride:', error); |
| return null; |
| } |
| }, |
| [db, loadRides, ridesList], |
| ); |
|
|
| |
|
|
| const updateRideStatus = useCallback( |
| async (rideId: string, status: RideStatus) => { |
| try { |
| await db |
| .update(rides) |
| .set({ status, updatedAt: new Date().toISOString() }) |
| .where(eq(rides.id, rideId)) |
| .run(); |
|
|
| await loadRides(); |
| } catch (error) { |
| console.error('[useRides] Failed to update ride status:', error); |
| } |
| }, |
| [db, loadRides], |
| ); |
|
|
| |
|
|
| const getRideById = useCallback( |
| async (rideId: string): Promise<RideData | null> => { |
| try { |
| const results = await db |
| .select() |
| .from(rides) |
| .where(eq(rides.id, rideId)) |
| .all(); |
|
|
| return (results[0] as RideData) ?? null; |
| } catch (error) { |
| console.error('[useRides] Failed to get ride:', error); |
| return null; |
| } |
| }, |
| [db], |
| ); |
|
|
| return { |
| rides: ridesList, |
| activeRide, |
| loading, |
| createRide, |
| updateRideStatus, |
| getRideById, |
| refresh: loadRides, |
| }; |
| } |
|
|