mobileapp / src /hooks /useSavedLocations.ts
Antaram Dev Bot
feat: complete ANTARAM.ORG ride-sharing app frontend
5c876be
import { useState, useEffect, useCallback } from 'react';
import { eq, desc, sql, and } from 'drizzle-orm';
import { useDatabase } from './useDatabase';
import { savedLocations } from '../db/schema';
// ─── Types ─────────────────────────────────────────────────────────────────────
type LocationType = 'home' | 'work' | 'favorite' | 'recent';
interface SavedLocationData {
id: string;
userId: string;
name: string;
address: string;
latitude: number;
longitude: number;
type: LocationType;
createdAt: string | null;
}
interface NewLocation {
id: string;
userId: string;
name: string;
address: string;
latitude: number;
longitude: number;
type?: LocationType;
}
interface UpdateLocationData {
name?: string;
address?: string;
latitude?: number;
longitude?: number;
type?: LocationType;
}
interface UseSavedLocationsReturn {
locations: SavedLocationData[];
loading: boolean;
loadLocations: () => Promise<void>;
addLocation: (data: NewLocation) => Promise<SavedLocationData | null>;
updateLocation: (locationId: string, data: UpdateLocationData) => Promise<void>;
deleteLocation: (locationId: string) => Promise<void>;
incrementUsage: (locationId: string) => Promise<void>;
refresh: () => Promise<void>;
}
// ─── Hook ──────────────────────────────────────────────────────────────────────
export function useSavedLocations(userId?: string): UseSavedLocationsReturn {
const { db } = useDatabase();
const [locationsList, setLocationsList] = useState<SavedLocationData[]>([]);
const [loading, setLoading] = useState(true);
// ── Load locations ───────────────────────────────────────────────────────────
const loadLocations = useCallback(async () => {
try {
setLoading(true);
let results;
if (userId) {
results = await db
.select()
.from(savedLocations)
.where(eq(savedLocations.userId, userId))
.orderBy(desc(savedLocations.createdAt))
.all();
} else {
results = await db
.select()
.from(savedLocations)
.orderBy(desc(savedLocations.createdAt))
.all();
}
setLocationsList(results as SavedLocationData[]);
} catch (error) {
console.error('[useSavedLocations] Failed to load locations:', error);
setLocationsList([]);
} finally {
setLoading(false);
}
}, [db, userId]);
useEffect(() => {
loadLocations();
}, [loadLocations]);
// ── Add location ─────────────────────────────────────────────────────────────
const addLocation = useCallback(
async (data: NewLocation): Promise<SavedLocationData | null> => {
try {
await db.insert(savedLocations).values({
id: data.id,
userId: data.userId,
name: data.name,
address: data.address,
latitude: data.latitude,
longitude: data.longitude,
type: data.type ?? 'favorite',
}).run();
await loadLocations();
return (
(locationsList.find((l) => l.id === data.id) as SavedLocationData) ?? null
);
} catch (error) {
console.error('[useSavedLocations] Failed to add location:', error);
return null;
}
},
[db, loadLocations, locationsList],
);
// ── Update location ──────────────────────────────────────────────────────────
const updateLocation = useCallback(
async (locationId: string, data: UpdateLocationData) => {
try {
await db
.update(savedLocations)
.set(data)
.where(eq(savedLocations.id, locationId))
.run();
await loadLocations();
} catch (error) {
console.error('[useSavedLocations] Failed to update location:', error);
}
},
[db, loadLocations],
);
// ── Delete location ──────────────────────────────────────────────────────────
const deleteLocation = useCallback(
async (locationId: string) => {
try {
await db
.delete(savedLocations)
.where(eq(savedLocations.id, locationId))
.run();
await loadLocations();
} catch (error) {
console.error('[useSavedLocations] Failed to delete location:', error);
}
},
[db, loadLocations],
);
// ── Increment usage (bump to top of recent) ──────────────────────────────────
const incrementUsage = useCallback(
async (locationId: string) => {
try {
// Update the createdAt timestamp to "now" so it appears at the top
await db
.update(savedLocations)
.set({ type: 'recent', createdAt: new Date().toISOString() })
.where(eq(savedLocations.id, locationId))
.run();
await loadLocations();
} catch (error) {
console.error(
'[useSavedLocations] Failed to increment usage:',
error,
);
}
},
[db, loadLocations],
);
return {
locations: locationsList,
loading,
loadLocations,
addLocation,
updateLocation,
deleteLocation,
incrementUsage,
refresh: loadLocations,
};
}