From 7f431b07e140c0f4a1903ffe9df3a0f9fb3179a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com>
Date: Sun, 1 Oct 2023 18:43:40 -0500
Subject: [PATCH] feat: added options
---
package.json | 1 +
src/app/embeds/session/page.tsx | 278 ++++++++++--------
.../tools/session/components/CustomColumn.tsx | 66 +++++
src/app/tools/session/page.tsx | 39 ++-
src/components/Breakdown/components/Row.tsx | 39 +--
src/stores/session.ts | 19 ++
yarn.lock | 5 +
7 files changed, 305 insertions(+), 142 deletions(-)
create mode 100644 src/app/tools/session/components/CustomColumn.tsx
diff --git a/package.json b/package.json
index 520ce4f0e..97e38c2e1 100644
--- a/package.json
+++ b/package.json
@@ -37,6 +37,7 @@
"esbuild": "^0.19.3",
"express": "^4.18.2",
"fuzzysort": "^2.0.4",
+ "immer": "^10.0.2",
"lodash": "^4.17.21",
"markdown-escape": "^2.0.0",
"next": "^13.5.2",
diff --git a/src/app/embeds/session/page.tsx b/src/app/embeds/session/page.tsx
index d04180de6..4bff801db 100644
--- a/src/app/embeds/session/page.tsx
+++ b/src/app/embeds/session/page.tsx
@@ -12,6 +12,7 @@ import { TankopediaEntry, tankopedia } from '../../../core/blitz/tankopedia';
import { tankAverages } from '../../../core/blitzstars/tankAverages';
import { useSession } from '../../../stores/session';
import { IndividualTankStats, TanksStats } from '../../../types/tanksStats';
+import { CustomColumnDisplay } from '../../tools/session/components/CustomColumn';
const REFRESH_RATE = 1 / 5;
@@ -139,136 +140,169 @@ export default function SessionPage() {
return () => clearInterval(interval);
}, [session]);
+ const totalRowStats: Record<
+ CustomColumnDisplay,
+ Breakdown.RowStat | undefined
+ > = {
+ battles: {
+ title: 'Battles',
+ current: sessionBattles?.toLocaleString(),
+ career: tankStatsArray
+ .reduce((accumulator, stats) => accumulator + stats.all.battles, 0)
+ .toLocaleString(),
+ },
+ winrate: {
+ title: 'Winrate',
+ current: sessionBattles ? `${(100 * sessionWinrate).toFixed(2)}%` : '--',
+ career: `${(100 * careerWinrate).toFixed(2)}%`,
+ delta: sessionBattles === 0 ? 0 : sessionWinrate - careerWinrate,
+ },
+ wn8: (() => {
+ if (!diff) return undefined;
+
+ const battlesWithWN8 = diff.list.reduce(
+ (accumulator, { currentWN8, stats }) =>
+ (currentWN8 === undefined ? 0 : stats.all.battles) + accumulator,
+ 0,
+ );
+ const currentWN8 =
+ diff.list.reduce(
+ (accumulator, { currentWN8, stats }) =>
+ stats.all.battles * (currentWN8 ?? 0) + accumulator,
+ 0,
+ ) / battlesWithWN8!;
+
+ return {
+ title: 'WN8',
+ current: battlesWithWN8
+ ? Math.round(currentWN8!).toLocaleString()
+ : '--',
+ percentile: battlesWithWN8 ? getWN8Percentile(currentWN8!) : undefined,
+ career: Math.round(diff.careerWN8).toLocaleString(),
+ };
+ })(),
+ damage: {
+ title: 'Damage',
+ delta: sessionBattles === 0 ? 0 : currentDamage - careerDamage,
+ current: sessionBattles
+ ? Math.round(currentDamage).toLocaleString()
+ : '--',
+ career: Math.round(careerDamage).toLocaleString(),
+ },
+ none: undefined,
+ };
+
return (
- {session.isTracking && since !== undefined && diff !== undefined && (
- accumulator + stats.all.battles,
- 0,
- )
- .toLocaleString(),
- },
- {
- title: 'Winrate',
- current: sessionBattles
- ? `${(100 * sessionWinrate).toFixed(2)}%`
- : '--',
- career: `${(100 * careerWinrate).toFixed(2)}%`,
- delta: sessionBattles === 0 ? 0 : sessionWinrate - careerWinrate,
- },
- (() => {
- const battlesWithWN8 = diff.list.reduce(
- (accumulator, { currentWN8, stats }) =>
- (currentWN8 === undefined ? 0 : stats.all.battles) +
- accumulator,
- 0,
- );
- const currentWN8 =
- diff.list.reduce(
- (accumulator, { currentWN8, stats }) =>
- stats.all.battles * (currentWN8 ?? 0) + accumulator,
- 0,
- ) / battlesWithWN8;
+ {session.showTotal &&
+ session.isTracking &&
+ since !== undefined &&
+ diff !== undefined && (
+ {
+ const rowStat = totalRowStats[customColumn.display];
+
+ if (!rowStat) return undefined;
return {
- title: 'WN8',
- current: battlesWithWN8
- ? Math.round(currentWN8).toLocaleString()
- : '--',
- percentile: battlesWithWN8
- ? getWN8Percentile(currentWN8)
- : undefined,
- career: Math.round(diff.careerWN8).toLocaleString(),
+ ...rowStat,
+ delta:
+ customColumn.showDelta && rowStat.percentile === undefined
+ ? rowStat.delta
+ : undefined,
};
- })(),
- {
- title: 'Damage',
- delta: sessionBattles === 0 ? 0 : currentDamage - careerDamage,
- current: sessionBattles
- ? Math.round(currentDamage).toLocaleString()
- : '--',
- career: Math.round(careerDamage).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,
- },
- ]}
- />
- ))}
+ .map(({ stats, tankopedia, career, careerWN8, currentWN8 }) => {
+ const rowStats: Record<
+ CustomColumnDisplay,
+ Breakdown.RowStat | undefined
+ > = {
+ battles: {
+ title: 'Battles',
+ current: stats.all.battles.toLocaleString(),
+ career: career.all.battles.toLocaleString(),
+ },
+ winrate: {
+ 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,
+ },
+ wn8: {
+ title: 'WN8',
+ current:
+ currentWN8 === undefined
+ ? undefined
+ : Math.round(currentWN8).toLocaleString(),
+ career:
+ careerWN8 === undefined
+ ? undefined
+ : Math.round(careerWN8).toLocaleString(),
+ percentile:
+ currentWN8 === undefined
+ ? undefined
+ : getWN8Percentile(currentWN8),
+ },
+ damage: {
+ 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,
+ },
+ none: undefined,
+ };
+
+ return (
+ {
+ if (tankopedia?.is_collectible) return TreeTypeEnum.Collector;
+ if (tankopedia?.is_premium) return TreeTypeEnum.Premium;
+ })()}
+ stats={session.customColumns.map((customColumn) => {
+ const rowStat = rowStats[customColumn.display];
+
+ if (!rowStat) return undefined;
+
+ return {
+ ...rowStat,
+ delta:
+ customColumn.showDelta && rowStat.percentile === undefined
+ ? rowStat.delta
+ : undefined,
+ };
+ })}
+ />
+ );
+ })}
);
}
diff --git a/src/app/tools/session/components/CustomColumn.tsx b/src/app/tools/session/components/CustomColumn.tsx
new file mode 100644
index 000000000..ee4a788e3
--- /dev/null
+++ b/src/app/tools/session/components/CustomColumn.tsx
@@ -0,0 +1,66 @@
+import { DropdownMenu } from '@radix-ui/themes';
+import mutateSession, { useSession } from '../../../../stores/session';
+
+export type CustomColumnDisplay =
+ | 'battles'
+ | 'winrate'
+ | 'wn8'
+ | 'damage'
+ | 'none';
+
+const NO_DELTA: CustomColumnDisplay[] = ['battles', 'wn8', 'none'];
+
+interface CustomColumn {
+ column: number;
+}
+
+export function CustomColumn({ column }: CustomColumn) {
+ const customColumn = useSession((state) => state.customColumns[column]);
+
+ return (
+
+ Column {column + 1}
+
+
+ Display
+
+
+ mutateSession((draft) => {
+ draft.customColumns[column].display =
+ event as CustomColumnDisplay;
+ })
+ }
+ >
+
+ Battles
+
+
+ Winrate
+
+ WN8
+ Damage
+ None
+
+
+ {!NO_DELTA.includes(customColumn.display) && (
+ <>
+
+
+
+ mutateSession((draft) => {
+ draft.customColumns[column].showDelta = checked;
+ })
+ }
+ >
+ Show delta
+
+ >
+ )}
+
+
+ );
+}
diff --git a/src/app/tools/session/page.tsx b/src/app/tools/session/page.tsx
index e267eee47..294337774 100644
--- a/src/app/tools/session/page.tsx
+++ b/src/app/tools/session/page.tsx
@@ -1,6 +1,11 @@
'use client';
-import { CopyIcon, PersonIcon, ReloadIcon } from '@radix-ui/react-icons';
+import {
+ CaretDownIcon,
+ CopyIcon,
+ PersonIcon,
+ ReloadIcon,
+} from '@radix-ui/react-icons';
import {
AlertDialog,
Button,
@@ -23,10 +28,9 @@ import listPlayers, {
import { useSession } from '../../../stores/session';
import { NormalizedTankStats, TanksStats } from '../../../types/tanksStats';
import SessionPage from '../../embeds/session/page';
+import { CustomColumn } from './components/CustomColumn';
import * as styles from './page.css';
-// 1 once per 5 seconds
-
export default function Page() {
const input = useRef(null);
const [searchResults, setSearchResults] = useState<
@@ -150,6 +154,7 @@ export default function Page() {