| import { useState, useEffect, useCallback } from 'react'; |
| import { eq, desc, and } from 'drizzle-orm'; |
| import { useDatabase } from './useDatabase'; |
| import { matches } from '../db/schema'; |
|
|
| |
|
|
| type MatchStatus = 'pending' | 'accepted' | 'rejected' | 'completed' | 'cancelled'; |
|
|
| interface MatchData { |
| id: string; |
| rideId: string; |
| matchedUserId: string; |
| matchedUserFullName: string; |
| matchedUserAvatar: string | null; |
| matchedUserRating: number | null; |
| pickupPoint: string | null; |
| pickupLatitude: number | null; |
| pickupLongitude: number | null; |
| dropoffPoint: string | null; |
| dropoffLatitude: number | null; |
| dropoffLongitude: number | null; |
| status: MatchStatus; |
| createdAt: string | null; |
| updatedAt: string | null; |
| } |
|
|
| interface NewMatch { |
| id: string; |
| rideId: string; |
| matchedUserId: string; |
| matchedUserFullName: string; |
| matchedUserAvatar?: string; |
| matchedUserRating?: number; |
| pickupPoint?: string; |
| pickupLatitude?: number; |
| pickupLongitude?: number; |
| dropoffPoint?: string; |
| dropoffLatitude?: number; |
| dropoffLongitude?: number; |
| } |
|
|
| interface UseMatchesReturn { |
| matches: MatchData[]; |
| pendingMatches: MatchData[]; |
| activeMatch: MatchData | null; |
| loading: boolean; |
| createMatch: (data: NewMatch) => Promise<MatchData | null>; |
| updateMatchStatus: (matchId: string, status: MatchStatus) => Promise<void>; |
| acceptMatch: (matchId: string) => Promise<void>; |
| rejectMatch: (matchId: string) => Promise<void>; |
| refresh: () => Promise<void>; |
| } |
|
|
| |
|
|
| export function useMatches(rideId?: string): UseMatchesReturn { |
| const { db } = useDatabase(); |
| const [matchesList, setMatchesList] = useState<MatchData[]>([]); |
| const [loading, setLoading] = useState(true); |
|
|
| |
|
|
| const loadMatches = useCallback(async () => { |
| try { |
| setLoading(true); |
|
|
| let results; |
|
|
| if (rideId) { |
| results = await db |
| .select() |
| .from(matches) |
| .where(eq(matches.rideId, rideId)) |
| .orderBy(desc(matches.createdAt)) |
| .all(); |
| } else { |
| results = await db |
| .select() |
| .from(matches) |
| .orderBy(desc(matches.createdAt)) |
| .all(); |
| } |
|
|
| setMatchesList(results as MatchData[]); |
| } catch (error) { |
| console.error('[useMatches] Failed to load matches:', error); |
| setMatchesList([]); |
| } finally { |
| setLoading(false); |
| } |
| }, [db, rideId]); |
|
|
| useEffect(() => { |
| loadMatches(); |
| }, [loadMatches]); |
|
|
| |
|
|
| const pendingMatches = matchesList.filter((m) => m.status === 'pending'); |
| const activeMatch = |
| matchesList.find((m) => m.status === 'accepted') ?? null; |
|
|
| |
|
|
| const createMatch = useCallback( |
| async (data: NewMatch): Promise<MatchData | null> => { |
| try { |
| await db.insert(matches).values({ |
| id: data.id, |
| rideId: data.rideId, |
| matchedUserId: data.matchedUserId, |
| matchedUserFullName: data.matchedUserFullName, |
| matchedUserAvatar: data.matchedUserAvatar ?? null, |
| matchedUserRating: data.matchedUserRating ?? 0, |
| pickupPoint: data.pickupPoint ?? null, |
| pickupLatitude: data.pickupLatitude ?? null, |
| pickupLongitude: data.pickupLongitude ?? null, |
| dropoffPoint: data.dropoffPoint ?? null, |
| dropoffLatitude: data.dropoffLatitude ?? null, |
| dropoffLongitude: data.dropoffLongitude ?? null, |
| }).run(); |
|
|
| await loadMatches(); |
|
|
| return matchesList.find((m) => m.id === data.id) ?? null; |
| } catch (error) { |
| console.error('[useMatches] Failed to create match:', error); |
| return null; |
| } |
| }, |
| [db, loadMatches, matchesList], |
| ); |
|
|
| |
|
|
| const updateMatchStatus = useCallback( |
| async (matchId: string, status: MatchStatus) => { |
| try { |
| await db |
| .update(matches) |
| .set({ status, updatedAt: new Date().toISOString() }) |
| .where(eq(matches.id, matchId)) |
| .run(); |
|
|
| await loadMatches(); |
| } catch (error) { |
| console.error('[useMatches] Failed to update match status:', error); |
| } |
| }, |
| [db, loadMatches], |
| ); |
|
|
| |
|
|
| const acceptMatch = useCallback( |
| (matchId: string) => updateMatchStatus(matchId, 'accepted'), |
| [updateMatchStatus], |
| ); |
|
|
| const rejectMatch = useCallback( |
| (matchId: string) => updateMatchStatus(matchId, 'rejected'), |
| [updateMatchStatus], |
| ); |
|
|
| return { |
| matches: matchesList, |
| pendingMatches, |
| activeMatch, |
| loading, |
| createMatch, |
| updateMatchStatus, |
| acceptMatch, |
| rejectMatch, |
| refresh: loadMatches, |
| }; |
| } |
|
|