Cap smart feed results and add search fetch

This commit is contained in:
Your Name 2025-12-26 00:20:04 -05:00
parent 80b266ca56
commit 40b1924a77
1 changed files with 68 additions and 4 deletions

View File

@ -1,5 +1,5 @@
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { fetchPosts, fetchSmartFeed } from "../../api/client"; import { fetchPosts, fetchSmartFeed, fetchUnifiedSearch } from "../../api/client";
import { categoryCode, matchesSubFilter, matchesTimeFilter } from "./mapFilter"; import { categoryCode, matchesSubFilter, matchesTimeFilter } from "./mapFilter";
import { getCoords, getViewFromMap, haversineKm } from "./mapGeo"; import { getCoords, getViewFromMap, haversineKm } from "./mapGeo";
import { createMarkerForPost, createSimpleMarkerForPost } from "./markerManager"; import { createMarkerForPost, createSimpleMarkerForPost } from "./markerManager";
@ -105,6 +105,32 @@ function filterByBounds(posts, map) {
}); });
} }
function getPostTimeMs(p) {
const raw = p?.created_at || p?.CreatedAt || p?.createdAt || p?.published_at;
if (!raw) return 0;
const d = raw instanceof Date ? raw : new Date(String(raw));
if (Number.isNaN(d.getTime())) return 0;
return d.getTime();
}
function prunePosts(posts, center, maxCount) {
if (!Array.isArray(posts) || posts.length <= maxCount) return posts || [];
const [centerLon, centerLat] = center || [];
const now = Date.now();
const scored = posts.map((p) => {
const coords = getCoords(p);
let dist = 99999;
if (coords && Number.isFinite(centerLat) && Number.isFinite(centerLon)) {
dist = haversineKm(centerLat, centerLon, coords[1], coords[0]);
}
const ageH = Math.max(0, (now - getPostTimeMs(p)) / 3600000);
const score = dist + ageH * 0.4;
return { p, score };
});
scored.sort((a, b) => a.score - b.score);
return scored.slice(0, maxCount).map((x) => x.p);
}
export function usePostsEngine({ export function usePostsEngine({
mapRef, mapRef,
viewParams, viewParams,
@ -541,6 +567,7 @@ export function usePostsEngine({
const resolvedView = const resolvedView =
viewParams && viewParams.center ? viewParams : getViewFromMap(mapObj); viewParams && viewParams.center ? viewParams : getViewFromMap(mapObj);
if (!resolvedView?.center) return; if (!resolvedView?.center) return;
if ((searchQuery || "").trim()) return;
// If expanded overlay is open: delay fetch (do NOT disturb UI) // If expanded overlay is open: delay fetch (do NOT disturb UI)
if (expandedElRef?.current) { if (expandedElRef?.current) {
@ -621,7 +648,7 @@ export function usePostsEngine({
lat, lat,
lon: lng, lon: lng,
radius_km: radiusKm, radius_km: radiusKm,
limit: 80, limit: 50,
bounds, bounds,
username: username || undefined, username: username || undefined,
}); });
@ -662,7 +689,7 @@ export function usePostsEngine({
} }
} }
allPostsRef.current = Array.from(byId.values()); allPostsRef.current = prunePosts(Array.from(byId.values()), [lng, lat], 180);
lastFetchRef.current = { center: [...resolvedView.center], radiusKm, filterKey, timeFilter, bounds }; lastFetchRef.current = { center: [...resolvedView.center], radiusKm, filterKey, timeFilter, bounds };
// Smooth update: sync markers/clusters + wall without clearing everything // Smooth update: sync markers/clusters + wall without clearing everything
@ -698,6 +725,41 @@ export function usePostsEngine({
}; };
}, [viewParams, mapReady, mainFilter, subFilter, mapRef, timeFilter, expandedElRef, refreshVisibleAndMarkers, computeVisible, onAutoWidenTimeFilter, syncMarkers, username]); }, [viewParams, mapReady, mainFilter, subFilter, mapRef, timeFilter, expandedElRef, refreshVisibleAndMarkers, computeVisible, onAutoWidenTimeFilter, syncMarkers, username]);
useEffect(() => {
const q = (searchQuery || "").trim();
if (!q) return;
let cancelled = false;
async function runSearch() {
try {
const map = mapRef.current;
let lat;
let lon;
try {
const center = map?.getCenter?.();
lat = center?.lat;
lon = center?.lng;
} catch {}
const data = await fetchUnifiedSearch(q, {
type: "posts",
lat,
lon,
radius_km: viewParams?.radiusKm,
limit: 80,
});
if (cancelled) return;
const posts = Array.isArray(data?.posts) ? data.posts : [];
allPostsRef.current = prunePosts(posts, [lon, lat], 120);
refreshVisibleAndMarkers(timeFilter);
} catch {}
}
runSearch();
return () => {
cancelled = true;
};
}, [searchQuery, viewParams, mapRef, refreshVisibleAndMarkers, timeFilter]);
useEffect(() => { useEffect(() => {
const map = mapRef.current; const map = mapRef.current;
if (!map) return; if (!map) return;
@ -720,7 +782,9 @@ export function usePostsEngine({
const exists = (allPostsRef.current || []).some((x) => getPostKey(x) === key); const exists = (allPostsRef.current || []).some((x) => getPostKey(x) === key);
if (exists) return; if (exists) return;
} }
allPostsRef.current = [p, ...allPostsRef.current]; const map = mapRef.current;
const center = map?.getCenter?.();
allPostsRef.current = prunePosts([p, ...allPostsRef.current], [center?.lng, center?.lat], 200);
const catCode = categoryCode(mainFilter); const catCode = categoryCode(mainFilter);
if (catCode) { if (catCode) {