mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: migrate performance
This commit is contained in:
1 parent
b31c7a6738
commit
8d51ce2bea
20 files changed
+122
-149
No files matched your search
Vendored
+1
@@ -104,6 +104,7 @@
|
|||||||
"mmnow",
|
"mmnow",
|
||||||
"modeltransform",
|
"modeltransform",
|
||||||
"MURICA",
|
"MURICA",
|
||||||
|
"nanostores",
|
||||||
"NEGATIVEX",
|
"NEGATIVEX",
|
||||||
"NEGATIVEY",
|
"NEGATIVEY",
|
||||||
"NEGATIVEZ",
|
"NEGATIVEZ",
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ const args = [
|
|||||||
'--ts_proto_opt=oneof=unions-value',
|
'--ts_proto_opt=oneof=unions-value',
|
||||||
'--ts_proto_opt=removeEnumPrefix=true',
|
'--ts_proto_opt=removeEnumPrefix=true',
|
||||||
'--ts_proto_opt=unrecognizedEnum=false',
|
'--ts_proto_opt=unrecognizedEnum=false',
|
||||||
|
'--ts_proto_opt=snakeToCamel=false',
|
||||||
'--ts_proto_out=.',
|
'--ts_proto_out=.',
|
||||||
...files.map((file) => `${ROOT}/${file}`),
|
...files.map((file) => `${ROOT}/${file}`),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
import {
|
|
||||||
formatCompact,
|
|
||||||
TANK_CLASSES,
|
|
||||||
TankClass,
|
|
||||||
Tier,
|
|
||||||
TIER_ROMAN_NUMERALS,
|
|
||||||
} from '@blitzkit/core';
|
|
||||||
import strings from '@blitzkit/core/lang/en-US.json';
|
|
||||||
import { ResponsiveBar } from '@nivo/bar';
|
|
||||||
import { Box, Flex, Heading } from '@radix-ui/themes';
|
|
||||||
import { times } from 'lodash-es';
|
|
||||||
import { use } from 'react';
|
|
||||||
import { nivoTheme } from '../../../../core/nivo/theme';
|
|
||||||
|
|
||||||
export function TierBreakdown() {
|
|
||||||
const awaitedAverageDefinitionsArray = use(averageDefinitionsArray);
|
|
||||||
const awaitedTankDefinitions = use(tankDefinitions);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex justify="center" py="6">
|
|
||||||
<Flex direction="column" flexGrow="1" gap="4" maxWidth="640px">
|
|
||||||
<Heading ml="2" size="4">
|
|
||||||
Players (30d) per tier
|
|
||||||
</Heading>
|
|
||||||
|
|
||||||
<Box height="320px" width="100%">
|
|
||||||
<ResponsiveBar
|
|
||||||
{...nivoTheme}
|
|
||||||
data={times(10, (index) => {
|
|
||||||
const tier = (index + 1) as Tier;
|
|
||||||
const tierTanks = awaitedAverageDefinitionsArray.filter(
|
|
||||||
({ id }) => awaitedTankDefinitions[id]?.tier === tier,
|
|
||||||
);
|
|
||||||
const populations: Record<TankClass, number> = {
|
|
||||||
'AT-SPG': 0,
|
|
||||||
heavyTank: 0,
|
|
||||||
lightTank: 0,
|
|
||||||
mediumTank: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
tierTanks.forEach((stats) => {
|
|
||||||
const tank = awaitedTankDefinitions[stats.id];
|
|
||||||
populations[tank.class] +=
|
|
||||||
stats.mu.battles * stats.samples.d_30;
|
|
||||||
});
|
|
||||||
|
|
||||||
TANK_CLASSES.forEach((tankClass) => {
|
|
||||||
populations[tankClass] = Math.round(populations[tankClass]);
|
|
||||||
});
|
|
||||||
|
|
||||||
return { tier: TIER_ROMAN_NUMERALS[tier], ...populations };
|
|
||||||
})}
|
|
||||||
keys={[...TANK_CLASSES].reverse()}
|
|
||||||
indexBy="tier"
|
|
||||||
colors={{ scheme: 'dark2' }}
|
|
||||||
label={(d) => formatCompact(d.value as number)}
|
|
||||||
margin={{ right: 96, bottom: 20, left: 40 }}
|
|
||||||
legendLabel={(d) =>
|
|
||||||
strings.common.tank_class_short[d.id as TankClass]
|
|
||||||
}
|
|
||||||
axisLeft={{
|
|
||||||
tickSize: 0,
|
|
||||||
format: (value) => formatCompact(value as number),
|
|
||||||
}}
|
|
||||||
axisBottom={{ tickSize: 0 }}
|
|
||||||
legends={[
|
|
||||||
{
|
|
||||||
dataFrom: 'keys',
|
|
||||||
anchor: 'bottom-right',
|
|
||||||
direction: 'column',
|
|
||||||
translateX: 120,
|
|
||||||
itemsSpacing: 4,
|
|
||||||
itemWidth: 100,
|
|
||||||
itemHeight: 20,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import { Controls } from '../../../../../website/src/components/Performance/Controls';
|
||||||
|
import { Info } from '../../../../../website/src/components/Performance/PerformanceInfo';
|
||||||
|
import { TankTable } from '../../../../../website/src/components/Performance/Table';
|
||||||
import { PageWrapper } from '../../../components/PageWrapper';
|
import { PageWrapper } from '../../../components/PageWrapper';
|
||||||
import { Controls } from './components/Controls';
|
|
||||||
import { Info } from './components/Info';
|
|
||||||
import { TankTable } from './components/Table';
|
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -7,5 +7,9 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"include": ["src/**/*", ".next/types/**/*.ts"]
|
"include": [
|
||||||
|
"src/**/*",
|
||||||
|
".next/types/**/*.ts",
|
||||||
|
"../website/src/components/Performance/PerformanceInfo.tsx"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
File renamed without changes.
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import { FilterControl } from '../../../../../../website/src/components/TankSearch/components/FilterControl';
|
import { FilterControl } from '../TankSearch/components/FilterControl';
|
||||||
import { PlayerCountControl } from './PlayerCountControl';
|
import { PlayerCountControl } from './PlayerCountControl';
|
||||||
|
|
||||||
export function Controls() {
|
export function Controls() {
|
||||||
+3
-3
@@ -4,12 +4,12 @@ import {
|
|||||||
CaretUpIcon,
|
CaretUpIcon,
|
||||||
} from '@radix-ui/react-icons';
|
} from '@radix-ui/react-icons';
|
||||||
import { Flex, IconButton, Table } from '@radix-ui/themes';
|
import { Flex, IconButton, Table } from '@radix-ui/themes';
|
||||||
import { StickyColumnHeaderCell } from '../../../../components/StickyColumnHeaderCell';
|
import { TankPerformanceSort } from '../../stores/tankPerformanceSort';
|
||||||
import * as TankPerformanceSort from '../../../../stores/tankPerformanceSort';
|
|
||||||
import {
|
import {
|
||||||
TankPerformanceSortTypeNames,
|
TankPerformanceSortTypeNames,
|
||||||
TankPerformanceSortTypeNamesArray,
|
TankPerformanceSortTypeNamesArray,
|
||||||
} from '../../../../stores/tankPerformanceSort/constants';
|
} from '../../stores/tankPerformanceSort/constants';
|
||||||
|
import { StickyColumnHeaderCell } from '../StickyColumnHeaderCell';
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
const sort = TankPerformanceSort.use();
|
const sort = TankPerformanceSort.use();
|
||||||
+1
-1
@@ -9,7 +9,7 @@ import { Callout, Flex } from '@radix-ui/themes';
|
|||||||
const discoveredIdsDefinitions = await fetchDiscoveredIdsDefinitions();
|
const discoveredIdsDefinitions = await fetchDiscoveredIdsDefinitions();
|
||||||
const averageDefinitions = await fetchAverageDefinitions();
|
const averageDefinitions = await fetchAverageDefinitions();
|
||||||
|
|
||||||
export function Info() {
|
export function PerformanceInfo() {
|
||||||
const samples = discoveredIdsDefinitions.count;
|
const samples = discoveredIdsDefinitions.count;
|
||||||
const minutesAgo = Math.floor(
|
const minutesAgo = Math.floor(
|
||||||
(Date.now() - averageDefinitions.time) / (1000 * 60),
|
(Date.now() - averageDefinitions.time) / (1000 * 60),
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
import { Flex, Select, Text } from '@radix-ui/themes';
|
import { Flex, Select, Text } from '@radix-ui/themes';
|
||||||
import * as TankPerformancePersistent from '../../../../stores/tankPerformancePersistent';
|
import { TankPerformancePersistent } from '../../stores/tankPerformancePersistent';
|
||||||
import { PlayerCountPeriod } from '../../../../stores/tankPerformancePersistent/constants';
|
import { PlayerCountPeriod } from '../../stores/tankPerformancePersistent/constants';
|
||||||
|
|
||||||
export function PlayerCountControl() {
|
export function PlayerCountControl() {
|
||||||
const playerCountPeriod = TankPerformancePersistent.use(
|
const playerCountPeriod = TankPerformancePersistent.use(
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
import { Skeleton, Table } from '@radix-ui/themes';
|
import { Skeleton, Table } from '@radix-ui/themes';
|
||||||
import { times } from 'lodash-es';
|
import { times } from 'lodash-es';
|
||||||
import { memo, useRef } from 'react';
|
import { memo, useRef } from 'react';
|
||||||
import { useIntersection } from '../../../../hooks/useIntersection';
|
import { useIntersection } from '../../hooks/useIntersection';
|
||||||
import { TankPerformanceSortTypeNamesArray } from '../../../../stores/tankPerformanceSort/constants';
|
import { TankPerformanceSortTypeNamesArray } from '../../stores/tankPerformanceSort/constants';
|
||||||
|
|
||||||
interface RowLoaderProps {
|
interface RowLoaderProps {
|
||||||
onIntersection?: () => void;
|
onIntersection?: () => void;
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import { Flex } from '@radix-ui/themes';
|
import { Flex } from '@radix-ui/themes';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
import { StickyTableRoot } from '../../../../components/StickyTableRoot';
|
import { StickyTableRoot } from '../StickyTableRoot';
|
||||||
import { BodyLoader } from './BodyLoader';
|
import { BodyLoader } from './BodyLoader';
|
||||||
import { Header } from './Header';
|
import { Header } from './Header';
|
||||||
import { Tanks } from './Tanks';
|
import { Tanks } from './Tanks';
|
||||||
+8
-7
@@ -1,22 +1,23 @@
|
|||||||
import {
|
import {
|
||||||
TankDefinition,
|
TankDefinition,
|
||||||
averageDefinitions,
|
fetchAverageDefinitions,
|
||||||
formatCompact,
|
formatCompact,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { Table } from '@radix-ui/themes';
|
import { Table } from '@radix-ui/themes';
|
||||||
import { memo, use } from 'react';
|
import { memo } from 'react';
|
||||||
import { TankRowHeaderCell } from '../../../../components/TankRowHeaderCell';
|
import { useAveragesExclusionRatio } from '../../hooks/useAveragesExclusionRatio';
|
||||||
import { useAveragesExclusionRatio } from '../../../../hooks/useAveragesExclusionRatio';
|
import { TankPerformancePersistent } from '../../stores/tankPerformancePersistent';
|
||||||
import * as TankPerformancePersistent from '../../../../stores/tankPerformancePersistent';
|
import { TankRowHeaderCell } from '../TankRowHeaderCell';
|
||||||
|
|
||||||
interface TankRowProps {
|
interface TankRowProps {
|
||||||
tank: TankDefinition;
|
tank: TankDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const averageDefinitions = await fetchAverageDefinitions();
|
||||||
|
|
||||||
export const TankRow = memo<TankRowProps>(
|
export const TankRow = memo<TankRowProps>(
|
||||||
({ tank }) => {
|
({ tank }) => {
|
||||||
const awaitedAverageDefinitions = use(averageDefinitions);
|
const averages = averageDefinitions.averages[tank.id];
|
||||||
const averages = awaitedAverageDefinitions.averages[tank.id];
|
|
||||||
const ratio = useAveragesExclusionRatio();
|
const ratio = useAveragesExclusionRatio();
|
||||||
const playerCountPeriod = TankPerformancePersistent.use(
|
const playerCountPeriod = TankPerformancePersistent.use(
|
||||||
(state) => state.playerCountPeriod,
|
(state) => state.playerCountPeriod,
|
||||||
+32
-19
@@ -1,6 +1,12 @@
|
|||||||
|
import { fetchAverageDefinitions, fetchTankDefinitions } from '@blitzkit/core';
|
||||||
|
import { useStore } from '@nanostores/react';
|
||||||
import { Table } from '@radix-ui/themes';
|
import { Table } from '@radix-ui/themes';
|
||||||
import { times } from 'lodash-es';
|
import { times } from 'lodash-es';
|
||||||
import { Suspense, use, useEffect, useMemo, useState } from 'react';
|
import { Suspense, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { filterTank } from '../../core/blitzkit/filterTank';
|
||||||
|
import { $tankFilters } from '../../stores/tankFilters';
|
||||||
|
import { TankPerformancePersistent } from '../../stores/tankPerformancePersistent';
|
||||||
|
import { TankPerformanceSort } from '../../stores/tankPerformanceSort';
|
||||||
import { RowLoader } from './RowLoader';
|
import { RowLoader } from './RowLoader';
|
||||||
import { TankRow } from './TankRow';
|
import { TankRow } from './TankRow';
|
||||||
import { Total } from './Total';
|
import { Total } from './Total';
|
||||||
@@ -8,94 +14,101 @@ import { Total } from './Total';
|
|||||||
const PREVIEW_COUNT = 10;
|
const PREVIEW_COUNT = 10;
|
||||||
const DEFAULT_LOADED_ROWS = 25;
|
const DEFAULT_LOADED_ROWS = 25;
|
||||||
|
|
||||||
|
const tankDefinitions = await fetchTankDefinitions();
|
||||||
|
const averageDefinitionsArray = await fetchAverageDefinitions().then(
|
||||||
|
({ averages }) =>
|
||||||
|
Object.entries(averages).map(([id, average]) => ({
|
||||||
|
id: Number(id),
|
||||||
|
...average,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
export function Tanks() {
|
export function Tanks() {
|
||||||
const awaitedTankDefinitions = use(tankDefinitions);
|
|
||||||
const awaitedAverageDefinitionsArray = use(averageDefinitionsArray);
|
|
||||||
const filters = TankFilters.use();
|
|
||||||
const sort = TankPerformanceSort.use();
|
const sort = TankPerformanceSort.use();
|
||||||
const tankPerformancePersistentStore = TankPerformancePersistent.useStore();
|
const tankPerformancePersistentStore = TankPerformancePersistent.useStore();
|
||||||
|
const filters = useStore($tankFilters);
|
||||||
const tanksSorted = useMemo(() => {
|
const tanksSorted = useMemo(() => {
|
||||||
const { playerCountPeriod } = tankPerformancePersistentStore.getState();
|
const { playerCountPeriod } = tankPerformancePersistentStore.getState();
|
||||||
|
|
||||||
switch (sort.type) {
|
switch (sort.type) {
|
||||||
case 'accuracy':
|
case 'accuracy':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction * (a.mu.hits / a.mu.shots - b.mu.hits / b.mu.shots),
|
sort.direction * (a.mu.hits / a.mu.shots - b.mu.hits / b.mu.shots),
|
||||||
);
|
);
|
||||||
case 'capturePoints':
|
case 'capturePoints':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction *
|
sort.direction *
|
||||||
(a.mu.capture_points / a.mu.battles -
|
(a.mu.capture_points / a.mu.battles -
|
||||||
b.mu.capture_points / b.mu.battles),
|
b.mu.capture_points / b.mu.battles),
|
||||||
);
|
);
|
||||||
case 'damage':
|
case 'damage':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction *
|
sort.direction *
|
||||||
(a.mu.damage_dealt / a.mu.battles -
|
(a.mu.damage_dealt / a.mu.battles -
|
||||||
b.mu.damage_dealt / b.mu.battles),
|
b.mu.damage_dealt / b.mu.battles),
|
||||||
);
|
);
|
||||||
case 'damageRatio':
|
case 'damageRatio':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction *
|
sort.direction *
|
||||||
(a.mu.damage_dealt / a.mu.damage_received -
|
(a.mu.damage_dealt / a.mu.damage_received -
|
||||||
b.mu.damage_dealt / b.mu.damage_received),
|
b.mu.damage_dealt / b.mu.damage_received),
|
||||||
);
|
);
|
||||||
case 'damageTaken':
|
case 'damageTaken':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction *
|
sort.direction *
|
||||||
(a.mu.damage_received / a.mu.battles -
|
(a.mu.damage_received / a.mu.battles -
|
||||||
b.mu.damage_received / b.mu.battles),
|
b.mu.damage_received / b.mu.battles),
|
||||||
);
|
);
|
||||||
case 'hits':
|
case 'hits':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction *
|
sort.direction *
|
||||||
(a.mu.hits / a.mu.battles - b.mu.hits / b.mu.battles),
|
(a.mu.hits / a.mu.battles - b.mu.hits / b.mu.battles),
|
||||||
);
|
);
|
||||||
case 'kills':
|
case 'kills':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction *
|
sort.direction *
|
||||||
(a.mu.frags / a.mu.battles - b.mu.frags / b.mu.battles),
|
(a.mu.frags / a.mu.battles - b.mu.frags / b.mu.battles),
|
||||||
);
|
);
|
||||||
case 'shots':
|
case 'shots':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction *
|
sort.direction *
|
||||||
(a.mu.shots / a.mu.battles - b.mu.shots / b.mu.battles),
|
(a.mu.shots / a.mu.battles - b.mu.shots / b.mu.battles),
|
||||||
);
|
);
|
||||||
case 'players':
|
case 'players':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction *
|
sort.direction *
|
||||||
(a.samples[playerCountPeriod] - b.samples[playerCountPeriod]),
|
(a.samples[playerCountPeriod] - b.samples[playerCountPeriod]),
|
||||||
);
|
);
|
||||||
case 'spots':
|
case 'spots':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction *
|
sort.direction *
|
||||||
(a.mu.spotted / a.mu.battles - b.mu.spotted / b.mu.battles),
|
(a.mu.spotted / a.mu.battles - b.mu.spotted / b.mu.battles),
|
||||||
);
|
);
|
||||||
case 'survival':
|
case 'survival':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction *
|
sort.direction *
|
||||||
(a.mu.survived_battles / a.mu.battles -
|
(a.mu.survived_battles / a.mu.battles -
|
||||||
b.mu.survived_battles / b.mu.battles),
|
b.mu.survived_battles / b.mu.battles),
|
||||||
);
|
);
|
||||||
case 'winrate':
|
case 'winrate':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction *
|
sort.direction *
|
||||||
(a.mu.wins / a.mu.battles - b.mu.wins / b.mu.battles),
|
(a.mu.wins / a.mu.battles - b.mu.wins / b.mu.battles),
|
||||||
);
|
);
|
||||||
case 'xp':
|
case 'xp':
|
||||||
return awaitedAverageDefinitionsArray.sort(
|
return averageDefinitionsArray.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
sort.direction * (a.mu.xp / a.mu.battles - b.mu.xp / b.mu.battles),
|
sort.direction * (a.mu.xp / a.mu.battles - b.mu.xp / b.mu.battles),
|
||||||
);
|
);
|
||||||
@@ -103,7 +116,7 @@ export function Tanks() {
|
|||||||
}, [sort]);
|
}, [sort]);
|
||||||
const tanks = useMemo(() => {
|
const tanks = useMemo(() => {
|
||||||
return tanksSorted.filter((tank) =>
|
return tanksSorted.filter((tank) =>
|
||||||
filterTank(filters, awaitedTankDefinitions[tank.id]),
|
filterTank(filters, tankDefinitions.tanks[tank.id]),
|
||||||
);
|
);
|
||||||
}, [filters, sort]);
|
}, [filters, sort]);
|
||||||
const [loadedRows, setLoadedRows] = useState(DEFAULT_LOADED_ROWS);
|
const [loadedRows, setLoadedRows] = useState(DEFAULT_LOADED_ROWS);
|
||||||
@@ -117,7 +130,7 @@ export function Tanks() {
|
|||||||
<Total tanks={tanks} />
|
<Total tanks={tanks} />
|
||||||
|
|
||||||
{tanks.slice(0, loadedRows).map((averages) => {
|
{tanks.slice(0, loadedRows).map((averages) => {
|
||||||
const tank = awaitedTankDefinitions[averages.id];
|
const tank = tankDefinitions.tanks[averages.id];
|
||||||
|
|
||||||
if (tank === undefined) return null;
|
if (tank === undefined) return null;
|
||||||
|
|
||||||
+14
-11
@@ -1,22 +1,27 @@
|
|||||||
import {
|
import {
|
||||||
averageDefinitions,
|
AverageDefinitionsEntry,
|
||||||
AverageDefinitionsEntryWithId,
|
fetchAverageDefinitions,
|
||||||
BlitzkitStats,
|
|
||||||
formatCompact,
|
formatCompact,
|
||||||
|
type BlitzkitStats,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { Table } from '@radix-ui/themes';
|
import { Table } from '@radix-ui/themes';
|
||||||
import { memo, use, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { StickyRowHeaderCell } from '../../../../components/StickyRowHeaderCell';
|
import { useAveragesExclusionRatio } from '../../hooks/useAveragesExclusionRatio';
|
||||||
import { useAveragesExclusionRatio } from '../../../../hooks/useAveragesExclusionRatio';
|
import { TankPerformancePersistent } from '../../stores/tankPerformancePersistent';
|
||||||
import * as TankPerformancePersistent from '../../../../stores/tankPerformancePersistent';
|
import { StickyRowHeaderCell } from '../StickyRowHeaderCell';
|
||||||
|
|
||||||
|
interface AverageDefinitionsEntryWithId extends AverageDefinitionsEntry {
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
interface TotalProps {
|
interface TotalProps {
|
||||||
tanks: AverageDefinitionsEntryWithId[];
|
tanks: AverageDefinitionsEntryWithId[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const averageDefinitions = await fetchAverageDefinitions();
|
||||||
|
|
||||||
export const Total = memo<TotalProps>(
|
export const Total = memo<TotalProps>(
|
||||||
({ tanks }) => {
|
({ tanks }) => {
|
||||||
const awaitedAverageDefinitions = use(averageDefinitions);
|
|
||||||
const playerCountPeriod = TankPerformancePersistent.use(
|
const playerCountPeriod = TankPerformancePersistent.use(
|
||||||
(state) => state.playerCountPeriod,
|
(state) => state.playerCountPeriod,
|
||||||
);
|
);
|
||||||
@@ -53,9 +58,7 @@ export const Total = memo<TotalProps>(
|
|||||||
</StickyRowHeaderCell>
|
</StickyRowHeaderCell>
|
||||||
<Table.Cell align="center">{(winrate * 100).toFixed(1)}%</Table.Cell>
|
<Table.Cell align="center">{(winrate * 100).toFixed(1)}%</Table.Cell>
|
||||||
<Table.Cell align="center">
|
<Table.Cell align="center">
|
||||||
{formatCompact(
|
{formatCompact(ratio * averageDefinitions.samples[playerCountPeriod])}
|
||||||
ratio * awaitedAverageDefinitions.samples[playerCountPeriod],
|
|
||||||
)}
|
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
<Table.Cell align="center">
|
<Table.Cell align="center">
|
||||||
{Math.round(damage).toLocaleString()}
|
{Math.round(damage).toLocaleString()}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
import { Page } from '.';
|
||||||
|
import ToolLayout from '../../../layouts/ToolLayout.astro';
|
||||||
|
---
|
||||||
|
|
||||||
|
<ToolLayout>
|
||||||
|
<Page client:load />
|
||||||
|
</ToolLayout>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { PageWrapper } from '../../../components/PageWrapper';
|
||||||
|
import { Controls } from '../../../components/Performance/Controls';
|
||||||
|
import { PerformanceInfo } from '../../../components/Performance/PerformanceInfo';
|
||||||
|
import { TankTable } from '../../../components/Performance/Table';
|
||||||
|
import { TankPerformancePersistent } from '../../../stores/tankPerformancePersistent';
|
||||||
|
import { TankPerformanceSort } from '../../../stores/tankPerformanceSort';
|
||||||
|
|
||||||
|
export function Page() {
|
||||||
|
return (
|
||||||
|
<TankPerformanceSort.Provider>
|
||||||
|
<TankPerformancePersistent.Provider>
|
||||||
|
<Content />
|
||||||
|
</TankPerformancePersistent.Provider>
|
||||||
|
</TankPerformanceSort.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Content() {
|
||||||
|
return (
|
||||||
|
<PageWrapper color="jade" noMaxWidth>
|
||||||
|
<PerformanceInfo />
|
||||||
|
<Controls />
|
||||||
|
<TankTable />
|
||||||
|
</PageWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -8,14 +8,13 @@ export interface TankPerformancePersistent {
|
|||||||
playerCountPeriod: PlayerCountPeriod;
|
playerCountPeriod: PlayerCountPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } = createContextualStore(
|
export const TankPerformancePersistent = createContextualStore(() =>
|
||||||
() =>
|
create<TankPerformancePersistent>()(
|
||||||
create<TankPerformancePersistent>()(
|
persist(
|
||||||
persist(
|
subscribeWithSelector<TankPerformancePersistent>(() => ({
|
||||||
subscribeWithSelector<TankPerformancePersistent>(() => ({
|
playerCountPeriod: PlayerCountPeriod.ThisMonth,
|
||||||
playerCountPeriod: PlayerCountPeriod.ThisMonth,
|
})),
|
||||||
})),
|
{ name: 'tank-performance', merge: (a, b) => lodash.merge(b, a) },
|
||||||
{ name: 'tank-performance', merge: (a, b) => lodash.merge(b, a) },
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { TankPerformanceSortType } from '.';
|
import type { TankPerformanceSortType } from '.';
|
||||||
|
|
||||||
export const TankPerformanceSortTypeNames = {
|
export const TankPerformanceSortTypeNames = {
|
||||||
winrate: 'Winrate',
|
winrate: 'Winrate',
|
||||||
|
|||||||
@@ -9,10 +9,9 @@ export interface TankPerformanceSort {
|
|||||||
direction: -1 | 1;
|
direction: -1 | 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } = createContextualStore(
|
export const TankPerformanceSort = createContextualStore(() =>
|
||||||
() =>
|
create<TankPerformanceSort>()(() => ({
|
||||||
create<TankPerformanceSort>()(() => ({
|
type: 'winrate',
|
||||||
type: 'winrate',
|
direction: -1,
|
||||||
direction: -1,
|
})),
|
||||||
})),
|
|
||||||
);
|
);
|
||||||
Reference in new issue
Block a user