Skip to content

Commit 5478882

Browse files
feat: handle game ends + clean up components + handle edge cases
1 parent bcad577 commit 5478882

File tree

7 files changed

+97
-76
lines changed

7 files changed

+97
-76
lines changed

src/api/lichess/streaming.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ export const createAnalyzedGameFromLichessStream = (
152152
const tree = new GameTree(startingFen)
153153

154154
return {
155-
id: `stream-${id}`,
155+
id,
156156
blackPlayer,
157157
whitePlayer,
158158
gameType: 'stream',

src/components/Analysis/StreamAnalysis.tsx

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,19 @@ export const StreamAnalysis: React.FC<Props> = ({
183183
)}
184184
</div>
185185
))}
186+
<div className="mt-1 flex items-center justify-center gap-1">
187+
<span className="text-xxs text-secondary">
188+
Watch on{' '}
189+
<a
190+
href={`https://lichess.org/${game.id}`}
191+
target="_blank"
192+
rel="noopener noreferrer"
193+
className="text-primary/60 underline hover:text-primary"
194+
>
195+
Lichess
196+
</a>
197+
</span>
198+
</div>
186199
</div>
187200
<div className="flex w-full items-center justify-between text-xs md:hidden">
188201
<div className="flex items-center gap-1">
@@ -273,14 +286,10 @@ export const StreamAnalysis: React.FC<Props> = ({
273286
style={{ willChange: 'transform, opacity' }}
274287
>
275288
<GameInfo
276-
title="Live Analysis"
289+
title="Analysis"
277290
icon="live_tv"
278291
type="analysis"
279-
streamState={{
280-
isLive: streamState.isLive,
281-
isConnected: streamState.isConnected,
282-
error: streamState.error,
283-
}}
292+
streamState={streamState}
284293
>
285294
<NestedGameInfo />
286295
</GameInfo>
@@ -445,17 +454,13 @@ export const StreamAnalysis: React.FC<Props> = ({
445454
style={{ willChange: 'transform, opacity' }}
446455
>
447456
<GameInfo
448-
title="Live Analysis"
457+
title="Analysis"
449458
icon="live_tv"
450459
type="analysis"
451460
currentMaiaModel={analysisController.currentMaiaModel}
452461
setCurrentMaiaModel={analysisController.setCurrentMaiaModel}
453462
MAIA_MODELS={MAIA_MODELS}
454-
streamState={{
455-
isLive: streamState.isLive,
456-
isConnected: streamState.isConnected,
457-
error: streamState.error,
458-
}}
463+
streamState={streamState}
459464
>
460465
<NestedGameInfo />
461466
</GameInfo>

src/components/Common/GameInfo.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ interface Props {
1616
isLive: boolean
1717
isConnected: boolean
1818
error: string | null
19+
gameEnded: boolean
1920
}
2021
}
2122

@@ -60,9 +61,11 @@ export const GameInfo: React.FC<Props> = ({
6061
? 'LIVE'
6162
: streamState.isConnected
6263
? 'Connected'
63-
: streamState.error
64-
? 'Disconnected'
65-
: 'Connecting...'}
64+
: streamState.gameEnded
65+
? 'Game Ended'
66+
: streamState.error
67+
? 'Disconnected'
68+
: 'Connecting...'}
6669
</span>
6770
</div>
6871
)}

src/components/Common/PlayerInfo.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,11 @@ export const PlayerInfo: React.FC<PlayerInfoProps> = ({
5959
<div
6060
className={`h-2.5 w-2.5 rounded-full ${color === 'white' ? 'bg-white' : 'border bg-black'}`}
6161
/>
62-
<p>
63-
{name ?? 'Unknown'} {rating ? `(${rating})` : null}
62+
<p className="text-sm">
63+
{name ?? 'Unknown'}{' '}
64+
<span className="text-xs text-secondary">
65+
{rating ? `(${rating})` : null}
66+
</span>
6467
</p>
6568
</div>
6669
<div className="flex items-center gap-4">
@@ -85,7 +88,7 @@ export const PlayerInfo: React.FC<PlayerInfoProps> = ({
8588
<span
8689
className={`font-mono text-xs font-medium ${
8790
clock.isActive ? 'text-black' : 'text-black/60'
88-
} ${currentTime < 60 ? 'text-red-500' : ''}`}
91+
} ${currentTime < 60 ? 'text-red-700' : ''}`}
8992
>
9093
{formatTime(currentTime)}
9194
</span>

src/hooks/useLichessStreamController.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const useLichessStreamController = (): LichessStreamController => {
2929
isLive: false,
3030
error: null,
3131
gameStarted: false,
32+
gameEnded: false,
3233
})
3334
const [clockState, setClockState] = useState<ClockState>({
3435
whiteTime: 0,
@@ -67,6 +68,7 @@ export const useLichessStreamController = (): LichessStreamController => {
6768
isLive: false,
6869
error: null,
6970
gameStarted: false,
71+
gameEnded: false,
7072
})
7173

7274
currentGameId.current = null
@@ -84,25 +86,28 @@ export const useLichessStreamController = (): LichessStreamController => {
8486

8587
const handleGameStart = useCallback(
8688
(gameData: StreamedGame) => {
87-
if (game?.id === gameData.id) {
89+
setGame((prev) => {
90+
console.log('CHECKING FOR GAME END', prev?.id, gameData.id)
8891
// if the game is already loaded, this is a game termination message
89-
setGame((prev) => {
90-
if (!prev) return prev
92+
if (prev?.id === gameData.id) {
93+
console.log('GAME ENDED')
94+
95+
setStreamState((prev) => ({
96+
...prev,
97+
gameEnded: true,
98+
}))
9199

92100
return {
93101
...prev,
94102
termination: {
95-
winner: gameData.winner ?? 'none',
96-
result: gameData.winner ?? 'none',
103+
winner: gameData.winner,
104+
result: gameData.status?.name ?? 'none',
97105
},
98106
}
99-
})
100-
return
101-
}
102-
103-
const parsedGame = createAnalyzedGameFromLichessStream(gameData)
107+
}
104108

105-
setGame(parsedGame)
109+
return createAnalyzedGameFromLichessStream(gameData)
110+
})
106111

107112
setStreamState((prev) => ({
108113
...prev,
@@ -177,6 +182,7 @@ export const useLichessStreamController = (): LichessStreamController => {
177182
...prev,
178183
isConnected: false,
179184
isLive: false,
185+
gameEnded: true,
180186
}))
181187

182188
// DO NOT automatically reconnect when stream completes
@@ -223,6 +229,7 @@ export const useLichessStreamController = (): LichessStreamController => {
223229
isLive: false,
224230
error: errorMessage,
225231
gameStarted: false,
232+
gameEnded: false,
226233
})
227234

228235
abortController.current = null

src/pages/analysis/stream/[gameId].tsx

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ const StreamAnalysisPage: NextPage = () => {
105105
}
106106
}, [streamController.game, analysisController])
107107

108+
// When we finish streaming and load the game, we want to set the current node to the last move
108109
useEffect(() => {
109110
if (streamController.game?.loaded) {
110-
console.log('GAME LOADED')
111111
analysisController.setCurrentNode(
112112
streamController.game.tree.getMainLine()[
113113
streamController.game.tree.getMainLine().length - 1
@@ -116,48 +116,48 @@ const StreamAnalysisPage: NextPage = () => {
116116
}
117117
}, [streamController.game?.loaded])
118118

119-
if (
120-
streamController.streamState.isConnecting &&
121-
!streamController.streamState.gameStarted
122-
) {
123-
return (
124-
<>
125-
<Head>
126-
<title>Connecting to Live Game – Maia Chess</title>
127-
<meta
128-
name="description"
129-
content="Connecting to live chess game stream for real-time analysis with Maia AI."
130-
/>
131-
</Head>
132-
<DelayedLoading isLoading={true}>
133-
<div className="flex flex-col items-center justify-center gap-4">
134-
<div className="text-center">
135-
<h2 className="mb-2 text-xl font-semibold">
136-
{streamController.streamState.error
137-
? 'Connection Error'
138-
: 'Connecting to Live Game'}
139-
</h2>
140-
{streamController.streamState.error ? (
141-
<div className="mb-4 text-red-400">
142-
<p>{streamController.streamState.error}</p>
143-
<button
144-
onClick={streamController.reconnect}
145-
className="mt-2 rounded bg-human-4 px-4 py-2 text-white transition hover:bg-human-4/80"
146-
>
147-
Try Again
148-
</button>
149-
</div>
150-
) : (
151-
<p className="text-secondary">
152-
Establishing connection to Lichess game {gameId}...
153-
</p>
154-
)}
155-
</div>
156-
</div>
157-
</DelayedLoading>
158-
</>
159-
)
160-
}
119+
// if (
120+
// streamController.streamState.isConnecting &&
121+
// !streamController.streamState.gameStarted
122+
// ) {
123+
// return (
124+
// <>
125+
// <Head>
126+
// <title>Connecting to Live Game – Maia Chess</title>
127+
// <meta
128+
// name="description"
129+
// content="Connecting to live chess game stream for real-time analysis with Maia AI."
130+
// />
131+
// </Head>
132+
// <DelayedLoading isLoading={true}>
133+
// <div className="flex flex-col items-center justify-center gap-4">
134+
// <div className="text-center">
135+
// <h2 className="mb-2 text-xl font-semibold">
136+
// {streamController.streamState.error
137+
// ? 'Connection Error'
138+
// : 'Connecting to Live Game'}
139+
// </h2>
140+
// {streamController.streamState.error ? (
141+
// <div className="mb-4 text-red-400">
142+
// <p>{streamController.streamState.error}</p>
143+
// <button
144+
// onClick={streamController.reconnect}
145+
// className="mt-2 rounded bg-human-4 px-4 py-2 text-white transition hover:bg-human-4/80"
146+
// >
147+
// Try Again
148+
// </button>
149+
// </div>
150+
// ) : (
151+
// <p className="text-secondary">
152+
// Establishing connection to Lichess game {gameId}...
153+
// </p>
154+
// )}
155+
// </div>
156+
// </div>
157+
// </DelayedLoading>
158+
// </>
159+
// )
160+
// }
161161

162162
return (
163163
<>
@@ -184,13 +184,15 @@ const StreamAnalysisPage: NextPage = () => {
184184
</AnimatePresence>
185185

186186
<TreeControllerContext.Provider value={analysisController}>
187-
{!streamController.game?.loaded && streamController.game && (
187+
{!streamController.game?.loaded &&
188+
streamController.game &&
189+
!streamController.streamState.gameEnded ? (
188190
<div className="absolute left-0 top-0 z-50">
189191
<DelayedLoading transparent isLoading={true}>
190192
<p>Loading...</p>
191193
</DelayedLoading>
192194
</div>
193-
)}
195+
) : null}
194196
{analysisController && (
195197
<StreamAnalysis
196198
game={streamController.game || dummyGame}

src/types/stream/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export interface StreamedGame {
1818
}
1919
}
2020
}
21-
winner?: 'white' | 'black' | 'none'
21+
winner?: 'white' | 'black'
2222
status?: {
2323
id: number
2424
name: string
@@ -38,6 +38,7 @@ export interface StreamState {
3838
isLive: boolean
3939
error: string | null
4040
gameStarted: boolean
41+
gameEnded: boolean
4142
}
4243

4344
export interface ClockState {

0 commit comments

Comments
 (0)