@@ -22,6 +22,7 @@ import AudioSharing from './AudioSharing';
22
22
interface CollaborationEditorProps {
23
23
matchId : string | null ;
24
24
}
25
+ type AwarenessStates = Map < number , AwarenessState > ;
25
26
26
27
const CollaborationEditor = ( { matchId } : CollaborationEditorProps ) => {
27
28
const { user } = useAuthStore ( ) ;
@@ -30,7 +31,6 @@ const CollaborationEditor = ({ matchId }: CollaborationEditorProps) => {
30
31
Map < number , ConnectedClient >
31
32
> ( new Map ( ) ) ;
32
33
33
- // Refs for persistent state
34
34
const providerRef = useRef < WebsocketProvider | null > ( null ) ;
35
35
const bindingRef = useRef < MonacoBinding | null > ( null ) ;
36
36
const editorRef = useRef < MonacoEditor . IStandaloneCodeEditor | null > ( null ) ;
@@ -46,21 +46,20 @@ const CollaborationEditor = ({ matchId }: CollaborationEditorProps) => {
46
46
const { clearLastMatchId } = useCollaborationStore ( ) ;
47
47
const router = useRouter ( ) ;
48
48
49
- const TOAST_DEBOUNCE = 1000 ; // Minimum time between toasts
49
+ const TOAST_DEBOUNCE = 1000 ;
50
50
51
51
const onLanguageChange = ( language : string ) => {
52
52
setLanguage ( language ) ;
53
53
} ;
54
54
55
- const handleClientStateChange = ( states : Map < any , any > ) => {
55
+ const handleClientStateChange = ( states : AwarenessStates ) => {
56
56
const now = Date . now ( ) ;
57
57
if ( now - lastUpdateTimeRef . current < TOAST_DEBOUNCE ) {
58
58
return ;
59
59
}
60
60
61
61
const newClients = new Map < number , ConnectedClient > ( ) ;
62
- states . forEach ( ( value : { [ x : string ] : any } ) => {
63
- const state = value as AwarenessState ;
62
+ states . forEach ( ( state : AwarenessState ) => {
64
63
if ( state . client ) {
65
64
newClients . set ( state . client , {
66
65
id : state . client ,
@@ -69,15 +68,12 @@ const CollaborationEditor = ({ matchId }: CollaborationEditorProps) => {
69
68
}
70
69
} ) ;
71
70
72
- // Clear any pending timeout
73
71
if ( clientChangeTimeoutRef . current ) {
74
72
clearTimeout ( clientChangeTimeoutRef . current ) ;
75
73
}
76
74
77
- // Set a new timeout to handle the change
78
75
clientChangeTimeoutRef . current = setTimeout ( ( ) => {
79
76
if ( newClients . size !== prevClientsRef . current . size ) {
80
- // Check for new connections
81
77
const newConnectedUsers = Array . from ( newClients . values ( ) )
82
78
. filter (
83
79
( client ) =>
@@ -103,7 +99,6 @@ const CollaborationEditor = ({ matchId }: CollaborationEditorProps) => {
103
99
} ) ;
104
100
}
105
101
106
- // Check for disconnections
107
102
Array . from ( prevClientsRef . current . values ( ) ) . forEach ( ( prevClient ) => {
108
103
if (
109
104
! Array . from ( newClients . values ( ) ) . some (
@@ -123,7 +118,7 @@ const CollaborationEditor = ({ matchId }: CollaborationEditorProps) => {
123
118
124
119
prevClientsRef . current = newClients ;
125
120
setConnectedClients ( newClients ) ;
126
- } , 500 ) ; // Debounce time for client changes
121
+ } , 500 ) ;
127
122
} ;
128
123
129
124
const initializeWebSocket = ( editor : MonacoEditor . IStandaloneCodeEditor ) => {
@@ -132,30 +127,27 @@ const CollaborationEditor = ({ matchId }: CollaborationEditorProps) => {
132
127
return ;
133
128
}
134
129
135
- // If we already have a connection, don't reinitialize
136
130
if ( providerRef . current ?. wsconnected ) {
137
131
console . log ( 'Reusing existing WebSocket connection' ) ;
138
132
return ;
139
133
}
140
134
141
135
console . log ( 'Initializing new WebSocket connection' ) ;
142
136
143
- // Create new Y.Doc if it doesn't exist
144
137
if ( ! docRef . current ) {
145
138
docRef . current = new Y . Doc ( ) ;
146
139
}
147
140
148
- // Create new WebSocket provider with valid configuration options
149
141
providerRef . current = new WebsocketProvider (
150
142
sockServerURI ,
151
143
matchId ,
152
144
docRef . current ,
153
145
{
154
146
connect : true ,
155
- resyncInterval : 3000 , // Time between resync attempts
156
- disableBc : true , // Disable broadcast channel to prevent duplicate connections
147
+ resyncInterval : 3000 ,
148
+ disableBc : true ,
157
149
params : {
158
- version : '1.0.0' , // Optional version parameter
150
+ version : '1.0.0' ,
159
151
} ,
160
152
} ,
161
153
) ;
@@ -170,7 +162,6 @@ const CollaborationEditor = ({ matchId }: CollaborationEditorProps) => {
170
162
} ,
171
163
} ) ;
172
164
173
- // Add connection status handlers
174
165
providerRef . current . on ( 'status' , ( { status } : { status : string } ) => {
175
166
console . log ( 'WebSocket status:' , status ) ;
176
167
} ) ;
@@ -179,19 +170,18 @@ const CollaborationEditor = ({ matchId }: CollaborationEditorProps) => {
179
170
console . error ( 'WebSocket connection error:' , event ) ;
180
171
} ) ;
181
172
182
- // Set up awareness change handler with debouncing
183
173
let changeTimeout : NodeJS . Timeout ;
184
174
providerRef . current . awareness . on ( 'change' , ( ) => {
185
175
clearTimeout ( changeTimeout ) ;
186
176
changeTimeout = setTimeout ( ( ) => {
187
- const states = providerRef . current ?. awareness . getStates ( ) ;
177
+ const states =
178
+ providerRef . current ?. awareness . getStates ( ) as AwarenessStates ;
188
179
if ( states ) {
189
180
handleClientStateChange ( states ) ;
190
181
}
191
182
} , 100 ) ;
192
183
} ) ;
193
184
194
- // Set up Monaco binding
195
185
const model = editor . getModel ( ) ;
196
186
if ( editor && model ) {
197
187
bindingRef . current = new MonacoBinding (
@@ -208,7 +198,6 @@ const CollaborationEditor = ({ matchId }: CollaborationEditorProps) => {
208
198
initializeWebSocket ( editor ) ;
209
199
} ;
210
200
211
- // Cleanup function
212
201
const cleanup = ( force = false ) => {
213
202
if ( clientChangeTimeoutRef . current ) {
214
203
clearTimeout ( clientChangeTimeoutRef . current ) ;
@@ -241,23 +230,19 @@ const CollaborationEditor = ({ matchId }: CollaborationEditorProps) => {
241
230
}
242
231
} ;
243
232
244
- // Mount/unmount handling
245
233
useEffect ( ( ) => {
246
- mountCountRef . current ++ ;
247
- console . log ( `Editor component mounted (count: ${ mountCountRef . current } )` ) ;
234
+ const currentMountCount = mountCountRef . current + 1 ;
235
+ mountCountRef . current = currentMountCount ;
236
+ console . log ( `Editor component mounted (count: ${ currentMountCount } )` ) ;
248
237
249
238
return ( ) => {
250
- mountCountRef . current -- ;
251
- console . log (
252
- `Editor component unmounting (count: ${ mountCountRef . current } )` ,
253
- ) ;
254
-
255
- // Only do full cleanup when last instance unmounts
256
- cleanup ( mountCountRef . current === 0 ) ;
239
+ const finalMountCount = currentMountCount - 1 ;
240
+ mountCountRef . current = finalMountCount ;
241
+ console . log ( `Editor component unmounting (count: ${ finalMountCount } )` ) ;
242
+ cleanup ( finalMountCount === 0 ) ;
257
243
} ;
258
244
} , [ ] ) ;
259
245
260
- // Handle page unload
261
246
useEffect ( ( ) => {
262
247
const handleUnload = ( ) => {
263
248
cleanup ( true ) ;
0 commit comments