@@ -9,6 +9,9 @@ import CollabNavigationBar from './CollabNavigationBar';
9
9
import CodeSpace from './CodeSpace' ;
10
10
import { Container , Row , Col } from 'react-bootstrap' ;
11
11
import collabService from '../../services/collab' ;
12
+ import Toast from 'react-bootstrap/Toast' ;
13
+ import ToastContainer from 'react-bootstrap/ToastContainer' ;
14
+ import Spinner from 'react-bootstrap/Spinner' ;
12
15
13
16
const CollaborationSpace = ( ) => {
14
17
const navigate = useNavigate ( ) ;
@@ -22,14 +25,27 @@ const CollaborationSpace = () => {
22
25
const [ language , setLanguage ] = useState ( "python" ) // set default language to python
23
26
const [ output , setOutput ] = useState ( "" )
24
27
25
- // use https://emkc.org/api/v2/piston/runtimes to GET other languages
26
28
const LANGUAGEVERSIONS = {
27
29
"python" : "3.10.0" ,
28
30
"java" : "15.0.2" ,
29
31
"c++" : "10.2.0"
30
- }
32
+ } ;
33
+
34
+ const [ showAccessDeniedToast , setShowAccessDeniedToast ] = useState (
35
+ JSON . parse ( sessionStorage . getItem ( 'showAccessDeniedToast' ) ) || false
36
+ ) ;
37
+ const [ toastMessage , setToastMessage ] = useState ( '' ) ;
38
+ const [ loading , setLoading ] = useState (
39
+ JSON . parse ( sessionStorage . getItem ( 'loading' ) ) !== false
40
+ ) ;
41
+
42
+ const handleCloseToast = ( ) => {
43
+ setShowAccessDeniedToast ( false ) ;
44
+ sessionStorage . setItem ( 'showAccessDeniedToast' , false ) ;
45
+ navigate ( "/home" ) ;
46
+ } ;
31
47
32
- { /* Set up websockets for room management on client side, and collaboration for Yjs */ }
48
+ // Set up websockets for room management on client side, and collaboration for Yjs
33
49
useEffect ( ( ) => {
34
50
const fetchUser = async ( ) => {
35
51
const user = await getUserFromToken ( ) ;
@@ -42,25 +58,40 @@ const CollaborationSpace = () => {
42
58
} ;
43
59
44
60
fetchUser ( ) ;
45
- } , [ ] )
61
+ // Sync states with sessionStorage
62
+ return ( ) => {
63
+ sessionStorage . setItem ( 'loading' , loading ) ;
64
+ sessionStorage . setItem ( 'showAccessDeniedToast' , showAccessDeniedToast ) ;
65
+ } ;
66
+ } , [ loading , showAccessDeniedToast ] ) ;
46
67
47
68
const initiateWebSocket = ( userId ) => {
48
-
49
- // create websocket server for room management
50
69
const websocket = new WebSocket ( "ws://localhost:3004" ) ;
51
70
setWebsocket ( websocket ) ;
52
71
53
72
websocket . onopen = ( ) => {
54
- // notify the server user has joined
55
73
websocket . send ( JSON . stringify ( { type : 'joinRoom' , roomId, userId : userId } ) ) ;
56
- }
74
+
75
+ // Request userIds when matched user rejoins
76
+ websocket . send ( JSON . stringify ( { type : 'requestUserList' , roomId } ) ) ;
77
+ } ;
57
78
58
- // on getting a reply from server
59
79
websocket . onmessage = ( event ) => {
60
80
const data = JSON . parse ( event . data ) ;
81
+ const stringData = JSON . stringify ( data ) ;
82
+ console . log ( `[FRONTEND] data message is ${ stringData } ` ) ;
61
83
switch ( data . type ) {
62
84
case 'usersListUpdate' :
63
- setUsers ( data . users ) ;
85
+ setUsers ( data . users ) ; // Update the user list
86
+ setShowAccessDeniedToast ( false ) ;
87
+ setLoading ( false ) ; // Access allowed; stop loading
88
+ sessionStorage . setItem ( 'loading' , false ) ;
89
+ break ;
90
+ case 'accessDenied' :
91
+ setToastMessage ( data . message ) ;
92
+ setShowAccessDeniedToast ( true ) ;
93
+ setLoading ( false ) ;
94
+ sessionStorage . setItem ( 'showAccessDeniedToast' , true ) ;
64
95
break ;
65
96
default :
66
97
console . log ( "No messages received from room management server" ) ;
@@ -88,69 +119,85 @@ const CollaborationSpace = () => {
88
119
// clean up for room management
89
120
wsProvider . destroy ( ) ;
90
121
doc . destroy ( ) ;
91
- }
92
- }
93
-
94
- { /* Functions to handle interaction with UI elements */ }
122
+ } ;
123
+ } ;
95
124
96
125
const handleExit = ( ) => {
97
- // Notify server 3004 user is leaving
98
126
websocket . send ( JSON . stringify ( { type : 'leaveRoom' , roomId, userId} ) ) ;
99
-
100
- // Clean up Yjs document and provider before going back to home
101
- if ( provider ) {
102
- provider . destroy ( ) ;
103
- }
104
-
105
- if ( yDoc ) {
106
- yDoc . destroy ( ) ;
107
- }
108
-
109
- navigate ( "/home" )
127
+ if ( provider ) provider . destroy ( ) ;
128
+ if ( yDoc ) yDoc . destroy ( ) ;
129
+ navigate ( "/home" ) ;
110
130
} ;
111
131
112
132
const handleCodeRun = ( ) => {
113
133
const code_message = {
114
134
"language" : language ,
115
- "files" : [
116
- {
117
- "content" : code
118
- }
119
- ] ,
135
+ "files" : [ { "content" : code } ] ,
120
136
"version" : LANGUAGEVERSIONS [ language ]
121
- }
137
+ } ;
122
138
123
139
collabService . getCodeOutput ( code_message )
124
- . then ( result => {
125
- console . log ( result . data . run . output )
126
- setOutput ( result . data . run . output )
127
- } )
140
+ . then ( result => setOutput ( result . data . run . output ) )
128
141
. catch ( err => console . log ( err ) ) ;
129
-
130
- }
142
+ } ;
131
143
132
144
const handleEditorChange = ( value ) => {
133
145
const yText = yDoc . getText ( 'monacoEditor' ) ;
134
- yText . delete ( 0 , yText . length ) ; // Clear existing content
135
- yText . insert ( 0 , value ) ; // Insert new content
146
+ yText . delete ( 0 , yText . length ) ;
147
+ yText . insert ( 0 , value ) ;
148
+ } ;
149
+
150
+ if ( loading ) {
151
+ return (
152
+ < div style = { { textAlign : 'center' , marginTop : '50px' } } >
153
+ < Spinner animation = "border" variant = "primary" role = "status" >
154
+ < span className = "visually-hidden" > Loading...</ span >
155
+ </ Spinner >
156
+ < p > Loading collaboration space...</ p >
157
+ </ div >
158
+ ) ;
136
159
}
137
160
138
161
return (
139
- < div >
140
- < CollabNavigationBar handleExit = { handleExit } handleCodeRun = { handleCodeRun } users = { users } setLanguage = { setLanguage } language = { language } />
141
- < Container fluid style = { { marginTop : '20px' } } >
142
- < Row >
143
- < Col md = { 8 } >
144
- < CodeSpace handleEditorChange = { handleEditorChange } code = { code } language = { language } output = { output } />
145
- </ Col >
146
- < Col md = { 4 } >
147
- < QuestionDisplay />
148
- < Chat />
149
- </ Col >
150
- </ Row >
151
- </ Container >
162
+ < div style = { { textAlign : 'center' , marginTop : '50px' } } >
163
+ { 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 >
184
+ < CollabNavigationBar handleExit = { handleExit } handleCodeRun = { handleCodeRun } users = { users } setLanguage = { setLanguage } language = { language } />
185
+ < Container fluid style = { { marginTop : '20px' } } >
186
+ < Row >
187
+ < Col md = { 8 } >
188
+ < CodeSpace handleEditorChange = { handleEditorChange } code = { code } language = { language } output = { output } />
189
+ </ Col >
190
+ < Col md = { 4 } >
191
+ < QuestionDisplay />
192
+ < Chat />
193
+ </ Col >
194
+ </ Row >
195
+ </ Container >
196
+ </ div >
197
+ </ >
198
+ ) }
152
199
</ div >
153
200
) ;
154
201
} ;
155
202
156
- export default CollaborationSpace ;
203
+ export default CollaborationSpace ;
0 commit comments