Add bulk POI distances endpoint for decoupled loading

New GET /api/poi/distances/bulk returns all POI distances keyed by
listing ID, allowing the frontend to fetch distances separately
from the listing stream and keep the stream on the cached path.
This commit is contained in:
Viktor Barzin 2026-02-22 13:29:35 +00:00
parent 2f3d2dc480
commit 3885fd52fe
No known key found for this signature in database
GPG key ID: 0EB088298288D958
3 changed files with 46 additions and 1 deletions

View file

@ -172,6 +172,42 @@ async def calculate_distances(
return {"task_id": result.task_id or "", "message": result.message}
@poi_router.get("/distances/bulk")
async def get_bulk_distances(
user: Annotated[User, Depends(get_current_user)],
listing_type: ListingType = ListingType.RENT,
) -> dict[int, list[POIDistanceResponse]]:
"""Get all POI distances for the current user, keyed by listing ID."""
user_id = _get_user_id(user)
repo = POIRepository(engine)
pois = {p.id: p for p in poi_service.get_user_pois(repo, user_id)}
if not pois:
return {}
from repositories.listing_repository import ListingRepository
from database import engine as db_engine
listing_repo = ListingRepository(db_engine)
all_ids = list(listing_repo.get_listing_ids(listing_type))
if not all_ids:
return {}
distances = repo.get_distances_for_listings(all_ids, listing_type, user_id)
result: dict[int, list[POIDistanceResponse]] = {}
for d in distances:
poi_name = pois[d.poi_id].name if d.poi_id in pois else "Unknown"
result.setdefault(d.listing_id, []).append(
POIDistanceResponse(
poi_id=d.poi_id,
poi_name=poi_name,
travel_mode=d.travel_mode,
duration_seconds=d.duration_seconds,
distance_meters=d.distance_meters,
)
)
return result
@poi_router.get("/distances")
async def get_distances(
user: Annotated[User, Depends(get_current_user)],

View file

@ -4,6 +4,6 @@ export { fetchListingGeoJSON, refreshListings } from './listingService';
export { streamListingGeoJSON, type StreamingProgress } from './streamingService';
export { fetchTasksForUser, fetchTaskStatus, cancelTask, clearAllTasks, type CancelTaskResponse, type ClearAllTasksResponse } from './taskService';
export { checkBackendHealth, type HealthStatus, type HealthCheckResult } from './healthService';
export { fetchUserPOIs, createPOI, updatePOI, deletePOI, triggerPOICalculation, fetchPOIDistances } from './poiService';
export { fetchUserPOIs, createPOI, updatePOI, deletePOI, triggerPOICalculation, fetchPOIDistances, fetchBulkPOIDistances } from './poiService';
export { fetchDecisions, setDecision, clearDecision } from './decisionService';
export { fetchListingDetail } from './listingDetailService';

View file

@ -62,3 +62,12 @@ export async function fetchPOIDistances(
},
});
}
export async function fetchBulkPOIDistances(
user: AuthUser,
listingType: 'RENT' | 'BUY' = 'RENT'
): Promise<Record<number, POIDistanceInfo[]>> {
return apiRequest<Record<number, POIDistanceInfo[]>>(user, '/api/poi/distances/bulk', {
params: { listing_type: listingType },
});
}