@@ -2,7 +2,13 @@ import React, { useCallback, useEffect, useState } from "react"
2
2
3
3
import { StompSessionProvider , useSubscription } from "react-stomp-hooks"
4
4
import { useAppDispatch , useAppSelector } from "../../caches/hooks"
5
- import { getGameId , getIsMyGo , updateGame } from "../../caches/GameSlice"
5
+ import {
6
+ disableActions ,
7
+ getGameId ,
8
+ getIsMyGo ,
9
+ updateGame ,
10
+ updatePlayedCards ,
11
+ } from "../../caches/GameSlice"
6
12
import { getAccessToken } from "../../caches/MyProfileSlice"
7
13
import { getPlayerProfiles } from "../../caches/PlayerProfilesSlice"
8
14
import { GameState } from "../../model/Game"
@@ -16,6 +22,7 @@ import playCardAudioFile from "../../assets/sounds/play_card.ogg"
16
22
import callAudioFile from "../../assets/sounds/call.ogg"
17
23
import passAudioFile from "../../assets/sounds/pass.ogg"
18
24
import AutoActionManager from "./AutoActionManager"
25
+ import { Round } from "../../model/Round"
19
26
20
27
const shuffleAudio = new Audio ( shuffleAudioFile )
21
28
const playCardAudio = new Audio ( playCardAudioFile )
@@ -44,7 +51,8 @@ const passSound = () => {
44
51
45
52
interface ActionEvent {
46
53
type : Actions
47
- content : unknown
54
+ gameState : GameState
55
+ transitionData : unknown
48
56
}
49
57
50
58
const WebsocketHandler = ( ) => {
@@ -55,100 +63,129 @@ const WebsocketHandler = () => {
55
63
const playerProfiles = useAppSelector ( getPlayerProfiles )
56
64
const { enqueueSnackbar } = useSnackbar ( )
57
65
58
- const [ previousAction , updatePreviousAction ] = useState < Actions > ( )
59
-
60
66
// Enable the auto action manager after a delay if it isn't already active
61
67
useEffect ( ( ) => {
62
68
setTimeout ( ( ) => {
63
69
if ( ! autoActionEnabled ) setAutoActionEnabled ( true )
64
70
} , 2000 )
65
71
} , [ autoActionEnabled ] )
66
72
67
- const handleWebsocketMessage = useCallback (
68
- ( message : string ) => {
69
- if ( previousAction === "LAST_CARD_PLAYED" ) {
70
- console . info (
71
- "Waiting on last card to allow time to view cards..." ,
72
- )
73
- setTimeout ( ( ) => processWebsocketMessage ( message ) , 4000 )
74
- } else {
75
- processWebsocketMessage ( message )
76
- }
77
- } ,
78
- [ previousAction ] ,
79
- )
80
-
81
- const processWebsocketMessage = ( message : string ) => {
73
+ const handleWebsocketMessage = ( message : string ) => {
82
74
const payload = JSON . parse ( message )
83
75
const actionEvent = JSON . parse ( payload . payload ) as ActionEvent
84
76
85
- updatePreviousAction ( actionEvent . type )
86
- processActons ( actionEvent . type , actionEvent . content )
87
-
88
- if ( actionEvent . type !== Actions . BuyCardsNotification ) {
89
- const gameState = actionEvent . content as GameState
90
- dispatch ( updateGame ( gameState ) )
91
- }
77
+ processAction ( actionEvent )
92
78
93
79
// Only enable the auto action manager when we have successfully processed a message
94
80
if ( ! autoActionEnabled ) setAutoActionEnabled ( true )
95
81
}
96
82
97
- const reloadCards = ( payload : unknown , clearSelected = false ) => {
98
- const gameState = payload as GameState
83
+ const sendCardsBoughtNotification = useCallback (
84
+ ( buyCardsEvt : BuyCardsEvent ) => {
85
+ const player = playerProfiles . find (
86
+ p => p . id === buyCardsEvt . playerId ,
87
+ )
88
+ if ( player )
89
+ enqueueSnackbar ( `${ player . name } bought ${ buyCardsEvt . bought } ` )
90
+ } ,
91
+ [ playerProfiles ] ,
92
+ )
99
93
94
+ const reloadCards = ( cards : string [ ] , clearSelected = false ) => {
100
95
if ( clearSelected ) {
101
96
dispatch ( clearSelectedCards ( ) )
102
97
dispatch ( clearAutoPlay ( ) )
103
98
}
104
- dispatch ( updateMyCards ( gameState . cards ) )
99
+ dispatch ( updateMyCards ( cards ) )
105
100
}
106
101
107
- const processActons = useCallback (
108
- ( type : Actions , payload : unknown ) => {
109
- switch ( type ) {
110
- case "DEAL" :
111
- shuffleSound ( )
112
- reloadCards ( payload , true )
113
- break
114
- case "CHOOSE_FROM_DUMMY" :
115
- case "BUY_CARDS" :
116
- case "LAST_CARD_PLAYED" :
117
- case "CARD_PLAYED" :
118
- playCardSound ( )
119
- reloadCards ( payload , isMyGo )
120
- break
121
- case "REPLAY" :
122
- break
123
- case "GAME_OVER" :
124
- break
125
- case "BUY_CARDS_NOTIFICATION" :
126
- const buyCardsEvt = payload as BuyCardsEvent
127
- const player = playerProfiles . find (
128
- p => p . id === buyCardsEvt . playerId ,
129
- )
130
- if ( ! player ) {
131
- break
132
- }
102
+ // On hand completion we need to display the last card to the user
103
+ const processHandCompleted = async (
104
+ game : GameState ,
105
+ previousRound : Round ,
106
+ ) => {
107
+ // Disable actions by setting isMyGo to false
108
+ dispatch ( disableActions ( ) )
109
+
110
+ // Show the last card of the last roung being played
111
+ playCardSound ( )
112
+ dispatch ( updatePlayedCards ( previousRound . currentHand . playedCards ) )
113
+ await new Promise ( r => setTimeout ( r , 4000 ) )
114
+
115
+ // Finally update the game with the latest state
116
+ dispatch ( updateGame ( game ) )
117
+ dispatch ( updateMyCards ( game . cards ) )
118
+ }
133
119
134
- enqueueSnackbar (
135
- `${ player . name } bought ${ buyCardsEvt . bought } ` ,
136
- )
120
+ // On round completion we need to display the last round to the user
121
+ const processRoundCompleted = async (
122
+ game : GameState ,
123
+ previousRound : Round ,
124
+ ) => {
125
+ // Disable actions by setting isMyGo to false
126
+ dispatch ( disableActions ( ) )
127
+
128
+ // Show the last card of the penultimate round being played
129
+ playCardSound ( )
130
+ const penultimateHand = previousRound . completedHands . pop ( )
131
+ if ( ! penultimateHand ) throw Error ( "Failed to get the penultimate round" )
132
+ dispatch ( updatePlayedCards ( penultimateHand . playedCards ) )
133
+ await new Promise ( r => setTimeout ( r , 4000 ) )
134
+
135
+ // Next show the final round being played
136
+ playCardSound ( )
137
+ dispatch ( updatePlayedCards ( previousRound . currentHand . playedCards ) )
138
+ dispatch ( updateMyCards ( [ ] ) )
139
+ await new Promise ( r => setTimeout ( r , 6000 ) )
140
+
141
+ // Finally update the game with the latest state
142
+ shuffleSound ( )
143
+ dispatch ( updateGame ( game ) )
144
+ dispatch ( updateMyCards ( game . cards ) )
145
+ }
137
146
138
- break
147
+ const processAction = useCallback (
148
+ async ( action : ActionEvent ) => {
149
+ console . log ( action . type )
150
+ switch ( action . type ) {
139
151
case "HAND_COMPLETED" :
152
+ await processHandCompleted (
153
+ action . gameState ,
154
+ action . transitionData as Round ,
155
+ )
140
156
break
141
157
case "ROUND_COMPLETED" :
142
- reloadCards ( payload )
158
+ await processRoundCompleted (
159
+ action . gameState ,
160
+ action . transitionData as Round ,
161
+ )
162
+ break
163
+ case "BUY_CARDS" :
164
+ const buyCardsEvt = action . transitionData as BuyCardsEvent
165
+ sendCardsBoughtNotification ( buyCardsEvt )
166
+ reloadCards ( action . gameState . cards , isMyGo )
167
+ dispatch ( updateGame ( action . gameState ) )
168
+ break
169
+ case "CHOOSE_FROM_DUMMY" :
170
+ case "CARD_PLAYED" :
171
+ playCardSound ( )
172
+ reloadCards ( action . gameState . cards , isMyGo )
173
+ dispatch ( updateGame ( action . gameState ) )
143
174
break
144
175
case "CALL" :
145
176
callSound ( )
146
- reloadCards ( payload , true )
177
+ reloadCards ( action . gameState . cards , true )
178
+ dispatch ( updateGame ( action . gameState ) )
147
179
break
148
180
case "PASS" :
149
181
passSound ( )
150
- reloadCards ( payload , true )
182
+ reloadCards ( action . gameState . cards , true )
183
+ dispatch ( updateGame ( action . gameState ) )
151
184
break
185
+
186
+ case "REPLAY" :
187
+ case "GAME_OVER" :
188
+ dispatch ( updateGame ( action . gameState ) )
152
189
}
153
190
} ,
154
191
[ playerProfiles , isMyGo ] ,
0 commit comments