feat: session persistance

This commit is contained in:
TresAbhi committed 2023-09-19 15:52:39 +00:00
1 parent 57f6e928b7
commit 018783bb47
12 files changed
+121 -29

No files matched your search

File renamed without changes.
@@ -0,0 +1,16 @@
import { NextRequest, NextResponse } from 'next/server';
import { Region } from '../../../../../constants/regions';
import getTankStats from '../../../../../core/blitz/getTankStats';
import { NormalizedTankStats } from '../../../../../types/tanksStats';
export async function GET(request: NextRequest) {
const region = request.nextUrl.searchParams.get('region') as Region;
const id = parseInt(request.nextUrl.searchParams.get('id')!);
const tankStats = await getTankStats(region, id);
const normalized = tankStats.reduce<NormalizedTankStats>(
(accumulator, tank) => ({ ...accumulator, [tank.tank_id]: tank }),
{},
);
return NextResponse.json(normalized);
}
+45 -5
View File
@@ -9,6 +9,8 @@ import { SearchBar } from '../../../components/SearchBar';
import { REGION_NAMES } from '../../../constants/regions';
import { AccountListWithServer } from '../../../core/blitz/listPlayers';
import { theme } from '../../../stitches.config';
import { useSession } from '../../../stores/session';
import { NormalizedTankStats } from '../../../types/tanksStats';
import * as styles from './page.css';
export default function Page() {
@@ -21,7 +23,7 @@ export default function Page() {
async (event: ChangeEvent<HTMLInputElement>) => {
if (event.target.value) {
const players = await fetch(
`/api/list/players?search=${event.target.value}`,
`/api/search/players?search=${event.target.value}`,
).then((response) => response.json() as Promise<AccountListWithServer>);
setSearchResults(players);
@@ -31,6 +33,7 @@ export default function Page() {
},
500,
);
const initialSession = useSession.getState();
return (
<PageWrapper>
@@ -39,6 +42,9 @@ export default function Page() {
<SearchBar
ref={input}
style={{ width: '100%', boxSizing: 'border-box' }}
defaultValue={
initialSession.isTracking ? initialSession.nickname : undefined
}
onChange={(event) => {
if (event.target.value) {
setShowSearchResults(true);
@@ -93,13 +99,30 @@ export default function Page() {
No results
</div>
) : (
searchResults?.map(({ account_id, nickname, region }) => (
searchResults?.map(({ account_id: id, nickname, region }) => (
<button
key={account_id}
key={id}
className={styles.searchButton}
onClick={() => {
setShowSearchResults(false);
if (input.current) input.current.value = nickname;
input.current!.value = nickname;
fetch(
`/api/stats/normalized/tanks?id=${id}&region=${region}`,
)
.then(
(response) =>
response.json() as Promise<NormalizedTankStats>,
)
.then((tankStats) =>
useSession.setState({
isTracking: true,
id,
region,
nickname,
tankStats,
}),
);
}}
>
<span
@@ -124,7 +147,24 @@ export default function Page() {
</div>
<div style={{ display: 'flex', gap: 8 }}>
<Button className={styles.toolbarButton} color="dangerous">
<Button
className={styles.toolbarButton}
color="dangerous"
onClick={async () => {
const session = useSession.getState();
if (!session.isTracking) return;
const { id, region } = session;
const tankStats = await fetch(
`/api/stats/normalized/tanks?id=${id}&region=${region}`,
).then(
(response) => response.json() as Promise<NormalizedTankStats>,
);
useSession.setState({ tankStats });
}}
>
<ReloadIcon /> Reset
</Button>
<Button className={styles.toolbarButton}>
-1
View File
@@ -1,5 +1,4 @@
import { SlashCommandBuilder } from 'discord.js';
import { CYCLIC_API } from '../constants/cyclic';
import getWargamingResponse from '../core/blitz/getWargamingResponse';
import addUsernameChoices from '../core/discord/addUsernameChoices';
import autocompleteUsername from '../core/discord/autocompleteUsername';
+5 -5
View File
@@ -1,18 +1,18 @@
import { REGION_NAMES, Region } from '../../constants/regions';
import { TanksStats } from '../../types/tanksStats';
import { TankStats } from '../../types/tanksStats';
import { secrets } from '../node/secrets';
import throwError from '../node/throwError';
import getWargamingResponse from './getWargamingResponse';
export default async function getTankStats(server: Region, id: number) {
const tankStats = await getWargamingResponse<TanksStats>(
`https://api.wotblitz.${server}/wotb/tanks/stats/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${id}`,
export default async function getTankStats(region: Region, id: number) {
const tankStats = await getWargamingResponse<TankStats>(
`https://api.wotblitz.${region}/wotb/tanks/stats/?application_id=${secrets.WARGAMING_APPLICATION_ID}&account_id=${id}`,
);
if (tankStats[id] === null) {
throw throwError(
'No tank stats available',
`Wargaming says there is no tank stats for this account. This account may not have any battles/tanks or exist in the ${REGION_NAMES[server]} server.`,
`Wargaming says there is no tank stats for this account. This account may not have any battles/tanks or exist in the ${REGION_NAMES[region]} server.`,
);
}
+1 -1
View File
@@ -17,7 +17,7 @@ export const secrets = SECRET_KEYS.reduce<Partial<Record<SECRET, string>>>(
...accumulator,
get [key](): string {
if (!(key in process.env)) throw new Error(`Key ${key} not provided`);
if (!(key in process.env)) throw new Error(`Secret ${key} not provided`);
return process.env[key]!;
},
}),
+21
View File
@@ -0,0 +1,21 @@
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import { Region } from '../constants/regions';
import { NormalizedTankStats } from '../types/tanksStats';
type Session =
| {
isTracking: false;
}
| {
isTracking: true;
region: Region;
id: number;
nickname: string;
tankStats: NormalizedTankStats;
};
export const useSession = create<Session>()(
devtools(persist((set) => ({ isTracking: false }), { name: 'session' })),
);
+11 -13
View File
@@ -46,18 +46,16 @@ export interface ClanStats {
dropped_capture_points: number;
}
export type AccountInfo = {
export interface AccountInfo {
[accountId: number]: {
statistics: {
clan: ClanStats;
all: AllStats;
frags: null;
};
account_id: number;
created_at: number;
updated_at: number;
private: null;
last_battle_time: number;
nickname: string;
clan: ClanStats;
all: AllStats;
frags: null;
};
};
account_id: number;
created_at: number;
updated_at: number;
private: null;
last_battle_time: number;
nickname: string;
}
+6 -2
View File
@@ -14,6 +14,10 @@ export interface IndividualTankStats {
tank_id: number;
}
export type TanksStats = {
export interface TankStats {
[accountId: number]: IndividualTankStats[];
};
}
export interface NormalizedTankStats {
[tankId: number]: IndividualTankStats;
}