mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 03:59:50 +02:00
feat: jump to position for current season
This commit is contained in:
1 parent
81aec6bad2
commit
551ef79f03
1 file changed
+127
-5
@@ -1,5 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { blackA, orangeDark } from '@radix-ui/colors';
|
||||||
import {
|
import {
|
||||||
CaretLeftIcon,
|
CaretLeftIcon,
|
||||||
CaretRightIcon,
|
CaretRightIcon,
|
||||||
@@ -19,6 +20,7 @@ import { ChangeEvent, useEffect, useRef, useState } from 'react';
|
|||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { BlitzkriegRatingsLeaderboardEntry } from '../../../../scripts/buildRatingsLeaderboard';
|
import { BlitzkriegRatingsLeaderboardEntry } from '../../../../scripts/buildRatingsLeaderboard';
|
||||||
|
import { RatingsPlayer } from '../../../commands/ratings';
|
||||||
import * as Leaderboard from '../../../components/Leaderboard';
|
import * as Leaderboard from '../../../components/Leaderboard';
|
||||||
import PageWrapper from '../../../components/PageWrapper';
|
import PageWrapper from '../../../components/PageWrapper';
|
||||||
import { LEAGUES } from '../../../constants/leagues';
|
import { LEAGUES } from '../../../constants/leagues';
|
||||||
@@ -43,6 +45,7 @@ import { withCORSProxy } from '../../../core/blitzkrieg/withCORSProxy';
|
|||||||
import { noArrows } from './page.css';
|
import { noArrows } from './page.css';
|
||||||
|
|
||||||
const ROWS_OPTIONS = [5, 10, 15, 25, 30];
|
const ROWS_OPTIONS = [5, 10, 15, 25, 30];
|
||||||
|
const SEEDING_SIZE = 2 ** 7;
|
||||||
|
|
||||||
type UsernameCache = Record<Region, Record<number, string | null>>;
|
type UsernameCache = Record<Region, Record<number, string | null>>;
|
||||||
type ClanCache = Record<Region, Record<number, string | undefined>>;
|
type ClanCache = Record<Region, Record<number, string | undefined>>;
|
||||||
@@ -91,6 +94,9 @@ export default function Page() {
|
|||||||
const [searchResults, setSearchResults] = useState<
|
const [searchResults, setSearchResults] = useState<
|
||||||
(AccountListItem & { number: number })[] | undefined
|
(AccountListItem & { number: number })[] | undefined
|
||||||
>(undefined);
|
>(undefined);
|
||||||
|
const [loadingProgress, setLoadingProgress] = useState<
|
||||||
|
[number, number] | null
|
||||||
|
>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// league caching
|
// league caching
|
||||||
@@ -193,6 +199,8 @@ export default function Page() {
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return neighbors;
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -245,15 +253,85 @@ export default function Page() {
|
|||||||
}
|
}
|
||||||
}, [page]);
|
}, [page]);
|
||||||
|
|
||||||
const handleJumpToPosition = () => {
|
const handleJumpToPosition = async () => {
|
||||||
if (!players || !ratingsInfo || ratingsInfo?.detail) return;
|
if (!players || !ratingsInfo || ratingsInfo?.detail) return;
|
||||||
|
|
||||||
const rawPosition = positionInput.current!.valueAsNumber - 1;
|
const rawPosition = positionInput.current!.valueAsNumber - 1;
|
||||||
const position = Math.max(0, Math.min(rawPosition, ratingsInfo.count - 1));
|
const targetPosition = Math.max(
|
||||||
setPage(Math.floor(position / rowsPerPage));
|
0,
|
||||||
|
Math.min(rawPosition, ratingsInfo.count - 1),
|
||||||
|
);
|
||||||
|
|
||||||
if (players) {
|
if (season === null) {
|
||||||
setHighlightedPlayerId(players[position].id);
|
const playerEntries = Object.entries(players);
|
||||||
|
let closest: BlitzkriegRatingsLeaderboardEntry | null = null;
|
||||||
|
let closestPosition: number | null = null;
|
||||||
|
let closestPositionDistance = Infinity;
|
||||||
|
|
||||||
|
playerEntries.forEach(([positionAsString, player]) => {
|
||||||
|
const position = parseInt(positionAsString);
|
||||||
|
const distance = Math.abs(position - targetPosition);
|
||||||
|
|
||||||
|
if (distance < closestPositionDistance) {
|
||||||
|
closestPositionDistance = distance;
|
||||||
|
closestPosition = position;
|
||||||
|
closest = player;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (closest === null || closestPosition === null) return;
|
||||||
|
|
||||||
|
if (closestPositionDistance === 0) {
|
||||||
|
setHighlightedPlayerId(
|
||||||
|
(closest as BlitzkriegRatingsLeaderboardEntry).id,
|
||||||
|
);
|
||||||
|
setPage(Math.floor(targetPosition / rowsPerPage));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1 going down and -1 going up
|
||||||
|
const loadingDirection = Math.sign(targetPosition - closestPosition);
|
||||||
|
let seedingPlayer = (closest as BlitzkriegRatingsLeaderboardEntry).id;
|
||||||
|
let targetPositionAcquired = false;
|
||||||
|
let neighbors: RatingsPlayer[];
|
||||||
|
|
||||||
|
setLoadingProgress([0, closestPositionDistance]);
|
||||||
|
|
||||||
|
while (!targetPositionAcquired) {
|
||||||
|
console.log('starting');
|
||||||
|
neighbors = await cacheNeighbors(seedingPlayer, SEEDING_SIZE);
|
||||||
|
console.log('done');
|
||||||
|
seedingPlayer = neighbors.at(loadingDirection === -1 ? 0 : -1)!.spa_id;
|
||||||
|
|
||||||
|
if (loadingDirection === 1) {
|
||||||
|
targetPositionAcquired =
|
||||||
|
targetPosition <= neighbors.at(-1)!.number - 1;
|
||||||
|
setLoadingProgress([
|
||||||
|
Math.abs(neighbors.at(-1)!.number - 1 - closestPosition),
|
||||||
|
closestPositionDistance,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
targetPositionAcquired = targetPosition >= neighbors[0].number - 1;
|
||||||
|
setLoadingProgress([
|
||||||
|
Math.abs(neighbors[0].number - 1 - closestPosition),
|
||||||
|
closestPositionDistance,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoadingProgress(null);
|
||||||
|
setPage(Math.floor(targetPosition / rowsPerPage));
|
||||||
|
setHighlightedPlayerId(
|
||||||
|
neighbors!.find((neighbor) => neighbor.number - 1 === targetPosition)!
|
||||||
|
.spa_id,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setPage(Math.floor(targetPosition / rowsPerPage));
|
||||||
|
|
||||||
|
if (players) {
|
||||||
|
setHighlightedPlayerId(players[targetPosition].id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const [jumpToPositionOpen, setJumpToPositionOpen] = useState(false);
|
const [jumpToPositionOpen, setJumpToPositionOpen] = useState(false);
|
||||||
@@ -804,6 +882,50 @@ export default function Page() {
|
|||||||
</Leaderboard.Root>
|
</Leaderboard.Root>
|
||||||
|
|
||||||
<PageTurner />
|
<PageTurner />
|
||||||
|
|
||||||
|
{loadingProgress !== null && (
|
||||||
|
<Flex
|
||||||
|
style={{
|
||||||
|
position: 'fixed',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
background: blackA.blackA10,
|
||||||
|
zIndex: 2,
|
||||||
|
}}
|
||||||
|
gap="4"
|
||||||
|
justify="center"
|
||||||
|
align="center"
|
||||||
|
direction="column"
|
||||||
|
>
|
||||||
|
<Text>
|
||||||
|
Loading {loadingProgress[0]} of {loadingProgress[1]} players...
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: 16,
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: 256,
|
||||||
|
borderRadius: 8,
|
||||||
|
backgroundColor: orangeDark.orange2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: '100%',
|
||||||
|
transitionDuration: '200ms',
|
||||||
|
width: `${Math.round(
|
||||||
|
(loadingProgress[0] / loadingProgress[1]) * 100,
|
||||||
|
)}%`,
|
||||||
|
backgroundColor: orangeDark.orange9,
|
||||||
|
borderRadius: 8,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user