Профиль: догрузка истории и счётчик партий в шапке

История запрашивалась без limit/offset, поэтому бэкенд отдавал первые 20 партий, а
страницы рисовали их и молча игнорировали total: у игрока с 40 партиями половина
истории просто не существовала — ни кнопки, ни намёка.

Теперь история грузится страницами по 20, под списком — «Показать ещё». Постранично,
а не одним большим запросом: у эндпоинта потолок limit=100, и на 101-й партии
обрезка вернулась бы. Кнопка живёт в самом компоненте истории, поэтому появилась
сразу и в своём профиле, и в чужом, и в обоих режимах подробности.

Общее число партий вынесено в шапку профиля, к нику. Берём его из статистики, а не
из total истории: в режиме «только лучшая партия» total равен единице, и счётчик
показывал бы «Партий: 1».

#30

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BoiJK9ux8peeyjLb8TYjFf
This commit is contained in:
2026-09-09 20:27:38 +03:00
co-authored by Claude Opus 5
parent f3067b1f89
commit f2aaa2a15e
4 changed files with 76 additions and 15 deletions
+20 -7
View File
@@ -1,4 +1,4 @@
import { keepPreviousData, useQuery } from "@tanstack/react-query";
import { keepPreviousData, useInfiniteQuery, useQuery } from "@tanstack/react-query";
import { useEffect, useState } from "react";
import { api, unwrap } from "../api/client";
@@ -15,18 +15,31 @@ function useDebounced<T>(value: T, ms = 100): T {
return debounced;
}
/** История партий игрока. Режим и подробность приходят вместе со списком:
* это витрина ВЛАДЕЛЬЦА профиля, её видят и гости. */
const HISTORY_PAGE = 20;
/** История партий игрока страницами по 20 («Показать ещё»).
*
* Режим и подробность приходят вместе со списком: это витрина ВЛАДЕЛЬЦА профиля,
* её видят и гости. Постранично, а не одним большим запросом: у эндпоинта потолок
* limit=100, и на 101-й партии обрезка вернулась бы. */
export function useUserMatches(userId: number | null) {
return useQuery({
queryKey: userId ? qk.userMatches(userId) : ["userMatches", "none"],
return useInfiniteQuery({
queryKey: userId != null ? qk.userMatches(userId) : ["userMatches", "none"],
enabled: userId != null,
queryFn: async () =>
initialPageParam: 0,
queryFn: async ({ pageParam }) =>
unwrap(
await api.GET("/api/users/{user_id}/matches", {
params: { path: { user_id: userId as number } },
params: {
path: { user_id: userId as number },
query: { limit: HISTORY_PAGE, offset: pageParam as number },
},
}),
),
getNextPageParam: (last, pages) => {
const loaded = pages.reduce((n, p) => n + p.items.length, 0);
return loaded < last.total ? loaded : undefined;
},
});
}