Рейтинг с #80 один на всё приложение: завершённая или удалённая партия двигает топ, историю и профили всех, кто играл после неё, и страницы других групп. Событие match по-прежнему идёт группе партии, остальным активным игрокам — ratings без подробностей о партии. Фронт по обоим сбрасывает все рейтинговые витрины (invalidateRatingViews); participant_ids больше не нужен. #88 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LqSoRj99iwVEH5U5fnZgsd
60 lines
2.8 KiB
TypeScript
60 lines
2.8 KiB
TypeScript
import type { QueryClient } from "@tanstack/react-query";
|
|
|
|
export const qk = {
|
|
me: ["me"] as const,
|
|
adminMe: ["adminMe"] as const,
|
|
home: ["home"] as const,
|
|
leaderboard: ["leaderboard"] as const,
|
|
expansions: ["expansions"] as const,
|
|
factions: ["factions"] as const,
|
|
myStats: ["myStats"] as const,
|
|
publicProfile: (id: number) => ["publicProfile", id] as const,
|
|
userMatches: (id: number) => ["userMatches", id] as const,
|
|
userSearch: (q: string, limit: number) => ["userSearch", q, limit] as const,
|
|
groups: ["groups"] as const,
|
|
group: (id: number) => ["group", id] as const,
|
|
groupFactions: (id: number) => ["group", id, "factions"] as const,
|
|
groupMembers: (id: number) => ["group", id, "members"] as const,
|
|
groupMatches: (id: number) => ["group", id, "matches"] as const,
|
|
groupStats: (id: number) => ["group", id, "stats"] as const,
|
|
match: (id: number) => ["match", id] as const,
|
|
authConfig: ["authConfig"] as const,
|
|
invitations: ["invitations"] as const,
|
|
notifications: ["notifications"] as const,
|
|
announcements: ["announcements"] as const,
|
|
devUsers: ["devUsers"] as const,
|
|
adminUsers: ["adminUsers"] as const,
|
|
adminGroups: ["adminGroups"] as const,
|
|
adminMatches: ["adminMatches"] as const,
|
|
adminLogs: ["adminLogs"] as const,
|
|
adminAchievements: ["adminAchievements"] as const,
|
|
adminAnnouncements: ["adminAnnouncements"] as const,
|
|
};
|
|
|
|
/**
|
|
* Ключи, которые протухают от любой завершённой партии: рейтинг общий и считается по
|
|
* всей истории (#80), так что партия двигает топ, историю и профили всех, кто играл
|
|
* после неё. Поэтому инвалидируем по префиксу. Один список на SSE-обработчик и на
|
|
* мутации партии — иначе переименование ключа тихо разойдётся с местами, где он
|
|
* написан строкой.
|
|
*/
|
|
export const matchAffectedKeys = [
|
|
qk.home,
|
|
qk.leaderboard,
|
|
qk.myStats,
|
|
["userMatches"],
|
|
["publicProfile"],
|
|
] as const;
|
|
|
|
/**
|
|
* Все рейтинговые витрины, включая статистику любой группы: рейтинг игроков в ней
|
|
* общий, так что его двигает и партия другой группы (#88). Перезапрашиваются только
|
|
* открытые на экране запросы, остальные лишь помечаются устаревшими.
|
|
*/
|
|
export function invalidateRatingViews(qc: QueryClient) {
|
|
for (const key of matchAffectedKeys) qc.invalidateQueries({ queryKey: key });
|
|
qc.invalidateQueries({
|
|
predicate: (q) => q.queryKey[0] === "group" && q.queryKey[2] === "stats",
|
|
});
|
|
}
|