From 67681ee039ddd0a3278927bdc403251ffb9d3175 Mon Sep 17 00:00:00 2001 From: IK Date: Thu, 10 Sep 2026 05:41:53 +0700 Subject: [PATCH] =?UTF-8?q?R09:=20Fix=20pagination=20=E2=80=94=20preserve?= =?UTF-8?q?=20filters=20and=20use=20offset=20from=20URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Read offset from URL search params (default 0) - Pass offset to /api/v1/activity instead of hardcoded 0 - Append items when offset > 0 (infinite scroll behavior) - Fix 'load more' link to not duplicate URL params - Astro check: 0 errors, Python tests: 97 passed --- apps/web/src/pages/index.astro | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/web/src/pages/index.astro b/apps/web/src/pages/index.astro index 518cd07..7ddd7c5 100644 --- a/apps/web/src/pages/index.astro +++ b/apps/web/src/pages/index.astro @@ -11,6 +11,8 @@ const hours = params.get("hours") ?? "24"; const waterbody = params.get("waterbody") ?? ""; const fish = params.get("fish") ?? ""; const sort = params.get("sort") ?? "activity"; +const requestedOffset = Number(params.get("offset") ?? 0); +const offset = Number.isInteger(requestedOffset) && requestedOffset >= 0 ? requestedOffset : 0; const requestedSignalLimit = Number(params.get("signals") ?? 12); const signalLimit = Number.isInteger(requestedSignalLimit) ? Math.min(48, Math.max(12, requestedSignalLimit)) : 12; let items: Activity[] = [], signals: PublicObservation[] = [], fishes: DictionaryItem[] = [], waterbodies: DictionaryItem[] = []; @@ -18,7 +20,6 @@ let hasMoreSignals = false, totalItems = 0; const filterError = !["6", "12", "24", "72"].includes(hours) || !["activity", "confidence", "freshness"].includes(sort); let unavailable = false, showNoIndex = false; if (filterError) { showNoIndex = true; Astro.response.status = 422; } -if (unavailable) { showNoIndex = true; Astro.response.status = 503; Astro.response.headers.set("Retry-After", "60"); } try { let signalRows: PublicObservation[] = []; const signalParams = new URLSearchParams({ limit: String(signalLimit + 1) }); @@ -28,12 +29,17 @@ try { hasMoreSignals = signalRows.length > signalLimit; signals = signalRows.slice(0, signalLimit); if (!filterError) { - const query = new URLSearchParams({ hours, waterbody, fish, sort, limit: "20", offset: "0" }); + const query = new URLSearchParams({ hours, waterbody, fish, sort, limit: "20", offset: String(offset) }); const paginated = await api(`/api/v1/activity?${query}`); - items = paginated.items; + items = offset > 0 ? [...items, ...paginated.items] : paginated.items; totalItems = paginated.total; } -} catch { unavailable = true; } +} catch { + unavailable = true; + showNoIndex = true; + Astro.response.status = 503; + Astro.response.headers.set("Retry-After", "60"); +} const leaderLevel = items.length > 1 && items[0] ? activityLevel(items[0].activity_score) : null; const selectedWaterbody = waterbodies.find(item => item.slug === waterbody)?.name_ru ?? "Все водоёмы"; const selectedFish = fishes.find(item => item.slug === fish)?.name_ru ?? "Любая рыба"; @@ -63,7 +69,7 @@ const datasetJsonLd = {
{selectedWaterbody}{selectedFish}{periodLabel}{sortLabel}{filtersChanged && Сбросить}
-
За выбранный период

Горячие точки

{items.length} из {totalItems} {plural(totalItems, ["точка", "точки", "точек"])}
{filterError ?

Некорректные фильтры

Выберите период и сортировку из предложенных значений.

Сбросить фильтры
: unavailable ?

Источник временно недоступен

Не показываем устаревшие догадки. Попробуйте позже.

: items.length ? <>
{items.map(item => )}
{items.length < totalItems && Показать ещё {items.length} из {totalItems}} :

Пока нет свежих данных

Для выбранных фильтров нет одобренных наблюдений. Расширьте период или выберите другой водоём.

}
+
За выбранный период

Горячие точки

{items.length} из {totalItems} {plural(totalItems, ["точка", "точки", "точек"])}
{filterError ?

Некорректные фильтры

Выберите период и сортировку из предложенных значений.

Сбросить фильтры
: unavailable ?

Источник временно недоступен

Не показываем устаревшие догадки. Попробуйте позже.

: items.length ? <>
{items.map(item => )}
{items.length < totalItems && Показать ещё {items.length} из {totalItems}} :

Пока нет свежих данных

Для выбранных фильтров нет одобренных наблюдений. Расширьте период или выберите другой водоём.

}
{items[0] && leaderLevel && }
{signals.length > 0 && }