diff --git a/src/app/tools/session/page.tsx b/src/app/tools/session/page.tsx index e698fbbeb..80bb32579 100644 --- a/src/app/tools/session/page.tsx +++ b/src/app/tools/session/page.tsx @@ -8,7 +8,7 @@ import { Button } from '../../../components/Button'; import PageWrapper from '../../../components/PageWrapper'; import { SearchBar } from '../../../components/SearchBar'; import { TreeTypeEnum } from '../../../components/Tanks'; -import { REGION_NAMES } from '../../../constants/regions'; +import { REGION_NAMES, Region } from '../../../constants/regions'; import { WARGAMING_APPLICATION_ID } from '../../../constants/wargamingApplicationID'; import calculateWN8 from '../../../core/blitz/calculateWN8'; import { diffNormalizedTankStats } from '../../../core/blitz/diffNormalizedTankStats'; @@ -28,6 +28,9 @@ import { } from '../../../types/tanksStats'; import * as styles from './page.css'; +// 1 once per 5 seconds +const REFRESH_RATE = 1 / 5; + export default function Page() { const input = useRef(null); const [searchResults, setSearchResults] = useState< @@ -45,63 +48,90 @@ export default function Page() { 500, ); const session = useSession(); + const tankStatsArray = session.isTracking + ? (Object.values(session.tankStats) as IndividualTankStats[]) + : []; + const since = session.isTracking ? new Date(session.time) : undefined; const [diff, setDiff] = useState< | { - stats: IndividualTankStats; - tankopedia?: TankopediaEntry; - career: IndividualTankStats; - currentWN8?: number; - careerWN8?: number; - }[] + careerWN8: number; + + list: { + stats: IndividualTankStats; + tankopedia?: TankopediaEntry; + career: IndividualTankStats; + currentWN8?: number; + careerWN8?: number; + }[]; + } | undefined >(undefined); - useEffect(() => { - (async () => { - if (session.isTracking) { - const { id, region } = session; - const careerRaw = await getWargamingResponse( - `https://api.wotblitz.${region}/wotb/tanks/stats/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, + async function recalculateDiff() { + if (session.isTracking) { + const { id, region } = session; + const careerRaw = await getWargamingResponse( + `https://api.wotblitz.${region}/wotb/tanks/stats/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, + ); + const career = careerRaw[id].reduce>( + (accumulator, curr) => ({ + ...accumulator, + [curr.tank_id]: curr, + }), + {}, + ); + const awaitedTankopedia = await tankopedia; + const awaitedTankAverages = await tankAverages; + const careerWN8 = + careerRaw[id].reduce( + (accumulator, { tank_id, all }) => + accumulator + + (awaitedTankAverages[tank_id] && all.battles > 0 + ? all.battles * + calculateWN8(awaitedTankAverages[tank_id].all, all) + : 0), + 0, + ) / + careerRaw[id].reduce( + (accumulator, { tank_id, all }) => + accumulator + + (awaitedTankAverages[tank_id] && all.battles > 0 ? all.battles : 0), + 0, ); - const career = careerRaw[id].reduce< - Record - >( - (accumulator, curr) => ({ - ...accumulator, - [curr.tank_id]: curr, - }), - {}, - ); - const awaitedTankopedia = await tankopedia; - const awaitedTankAverages = await tankAverages; - setDiff( - ( - Object.values( - diffNormalizedTankStats(session.tankStats, career), - ) as IndividualTankStats[] - ).map((stats) => { - return { - stats, - tankopedia: awaitedTankopedia[stats.tank_id], - career: career[stats.tank_id], - currentWN8: awaitedTankAverages[stats.tank_id] - ? calculateWN8( - awaitedTankAverages[stats.tank_id].all, - stats.all, - ) - : undefined, - careerWN8: awaitedTankAverages[stats.tank_id] - ? calculateWN8( - awaitedTankAverages[stats.tank_id].all, - career[stats.tank_id].all, - ) - : undefined, - }; - }), - ); - } - })(); + setDiff({ + careerWN8, + + list: ( + Object.values( + diffNormalizedTankStats(session.tankStats, career), + ) as IndividualTankStats[] + ).map((stats) => { + return { + stats, + tankopedia: awaitedTankopedia[stats.tank_id], + career: career[stats.tank_id], + currentWN8: awaitedTankAverages[stats.tank_id] + ? calculateWN8(awaitedTankAverages[stats.tank_id].all, stats.all) + : undefined, + careerWN8: awaitedTankAverages[stats.tank_id] + ? calculateWN8( + awaitedTankAverages[stats.tank_id].all, + career[stats.tank_id].all, + ) + : undefined, + }; + }), + }); + } + } + async function setSession(region: Region, id: number, nickname: string) {} + + useEffect(() => { + recalculateDiff(); + const interval = setInterval(recalculateDiff, 1000 / REFRESH_RATE); + + return () => clearInterval(interval); }, []); return ( @@ -135,7 +165,6 @@ export default function Page() { marginTop: 8, flexDirection: 'column', backgroundColor: theme.colors.componentNonInteractive, - border: theme.borderStyles.nonInteractive, borderRadius: 4, padding: 8, boxSizing: 'border-box', @@ -244,69 +273,171 @@ export default function Page() { - {diff && - diff - .sort((a, b) => b.stats.last_battle_time - a.stats.last_battle_time) - .map(({ stats, tankopedia, career, careerWN8, currentWN8 }) => ( - { - if (tankopedia?.is_collectible) return TreeTypeEnum.Collector; - if (tankopedia?.is_premium) return TreeTypeEnum.Premium; - })()} - rows={[ - { - title: 'Battles', - current: stats.all.battles.toLocaleString(), - career: career.all.battles.toLocaleString(), - }, - { - title: 'Winrate', - current: `${( - 100 * - (stats.all.wins / stats.all.battles) - ).toFixed(2)}%`, - career: `${( - 100 * - (career.all.wins / career.all.battles) - ).toFixed(2)}%`, - delta: - stats.all.wins / stats.all.battles - - career.all.wins / career.all.battles, - }, - { - title: 'WN8', - current: - currentWN8 === undefined - ? undefined - : Math.round(currentWN8).toLocaleString(), - career: - careerWN8 === undefined - ? undefined - : Math.round(careerWN8).toLocaleString(), - percentile: - currentWN8 === undefined - ? undefined - : getWN8Percentile(currentWN8), - }, - { - title: 'Damage', - current: Math.round( - stats.all.damage_dealt / stats.all.battles, - ).toLocaleString(), - career: Math.round( - career.all.damage_dealt / career.all.battles, - ).toLocaleString(), - delta: - stats.all.damage_dealt / stats.all.battles - - career.all.damage_dealt / career.all.battles, - }, - ]} - /> - ))} + {session.isTracking && since !== undefined && diff !== undefined && ( + accumulator + stats.all.battles, + 0, + ) + .toLocaleString(), + career: tankStatsArray + .reduce( + (accumulator, stats) => accumulator + stats.all.battles, + 0, + ) + .toLocaleString(), + }, + { + title: 'Winrate', + current: `${( + 100 * + (diff.list.reduce( + (accumulator, { stats }) => accumulator + stats.all.wins, + 0, + ) / + diff.list.reduce( + (accumulator, { stats }) => + accumulator + stats.all.battles, + 0, + )) + ).toFixed(2)}%`, + career: `${( + 100 * + (tankStatsArray.reduce( + (accumulator, stats) => accumulator + stats.all.wins, + 0, + ) / + tankStatsArray.reduce( + (accumulator, stats) => accumulator + stats.all.battles, + 0, + )) + ).toFixed(2)}%`, + }, + (() => { + const currentWN8 = + diff.list.reduce( + (accumulator, { currentWN8, stats }) => + stats.all.battles * (currentWN8 ?? 0) + accumulator, + 0, + ) / + diff.list.reduce( + (accumulator, { currentWN8, stats }) => + (currentWN8 === undefined ? 0 : stats.all.battles) + + accumulator, + 0, + ); + + return { + title: 'WN8', + current: Math.round(currentWN8).toLocaleString(), + percentile: getWN8Percentile(currentWN8), + career: Math.round(diff.careerWN8).toLocaleString(), + }; + })(), + { + title: 'Damage', + current: Math.round( + diff.list.reduce( + (accumulator, { stats }) => + accumulator + stats.all.damage_dealt, + 0, + ) / + diff.list.reduce( + (accumulator, { stats }) => + accumulator + stats.all.battles, + 0, + ), + ).toLocaleString(), + career: Math.round( + tankStatsArray.reduce( + (accumulator, stats) => + accumulator + stats.all.damage_dealt, + 0, + ) / + tankStatsArray.reduce( + (accumulator, stats) => accumulator + stats.all.battles, + 0, + ), + ).toLocaleString(), + }, + ]} + /> + )} + + {diff?.list + .sort((a, b) => b.stats.last_battle_time - a.stats.last_battle_time) + .map(({ stats, tankopedia, career, careerWN8, currentWN8 }) => ( + { + if (tankopedia?.is_collectible) return TreeTypeEnum.Collector; + if (tankopedia?.is_premium) return TreeTypeEnum.Premium; + })()} + stats={[ + { + title: 'Battles', + current: stats.all.battles.toLocaleString(), + career: career.all.battles.toLocaleString(), + }, + { + title: 'Winrate', + current: `${( + 100 * + (stats.all.wins / stats.all.battles) + ).toFixed(2)}%`, + career: `${( + 100 * + (career.all.wins / career.all.battles) + ).toFixed(2)}%`, + delta: + stats.all.wins / stats.all.battles - + career.all.wins / career.all.battles, + }, + { + title: 'WN8', + current: + currentWN8 === undefined + ? undefined + : Math.round(currentWN8).toLocaleString(), + career: + careerWN8 === undefined + ? undefined + : Math.round(careerWN8).toLocaleString(), + percentile: + currentWN8 === undefined + ? undefined + : getWN8Percentile(currentWN8), + }, + { + title: 'Damage', + current: Math.round( + stats.all.damage_dealt / stats.all.battles, + ).toLocaleString(), + career: Math.round( + career.all.damage_dealt / career.all.battles, + ).toLocaleString(), + delta: + stats.all.damage_dealt / stats.all.battles - + career.all.damage_dealt / career.all.battles, + }, + ]} + /> + ))} ); diff --git a/src/components/Breakdown/components/Row.tsx b/src/components/Breakdown/components/Row.tsx index 0ee489c51..5acd25cf8 100644 --- a/src/components/Breakdown/components/Row.tsx +++ b/src/components/Breakdown/components/Row.tsx @@ -5,13 +5,13 @@ import { TREE_TYPE_ICONS, TreeTypeEnum } from '../../Tanks'; import { RowStat } from './RowStat'; interface RowProps { - type: 'tank' | 'summary'; + type?: 'tank' | 'summary'; title: string; minimized?: boolean; treeType?: TreeTypeEnum; tankType?: TankType; - rows: { + stats: { title: string; current?: number | string; career?: number | string; @@ -77,7 +77,7 @@ export function Row(props: RowProps) { paddingBottom: 8, }} > - {props.rows.map((row, index) => ( + {props.stats.map((row, index) => ( >( display: 'flex', padding: 8, borderRadius: 4, - border: theme.borderStyles.interactive, backgroundColor: theme.colors.componentInteractive, color: theme.colors.textLowContrast, fontSize: 16, diff --git a/src/renderers/today.tsx b/src/renderers/today.tsx index 0922c3db0..ff0c40bc6 100644 --- a/src/renderers/today.tsx +++ b/src/renderers/today.tsx @@ -138,7 +138,7 @@ export default async function today( treeType={tankopediaEntry ? await getTreeType(id) : undefined} title={showTotal && id === 0 ? 'Total' : await resolveTankName(id)} minimized={showTotal ? index > maximized : index + 1 > maximized} - rows={[ + stats={[ { title: 'Battles', current: tankStats.battles.toLocaleString(), diff --git a/src/stores/session.ts b/src/stores/session.ts index b7b8343c9..aeeb82ac5 100644 --- a/src/stores/session.ts +++ b/src/stores/session.ts @@ -14,6 +14,7 @@ type Session = id: number; nickname: string; tankStats: NormalizedTankStats; + time: number; }; export const useSession = create()(