diff --git a/src/api/analysis/analysis.ts b/src/api/analysis/analysis.ts index e3efc67..61da8cf 100644 --- a/src/api/analysis/analysis.ts +++ b/src/api/analysis/analysis.ts @@ -49,6 +49,18 @@ export const getAnalysisList = async (): Promise< return data } +export const getAnalysisGameList = async (type = 'play', page = 1) => { + const res = await fetch(buildUrl(`analysis/user/list/${type}/${page}`)) + + if (res.status === 401) { + throw new Error('Unauthorized') + } + + const data = await res.json() + + return data +} + export const getLichessGames = async ( username: string, onMessage: (data: any) => void, @@ -260,3 +272,103 @@ export const getAnalyzedLichessGame = async ( pgn, } as AnalyzedGame } + +export const getAnalyzedUserGame = async ( + id: string, + game_type: 'play' | 'hand' | 'brain', + maia_model = 'maia_kdd_1500', +) => { + const res = await fetch( + buildUrl( + `analysis/user/analyze_user_maia_game/${id}?` + + new URLSearchParams({ + game_type, + maia_model, + }), + ), + { + method: 'GET', + headers: { + 'Content-Type': 'text/plain', + }, + }, + ) + + if (res.status === 401) { + throw new Error('Unauthorized') + } + + const data = await res.json() + + const termination = { + ...data['termination'], + condition: 'Normal', + } + + const gameType = 'blitz' + const blackPlayer = data['black_player'] + const whitePlayer = data['white_player'] + + const maiaEvaluations: { [model: string]: MoveMap[] } = {} + const positionEvaluations: { [model: string]: PositionEvaluation[] } = {} + const availableMoves: AvailableMoves[] = [] + + for (const model of data['maia_versions']) { + maiaEvaluations[model] = data['maia_evals'][model] + positionEvaluations[model] = Object.keys(data['maia_evals'][model]).map( + () => ({ + trickiness: 1, + performance: 1, + }), + ) + } + + for (const position of data['move_maps']) { + const moves: AvailableMoves = {} + for (const move of position) { + const fromTo = move.move.join('') + const san = move['move_san'] + const { check, fen } = move + + moves[fromTo] = { + board: fen, + check, + san, + lastMove: move.move, + } + } + availableMoves.push(moves) + } + + const gameStates = data['game_states'] + + const moves = gameStates.map((gameState: any) => { + const { + last_move: lastMove, + fen, + check, + last_move_san: san, + evaluations: maia_values, + } = gameState + + return { + board: fen, + lastMove, + san, + check, + maia_values, + } + }) + + return { + id, + blackPlayer, + whitePlayer, + moves, + maiaEvaluations, + availableMoves, + gameType, + termination, + positionEvaluations, + } as AnalyzedGame +} diff --git a/src/components/AnalysisGameList/AnalysisGameList.tsx b/src/components/Analysis/AnalysisGameList.tsx similarity index 68% rename from src/components/AnalysisGameList/AnalysisGameList.tsx rename to src/components/Analysis/AnalysisGameList.tsx index 7f4989a..63e6d25 100644 --- a/src/components/AnalysisGameList/AnalysisGameList.tsx +++ b/src/components/Analysis/AnalysisGameList.tsx @@ -11,6 +11,7 @@ import { motion } from 'framer-motion' import Tournament from './Tournament' import { AnalysisListContext, GameControllerContext } from 'src/contexts' +import UserGameList from './UserGameList' interface AnalysisGameListProps { currentId: string[] | null @@ -25,6 +26,12 @@ interface AnalysisGameListProps { setCurrentMove: Dispatch>, currentMaiaModel: string, ) => Promise + loadNewUserGames: ( + id: string, + type: 'play' | 'hand' | 'brain', + setCurrentMove: Dispatch>, + currentMaiaModel: string, + ) => Promise } const AnalysisGameList: React.FC = ({ @@ -32,12 +39,20 @@ const AnalysisGameList: React.FC = ({ currentMaiaModel, loadNewTournamentGame, loadNewLichessGames, + loadNewUserGames, }) => { - const [selected, setSelected] = useState<'tournament' | 'lichess'>('lichess') + const [selected, setSelected] = useState< + 'tournament' | 'pgn' | 'play' | 'hand' | 'brain' + >('pgn') const controller = useContext(GameControllerContext) - const { analysisTournamentList, analysisLichessList } = - useContext(AnalysisListContext) + const { + analysisPlayList, + analysisHandList, + analysisBrainList, + analysisLichessList, + analysisTournamentList, + } = useContext(AnalysisListContext) const listKeys = useMemo(() => { return analysisTournamentList ? Array.from(analysisTournamentList.keys()).sort((a, b) => @@ -85,11 +100,11 @@ const AnalysisGameList: React.FC = ({
) : ( -
- {analysisLichessList.map((game, index) => { - const selected = - currentId && currentId[1] === 'lichess' - ? currentId[0] === game.id - : false - - return ( - - ) - })} -
+ )}
) : null diff --git a/src/components/AnalysisGameList/Tournament.tsx b/src/components/Analysis/Tournament.tsx similarity index 98% rename from src/components/AnalysisGameList/Tournament.tsx rename to src/components/Analysis/Tournament.tsx index 0944373..4bb8516 100644 --- a/src/components/AnalysisGameList/Tournament.tsx +++ b/src/components/Analysis/Tournament.tsx @@ -1,4 +1,5 @@ import { Dispatch, SetStateAction } from 'react' + import { PlusIcon, MinusIcon, @@ -67,7 +68,7 @@ export default function Tournament({ > {games?.map((game, j) => { const selected = - currentId && currentId[1] != 'lichess' + currentId && currentId[1] == 'tournament' ? sectionId == currentId[0] && game.game_index == Number.parseInt(currentId[1]) : false diff --git a/src/components/Analysis/UserGameList.tsx b/src/components/Analysis/UserGameList.tsx new file mode 100644 index 0000000..b4dadfb --- /dev/null +++ b/src/components/Analysis/UserGameList.tsx @@ -0,0 +1,164 @@ +import { motion } from 'framer-motion' +import { SetStateAction, Dispatch } from 'react' + +import { AnalysisWebGame } from 'src/types' + +interface Props { + currentId: string[] | null + playGames: AnalysisWebGame[] + handGames: AnalysisWebGame[] + brainGames: AnalysisWebGame[] + lichessGames: AnalysisWebGame[] + selected: 'tournament' | 'play' | 'hand' | 'brain' | 'pgn' + setSelected: (name: 'tournament' | 'play' | 'hand' | 'brain' | 'pgn') => void + setCurrentIndex: Dispatch> + setLoadingIndex: (index: number | null) => void + loadNewLichessGames: ( + id: string, + pgn: string, + setCurrentMove: Dispatch>, + currentMaiaModel: string, + ) => void + loadNewUserGames: ( + id: string, + type: 'play' | 'hand' | 'brain', + setCurrentMove: Dispatch>, + currentMaiaModel: string, + ) => void + currentMaiaModel: string +} + +export default function UserGameList({ + currentId, + selected, + setSelected, + playGames, + handGames, + brainGames, + lichessGames, + setLoadingIndex, + setCurrentIndex, + loadNewLichessGames, + loadNewUserGames, + currentMaiaModel, +}: Props) { + return ( +
+
+
+
+
+
+
+
+ {(selected === 'play' + ? playGames + : selected === 'hand' + ? handGames + : selected === 'brain' + ? brainGames + : lichessGames + ).map((game, index) => { + const selectedGame = currentId && currentId[0] === game.id + return ( + + ) + })} +
+
+ ) +} + +function Header({ + name, + label, + selected, + setSelected, +}: { + label: string + name: 'play' | 'hand' | 'brain' | 'pgn' + selected: 'tournament' | 'play' | 'hand' | 'brain' | 'pgn' + setSelected: (name: 'tournament' | 'play' | 'hand' | 'brain' | 'pgn') => void +}) { + return ( + + ) +} diff --git a/src/components/ProfileColumn/ProfileColumn.tsx b/src/components/ProfileColumn/ProfileColumn.tsx index 96bdff9..23a11c3 100644 --- a/src/components/ProfileColumn/ProfileColumn.tsx +++ b/src/components/ProfileColumn/ProfileColumn.tsx @@ -18,12 +18,12 @@ export const ProfileColumn: React.FC = ({ icon, name, data }: Props) => { const losses = data.losses ?? data.games - data.wins - (data?.draws || 0) return ( -
-
-
{icon}
+
+
+
{icon}

{name}

-
+

Rating

@@ -45,7 +45,7 @@ export const ProfileColumn: React.FC = ({ icon, name, data }: Props) => {
-
+

Wins: {wins}{' '} @@ -55,7 +55,7 @@ export const ProfileColumn: React.FC = ({ icon, name, data }: Props) => {

{draws > 0 ? (
-
+

Draws: {draws}{' '} @@ -67,7 +67,7 @@ export const ProfileColumn: React.FC = ({ icon, name, data }: Props) => { <> )}

-
+

Losses: {losses}{' '} @@ -79,20 +79,20 @@ export const ProfileColumn: React.FC = ({ icon, name, data }: Props) => {

{wins > 0 && (
)} {draws > 0 && (
)} {losses > 0 && (
)} diff --git a/src/components/UserProfile/GameList.tsx b/src/components/UserProfile/GameList.tsx index 07b6803..3426d4c 100644 --- a/src/components/UserProfile/GameList.tsx +++ b/src/components/UserProfile/GameList.tsx @@ -1,32 +1,30 @@ +import { motion } from 'framer-motion' import { AuthContext } from 'src/contexts' import React, { useState, useEffect, useContext } from 'react' -import { getLichessGames } from 'src/api' -import { AnalysisLichessGame } from 'src/types' +import { AnalysisWebGame } from 'src/types' +import { getLichessGames, getAnalysisGameList } from 'src/api' export default function GameList() { const { user } = useContext(AuthContext) - const [games, setGames] = useState([]) + const [selected, setSelected] = useState<'play' | 'hand' | 'brain' | 'pgn'>( + 'play', + ) + const [games, setGames] = useState([]) + const [playGames, setPlayGames] = useState([]) + const [handGames, setHandGames] = useState([]) + const [brainGames, setBrainGames] = useState([]) useEffect(() => { if (user?.lichessId) { getLichessGames(user?.lichessId, (data) => { - const playerColor = - data.players.white.user?.id == user?.lichessId ? 'white' : 'black' const result = data.pgn.match(/\[Result\s+"(.+?)"\]/)[1] || '?' - const game = { + const game: AnalysisWebGame = { id: data.id, - white: - playerColor == 'white' - ? 'You' - : data.players.white.user?.id || 'Anonymous', - black: - playerColor == 'black' - ? 'You' - : data.players.black.user?.id || 'Anonymous', + label: `${data.players.white.user?.id || 'Unknown'} vs. ${data.players.black.user?.id || 'Unknown'}`, result: result, - pgn: data.pgn, + type: 'pgn', } setGames((x) => [...x, game]) @@ -34,27 +32,96 @@ export default function GameList() { } }, [user?.lichessId]) + useEffect(() => { + if (user?.lichessId) { + const playRequest = getAnalysisGameList('play', 1) + const handRequest = getAnalysisGameList('hand', 1) + const brainRequest = getAnalysisGameList('brain', 1) + + Promise.all([playRequest, handRequest, brainRequest]).then((data) => { + const [play, hand, brain] = data + + const parse = ( + game: { + game_id: string + maia_name: string + result: string + player_color: 'white' | 'black' + }, + type: string, + ) => { + const raw = game.maia_name.replace('_kdd_', ' ') + const maia = raw.charAt(0).toUpperCase() + raw.slice(1) + + return { + id: game.game_id, + label: + game.player_color === 'white' + ? `You vs. ${maia}` + : `${maia} vs. You`, + result: game.result, + type, + } + } + + setPlayGames(play.games.map((game: never) => parse(game, 'play'))) + setHandGames(hand.games.map((game: never) => parse(game, 'hand'))) + setBrainGames(brain.games.map((game: never) => parse(game, 'brain'))) + }) + } + }, [user?.lichessId]) + return ( -
-
-

YOUR GAMES

+
+
+

Your Games

- -
- {games.map((game, index) => ( +
+
+
+
+
+
+
+ {(selected === 'play' + ? playGames + : selected === 'hand' + ? handGames + : selected === 'brain' + ? brainGames + : games + ).map((game, index) => ( - ) } + +function Header({ + name, + label, + selected, + setSelected, +}: { + label: string + name: 'play' | 'hand' | 'brain' | 'pgn' + selected: 'play' | 'hand' | 'brain' | 'pgn' + setSelected: (name: 'play' | 'hand' | 'brain' | 'pgn') => void +}) { + return ( + + ) +} diff --git a/src/components/UserProfile/UserProfile.tsx b/src/components/UserProfile/UserProfile.tsx index 93bbae2..f932982 100644 --- a/src/components/UserProfile/UserProfile.tsx +++ b/src/components/UserProfile/UserProfile.tsx @@ -6,12 +6,12 @@ import { useRouter } from 'next/router' import React, { useState, useEffect, useContext } from 'react' import { + UserIcon, HandIcon, BrainIcon, TrainIcon, TuringIcon, RegularPlayIcon, - UserIcon, } from '../Icons/icons' import GameList from './GameList' import { getPlayerStats } from 'src/api' @@ -80,12 +80,12 @@ const UserProfile: React.FC = () => {
{UserIcon}

{user?.displayName}

-
+
} - name="REGULAR" + name="Regular" data={{ rating: stats.regularRating, highest: stats.regularMax, @@ -97,7 +97,7 @@ const UserProfile: React.FC = () => { /> } - name="HAND" + name="Hand" data={{ rating: stats.handRating, highest: stats.handMax, @@ -109,7 +109,7 @@ const UserProfile: React.FC = () => { /> } - name="BRAIN" + name="Brain" data={{ rating: stats.brainRating, highest: stats.brainMax, @@ -121,7 +121,7 @@ const UserProfile: React.FC = () => { /> } - name="TRAIN" + name="Train" data={{ rating: stats.trainRating, highest: stats.trainMax, @@ -132,7 +132,7 @@ const UserProfile: React.FC = () => { /> } - name="BOT/NOT" + name="Bot / Not" data={{ rating: stats.botNotRating, highest: stats.botNotMax, diff --git a/src/contexts/AnalysisListContext/AnalysisListContext.tsx b/src/contexts/AnalysisListContext/AnalysisListContext.tsx index f651041..4bc4aad 100644 --- a/src/contexts/AnalysisListContext/AnalysisListContext.tsx +++ b/src/contexts/AnalysisListContext/AnalysisListContext.tsx @@ -1,13 +1,19 @@ import React from 'react' -import { AnalysisLichessGame, AnalysisTournamentGame } from 'src/types' +import { AnalysisWebGame, AnalysisTournamentGame } from 'src/types' interface IAnalysisListContext { analysisTournamentList: Map | null - analysisLichessList: AnalysisLichessGame[] + analysisLichessList: AnalysisWebGame[] + analysisPlayList: AnalysisWebGame[] + analysisHandList: AnalysisWebGame[] + analysisBrainList: AnalysisWebGame[] } export const AnalysisListContext = React.createContext({ analysisTournamentList: null, analysisLichessList: [], + analysisPlayList: [], + analysisHandList: [], + analysisBrainList: [], }) diff --git a/src/hooks/useAnalysisController/useAnalysisController.ts b/src/hooks/useAnalysisController/useAnalysisController.ts index 4ee8f52..6d919a9 100644 --- a/src/hooks/useAnalysisController/useAnalysisController.ts +++ b/src/hooks/useAnalysisController/useAnalysisController.ts @@ -152,7 +152,7 @@ export const useAnalysisController = ( ) data[model].push(currentData) - } else if (game.type === 'pgn') { + } else { const stockfishRaw = stockfishEvaluations[index] if (!stockfishRaw || stockfishRaw.depth < 10) { data[model].push([]) diff --git a/src/pages/analysis/[...id].tsx b/src/pages/analysis/[...id].tsx index c30c86e..6755752 100644 --- a/src/pages/analysis/[...id].tsx +++ b/src/pages/analysis/[...id].tsx @@ -15,6 +15,7 @@ import type { DrawShape } from 'chessground/draw' import { getLichessGamePGN, + getAnalyzedUserGame, getAnalyzedLichessGame, getAnalyzedTournamentGame, } from 'src/api' @@ -32,8 +33,8 @@ import { AnalyzedGame, MoveMap } from 'src/types/analysis' import { MovesContainer } from 'src/components/MovesContainer' import { GameBoard } from 'src/components/GameBoard/GameBoard' import { GameInfo, ContinueAgainstMaia } from 'src/components/Core' +import AnalysisGameList from 'src/components/Analysis/AnalysisGameList' import { ThemeContext, ModalContext, WindowSizeContext } from 'src/contexts' -import AnalysisGameList from 'src/components/AnalysisGameList/AnalysisGameList' import { HorizontalEvaluationBar } from 'src/components/HorizontalEvaluationBar' import { GameControllerContext } from 'src/contexts/GameControllerContext/GameControllerContext' @@ -107,26 +108,55 @@ const AnalysisPage: NextPage = () => { ...game, type: 'pgn', }) - setCurrentId([id, 'lichess']) - router.push(`/analysis/${id}/lichess`, undefined, { shallow: true }) + setCurrentId([id, 'pgn']) + router.push(`/analysis/${id}/pgn`, undefined, { shallow: true }) }, [router], ) + const getAndSetUserGame = useCallback( + async ( + id: string, + type: 'play' | 'hand' | 'brain', + setCurrentMove?: Dispatch>, + currentMaiaModel = 'maia_kdd_1500', + ) => { + let game + try { + game = await getAnalyzedUserGame(id, type, currentMaiaModel) + } catch (e) { + router.push('/401') + return + } + if (setCurrentMove) setCurrentMove(0) + setAnalyzedGame({ ...game, type }) + setCurrentId([id, type]) + router.push(`/analysis/${id}/${type}`, undefined, { shallow: true }) + }, + [], + ) + useEffect(() => { ;(async () => { if (analyzedGame == undefined) { const queryId = id as string[] - if (queryId[1] == 'lichess') { + if (queryId[1] === 'licpgnhess') { const pgn = await getLichessGamePGN(queryId[0]) - getAndSetLichessGames(queryId[0], pgn, undefined) + } else if (['play', 'hand', 'brain'].includes(queryId[1])) { + getAndSetUserGame(queryId[0], queryId[1] as 'play' | 'hand' | 'brain') } else { getAndSetTournamentGame(queryId) } } })() - }, [id, analyzedGame, getAndSetTournamentGame, getAndSetLichessGames]) + }, [ + id, + analyzedGame, + getAndSetTournamentGame, + getAndSetLichessGames, + getAndSetUserGame, + ]) return ( <> @@ -139,6 +169,7 @@ const AnalysisPage: NextPage = () => { initialOrientation={orientation == 'black' ? 'black' : 'white'} getAndSetTournamentGame={getAndSetTournamentGame} getAndSetLichessGames={getAndSetLichessGames} + getAndSetUserGames={getAndSetUserGame} /> ) : ( @@ -159,10 +190,15 @@ interface Props { setCurrentMove?: Dispatch>, currentMaiaModel?: string, ) => Promise + getAndSetUserGames: ( + id: string, + type: 'play' | 'hand' | 'brain', + setCurrentMove: Dispatch>, + currentMaiaModel: string, + ) => Promise analyzedGame: AnalyzedGame initialIndex: number initialOrientation: Color - setAnalyzedGame: Dispatch> } @@ -173,6 +209,7 @@ const Analysis: React.FC = ({ initialOrientation, getAndSetTournamentGame, getAndSetLichessGames, + getAndSetUserGames, setAnalyzedGame, }: Props) => { const router = useRouter() @@ -220,23 +257,37 @@ const Analysis: React.FC = ({ const updateMaiaModel = async (model: string) => { if (analyzedGame.type === 'tournament') { setCurrentMaiaModel(model) - } else if (analyzedGame.type === 'pgn') { + } else { if (analyzedGame.maiaEvaluations[model]) { setCurrentMaiaModel(model) return } let game - try { - game = await getAnalyzedLichessGame( - analyzedGame.id, - analyzedGame.pgn as string, - model, - ) - } catch (e) { - router.push('/401') - return + if (analyzedGame.type === 'pgn') { + try { + game = await getAnalyzedLichessGame( + analyzedGame.id, + analyzedGame.pgn as string, + model, + ) + } catch (e) { + router.push('/401') + return + } + } else { + try { + game = await getAnalyzedUserGame( + analyzedGame.id, + analyzedGame.type, + model, + ) + } catch (e) { + router.push('/401') + return + } } + const evals = game.maiaEvaluations[model] if (evals) { const newAnalyzedGame = { ...analyzedGame } @@ -393,6 +444,7 @@ const Analysis: React.FC = ({ currentMaiaModel={currentMaiaModel} loadNewTournamentGame={getAndSetTournamentGame} loadNewLichessGames={getAndSetLichessGames} + loadNewUserGames={getAndSetUserGames} />
@@ -612,6 +664,7 @@ const Analysis: React.FC = ({ currentMaiaModel={currentMaiaModel} loadNewTournamentGame={getAndSetTournamentGame} loadNewLichessGames={getAndSetLichessGames} + loadNewUserGames={getAndSetUserGames} />
diff --git a/src/providers/AnalysisListContextProvider/AnalysisListContextProvider.tsx b/src/providers/AnalysisListContextProvider/AnalysisListContextProvider.tsx index c732011..48404e5 100644 --- a/src/providers/AnalysisListContextProvider/AnalysisListContextProvider.tsx +++ b/src/providers/AnalysisListContextProvider/AnalysisListContextProvider.tsx @@ -1,9 +1,9 @@ +import { useRouter } from 'next/router' import { ReactNode, useContext, useEffect, useState } from 'react' +import { AnalysisWebGame, AnalysisTournamentGame } from 'src/types' import { AuthContext, AnalysisListContext } from 'src/contexts' -import { getAnalysisList, getLichessGames } from 'src/api' -import { AnalysisLichessGame, AnalysisTournamentGame } from 'src/types' -import { useRouter } from 'next/router' +import { getAnalysisList, getLichessGames, getAnalysisGameList } from 'src/api' export const AnalysisListContextProvider: React.FC<{ children: ReactNode }> = ({ children, @@ -18,8 +18,17 @@ export const AnalysisListContextProvider: React.FC<{ children: ReactNode }> = ({ AnalysisTournamentGame[] > | null>(null) const [analysisLichessList, setAnalysisLichessList] = useState< - AnalysisLichessGame[] + AnalysisWebGame[] >([]) + const [analysisPlayList, setAnalysisPlayList] = useState( + [], + ) + const [analysisHandList, setAnalysisHandList] = useState( + [], + ) + const [analysisBrainList, setAnalysisBrainList] = useState( + [], + ) useEffect(() => { async function getAndSetData() { @@ -41,23 +50,12 @@ export const AnalysisListContextProvider: React.FC<{ children: ReactNode }> = ({ useEffect(() => { if (user?.lichessId) { getLichessGames(user?.lichessId, (data) => { - const playerColor = - data.players.white.user?.id == user?.lichessId ? 'white' : 'black' - const result = data.pgn.match(/\[Result\s+"(.+?)"\]/)[1] || '?' - const game = { + const game: AnalysisWebGame = { id: data.id, - white: - playerColor === 'white' - ? 'You' - : data.players.white.user?.id || 'Anonymous', - whiteRating: data.players.white.rating, - black: - playerColor === 'black' - ? 'You' - : data.players.black.user?.id || 'Anonymous', - blackRating: data.players.black.rating, + type: 'pgn', + label: `${data.players.white.user?.id || 'Unknown'} vs. ${data.players.black.user?.id || 'Unknown'}`, result: result, pgn: data.pgn, } @@ -67,9 +65,60 @@ export const AnalysisListContextProvider: React.FC<{ children: ReactNode }> = ({ } }, [user?.lichessId]) + useEffect(() => { + if (user?.lichessId) { + const playRequest = getAnalysisGameList('play', 1) + const handRequest = getAnalysisGameList('hand', 1) + const brainRequest = getAnalysisGameList('brain', 1) + + Promise.all([playRequest, handRequest, brainRequest]).then((data) => { + const [play, hand, brain] = data + + const parse = ( + game: { + game_id: string + maia_name: string + result: string + player_color: 'white' | 'black' + }, + type: string, + ) => { + const raw = game.maia_name.replace('_kdd_', ' ') + const maia = raw.charAt(0).toUpperCase() + raw.slice(1) + + return { + id: game.game_id, + label: + game.player_color === 'white' + ? `You vs. ${maia}` + : `${maia} vs. You`, + result: game.result, + type, + } + } + + setAnalysisPlayList( + play.games.map((game: never) => parse(game, 'play')), + ) + setAnalysisHandList( + hand.games.map((game: never) => parse(game, 'hand')), + ) + setAnalysisBrainList( + brain.games.map((game: never) => parse(game, 'brain')), + ) + }) + } + }, [user?.lichessId]) + return ( {children} diff --git a/src/types/analysis/index.ts b/src/types/analysis/index.ts index c36e8f8..35b2cd7 100644 --- a/src/types/analysis/index.ts +++ b/src/types/analysis/index.ts @@ -1,7 +1,7 @@ import { Game } from '../base' import { AvailableMoves } from '../training' -type EvaluationType = 'tournament' | 'pgn' +type EvaluationType = 'tournament' | 'pgn' | 'play' | 'hand' | 'brain' type StockfishEvaluations = T extends 'tournament' ? MoveMap[] @@ -26,6 +26,14 @@ export interface AnalysisLichessGame { result?: string } +export interface AnalysisWebGame { + id: string + type: 'tournament' | 'pgn' | 'play' | 'hand' | 'brain' + label: string + result: string + pgn?: string +} + export interface AnalyzedGame extends Game { maiaEvaluations: { [model: string]: MoveMap[] } stockfishEvaluations: StockfishEvaluations