1
- import React , { useEffect , useState } from 'react' ;
1
+ import React , { useEffect , useState , useRef } from 'react' ;
2
2
import { useParams , useNavigate } from 'react-router-dom' ;
3
3
import * as Y from 'yjs' ;
4
4
import { WebsocketProvider } from 'y-websocket' ;
@@ -16,32 +16,27 @@ import Spinner from 'react-bootstrap/Spinner';
16
16
const CollaborationSpace = ( ) => {
17
17
const navigate = useNavigate ( ) ;
18
18
const { roomId } = useParams ( ) ; // Get the roomId from the URL
19
+ const websocketRef = useRef ( null ) ; // Use ref to persist websocket across renders
19
20
const [ yDoc , setYDoc ] = useState ( null ) ;
20
21
const [ provider , setProvider ] = useState ( null ) ;
21
- const [ websocket , setWebsocket ] = useState ( null ) ; // add websocket state to be access by other functions
22
22
const [ code , setCode ] = useState ( '' ) ;
23
- const [ users , setUsers ] = useState ( [ ] ) ; // track users in the room
24
- const [ userId , setUserId ] = useState ( "" ) ; // current user
25
- const [ language , setLanguage ] = useState ( "python" ) // set default language to python
26
- const [ output , setOutput ] = useState ( "" )
27
-
23
+ const [ users , setUsers ] = useState ( [ ] ) ; // Track users in the room
24
+ const [ userId , setUserId ] = useState ( "" ) ; // Current user
25
+ const [ language , setLanguage ] = useState ( "python" ) ; // Set default language to python
26
+ const [ output , setOutput ] = useState ( "" ) ;
27
+
28
28
const LANGUAGEVERSIONS = {
29
29
"python" : "3.10.0" ,
30
30
"java" : "15.0.2" ,
31
31
"c++" : "10.2.0"
32
32
} ;
33
33
34
- const [ showAccessDeniedToast , setShowAccessDeniedToast ] = useState (
35
- JSON . parse ( sessionStorage . getItem ( 'showAccessDeniedToast' ) ) || false
36
- ) ;
34
+ const [ showAccessDeniedToast , setShowAccessDeniedToast ] = useState ( false ) ;
37
35
const [ toastMessage , setToastMessage ] = useState ( '' ) ;
38
- const [ loading , setLoading ] = useState (
39
- JSON . parse ( sessionStorage . getItem ( 'loading' ) ) !== false
40
- ) ;
36
+ const [ loading , setLoading ] = useState ( true ) ;
41
37
42
38
const handleCloseToast = ( ) => {
43
39
setShowAccessDeniedToast ( false ) ;
44
- sessionStorage . setItem ( 'showAccessDeniedToast' , false ) ;
45
40
navigate ( "/home" ) ;
46
41
} ;
47
42
@@ -58,74 +53,61 @@ const CollaborationSpace = () => {
58
53
} ;
59
54
60
55
fetchUser ( ) ;
61
- // Sync states with sessionStorage
56
+
62
57
return ( ) => {
63
- sessionStorage . setItem ( 'loading' , loading ) ;
64
- sessionStorage . setItem ( 'showAccessDeniedToast' , showAccessDeniedToast ) ;
58
+ if ( websocketRef . current ) {
59
+ websocketRef . current . close ( ) ;
60
+ websocketRef . current = null ;
61
+ }
62
+ if ( provider ) provider . destroy ( ) ;
63
+ if ( yDoc ) yDoc . destroy ( ) ;
65
64
} ;
66
- } , [ loading , showAccessDeniedToast ] ) ;
65
+ } , [ ] ) ;
67
66
68
67
const initiateWebSocket = ( userId ) => {
68
+ if ( websocketRef . current ) return ; // Prevent duplicate connections
69
69
const websocket = new WebSocket ( "ws://localhost:3004" ) ;
70
- setWebsocket ( websocket ) ;
70
+ websocketRef . current = websocket ;
71
71
72
72
websocket . onopen = ( ) => {
73
- websocket . send ( JSON . stringify ( { type : 'joinRoom' , roomId, userId : userId } ) ) ;
74
-
75
- // Request userIds when matched user rejoins
73
+ websocket . send ( JSON . stringify ( { type : 'joinRoom' , roomId, userId } ) ) ;
76
74
websocket . send ( JSON . stringify ( { type : 'requestUserList' , roomId } ) ) ;
77
75
} ;
78
76
79
77
websocket . onmessage = ( event ) => {
80
78
const data = JSON . parse ( event . data ) ;
81
- const stringData = JSON . stringify ( data ) ;
82
- console . log ( `[FRONTEND] data message is ${ stringData } ` ) ;
79
+ console . log ( `[FRONTEND] data message is ${ JSON . stringify ( data ) } ` ) ;
83
80
switch ( data . type ) {
84
81
case 'usersListUpdate' :
85
- setUsers ( data . users ) ; // Update the user list
82
+ setUsers ( data . users ) ; // Update the user list
86
83
setShowAccessDeniedToast ( false ) ;
87
- setLoading ( false ) ; // Access allowed; stop loading
88
- sessionStorage . setItem ( 'loading' , false ) ;
84
+ setLoading ( false ) ; // Access allowed; stop loading
89
85
break ;
90
86
case 'accessDenied' :
91
87
setToastMessage ( data . message ) ;
92
88
setShowAccessDeniedToast ( true ) ;
93
89
setLoading ( false ) ;
94
- sessionStorage . setItem ( 'showAccessDeniedToast' , true ) ;
95
90
break ;
96
91
default :
97
92
console . log ( "No messages received from room management server" ) ;
98
93
break ;
99
94
}
100
95
} ;
101
96
102
- // create a Yjs document for collaboration
103
97
const doc = new Y . Doc ( ) ;
104
98
setYDoc ( doc ) ;
105
99
106
- // create websocket provider to synchronize the document
107
100
const wsProvider = new WebsocketProvider ( "ws://localhost:1234" , roomId , doc ) ;
108
101
setProvider ( wsProvider ) ;
109
102
110
- // Create a shared type in Yjs for collaborative code editing
111
103
const yText = doc . getText ( 'monacoEditor' ) ;
112
-
113
- // Update monaco editor with Yjs changes
114
104
yText . observe ( ( ) => {
115
105
setCode ( yText . toString ( ) ) ;
116
106
} ) ;
117
-
118
- return ( ) => {
119
- // clean up for room management
120
- wsProvider . destroy ( ) ;
121
- doc . destroy ( ) ;
122
- } ;
123
107
} ;
124
108
125
109
const handleExit = ( ) => {
126
- websocket . send ( JSON . stringify ( { type : 'leaveRoom' , roomId, userId} ) ) ;
127
- if ( provider ) provider . destroy ( ) ;
128
- if ( yDoc ) yDoc . destroy ( ) ;
110
+ if ( websocketRef . current ) websocketRef . current . send ( JSON . stringify ( { type : 'leaveRoom' , roomId, userId } ) ) ;
129
111
navigate ( "/home" ) ;
130
112
} ;
131
113
@@ -137,8 +119,8 @@ const CollaborationSpace = () => {
137
119
} ;
138
120
139
121
collabService . getCodeOutput ( code_message )
140
- . then ( result => setOutput ( result . data . run . output ) )
141
- . catch ( err => console . log ( err ) ) ;
122
+ . then ( result => setOutput ( result . data . run . output ) )
123
+ . catch ( err => console . log ( err ) ) ;
142
124
} ;
143
125
144
126
const handleEditorChange = ( value ) => {
@@ -149,7 +131,7 @@ const CollaborationSpace = () => {
149
131
150
132
if ( loading ) {
151
133
return (
152
- < div style = { { textAlign : 'center' , marginTop : '50px' } } >
134
+ < div style = { { textAlign : 'center' } } >
153
135
< Spinner animation = "border" variant = "primary" role = "status" >
154
136
< span className = "visually-hidden" > Loading...</ span >
155
137
</ Spinner >
@@ -161,26 +143,21 @@ const CollaborationSpace = () => {
161
143
return (
162
144
< div style = { { textAlign : 'center' } } >
163
145
{ showAccessDeniedToast ? (
164
- < ToastContainer
165
- className = "p-3"
166
- position = "top-center"
167
- style = { { zIndex : 1 } }
168
- >
169
- < Toast
170
- onClose = { handleCloseToast }
171
- show = { showAccessDeniedToast }
172
- delay = { 3000 }
173
- autohide
174
- bg = "danger"
175
- >
176
- < Toast . Body className = 'text-white' >
177
- < strong > { toastMessage } </ strong >
178
- </ Toast . Body >
179
- </ Toast >
180
- </ ToastContainer >
181
- ) : (
182
- < >
183
- < div >
146
+ < ToastContainer className = "p-3" position = "top-center" style = { { zIndex : 1 } } >
147
+ < Toast
148
+ onClose = { handleCloseToast }
149
+ show = { showAccessDeniedToast }
150
+ delay = { 3000 }
151
+ autohide
152
+ bg = "danger"
153
+ >
154
+ < Toast . Body className = 'text-white' >
155
+ < strong > { toastMessage } </ strong >
156
+ </ Toast . Body >
157
+ </ Toast >
158
+ </ ToastContainer >
159
+ ) : (
160
+ < >
184
161
< CollabNavigationBar handleExit = { handleExit } handleCodeRun = { handleCodeRun } users = { users } setLanguage = { setLanguage } language = { language } />
185
162
< Container fluid style = { { marginTop : '20px' } } >
186
163
< Row >
@@ -193,11 +170,10 @@ const CollaborationSpace = () => {
193
170
</ Col >
194
171
</ Row >
195
172
</ Container >
196
- </ div >
197
- </ >
198
- ) }
173
+ </ >
174
+ ) }
199
175
</ div >
200
176
) ;
201
177
} ;
202
178
203
- export default CollaborationSpace ;
179
+ export default CollaborationSpace ;
0 commit comments