diff --git a/frontend/hooks/useLeafletMap.ts b/frontend/hooks/useLeafletMap.ts index 6ee22bae..39c7fa71 100644 --- a/frontend/hooks/useLeafletMap.ts +++ b/frontend/hooks/useLeafletMap.ts @@ -8,7 +8,7 @@ import { CitySummary, NearbyStation, } from "@/lib/dashboard-types"; -import { pickAnkaraNearbyStations } from "@/lib/dashboard-utils"; +import { pickMapNearbyStations } from "@/lib/dashboard-utils"; interface UseLeafletMapArgs { cities: CityListItem[]; @@ -325,13 +325,7 @@ export function useLeafletMap({ function renderNearbyStations(detail: CityDetail, preserveView = false) { layer.clearLayers(); - const allNearby = Array.isArray(detail.mgm_nearby) - ? detail.mgm_nearby - : []; - const nearbyStations = - String(detail.name || "").toLowerCase() === "ankara" - ? pickAnkaraNearbyStations(allNearby) - : allNearby; + const nearbyStations = pickMapNearbyStations(detail); if (!nearbyStations.length) { if (!preserveView && detail.lat != null && detail.lon != null) { diff --git a/frontend/lib/dashboard-utils.ts b/frontend/lib/dashboard-utils.ts index 80f41f93..c71f6f0e 100644 --- a/frontend/lib/dashboard-utils.ts +++ b/frontend/lib/dashboard-utils.ts @@ -822,6 +822,82 @@ export function pickAnkaraNearbyStations(stations: NearbyStation[]) { return picks.length ? picks : stations; } +function distanceKm( + lat1: number, + lon1: number, + lat2: number, + lon2: number, +) { + const toRad = (deg: number) => (deg * Math.PI) / 180; + const dLat = toRad(lat2 - lat1); + const dLon = toRad(lon2 - lon1); + const a = + Math.sin(dLat / 2) ** 2 + + Math.cos(toRad(lat1)) * + Math.cos(toRad(lat2)) * + Math.sin(dLon / 2) ** 2; + return 6371 * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); +} + +export function pickMapNearbyStations(detail: CityDetail) { + const stations = Array.isArray(detail.mgm_nearby) ? detail.mgm_nearby : []; + const city = String(detail.name || detail.display_name || "") + .trim() + .toLowerCase(); + + if (city === "ankara") { + return pickAnkaraNearbyStations(stations); + } + + if (city === "istanbul" && Number.isFinite(detail.lat) && Number.isFinite(detail.lon)) { + const preferredTokens = ["havalimani", "havalimanı", "arnavutkoy", "arnavutköy"]; + const scored = stations + .map((station) => { + const lat = Number(station.lat); + const lon = Number(station.lon); + if (!Number.isFinite(lat) || !Number.isFinite(lon)) { + return null; + } + const name = String(station.name || "").toLowerCase(); + const preferred = preferredTokens.some((token) => name.includes(token)); + return { + preferred, + station, + km: distanceKm(Number(detail.lat), Number(detail.lon), lat, lon), + }; + }) + .filter(Boolean) as Array<{ + preferred: boolean; + station: NearbyStation; + km: number; + }>; + + const closePreferred = scored + .filter((row) => row.preferred && row.km <= 20) + .sort((a, b) => a.km - b.km) + .map((row) => row.station); + + const closeFallback = scored + .filter((row) => row.km <= 12) + .sort((a, b) => a.km - b.km) + .map((row) => row.station); + + const merged = [...closePreferred, ...closeFallback].filter( + (station, index, list) => + list.findIndex( + (row) => + row.name === station.name && + row.lat === station.lat && + row.lon === station.lon, + ) === index, + ); + + return merged.slice(0, 5); + } + + return stations; +} + export function getFutureSlice(detail: CityDetail, dateStr: string) { const hourly = detail.hourly_next_48h || {}; const times = hourly.times || [];