1
- import React , { createContext , useState , useContext , ReactNode , useEffect , useMemo , useCallback } from "react" ;
1
+ import React , { createContext , useState , useContext , ReactNode , useEffect } from "react" ;
2
2
import * as Y from "yjs" ;
3
3
import * as monaco from "monaco-editor" ;
4
4
import { MonacoBinding } from "y-monaco" ;
@@ -48,78 +48,65 @@ export const CollaborationProvider: React.FC<{ children: ReactNode }> = ({ child
48
48
const [ binding , setBinding ] = useState < MonacoBinding | null > ( null ) ;
49
49
50
50
useEffect ( ( ) => {
51
- if ( roomId == null ) {
52
- console . log ( `RoomId is null!` )
53
- return ;
54
- }
55
- console . log ( `Starting Collaboration Context with roomId: ${ roomId } ` )
56
-
57
- const provider = new WebsocketProvider ( `ws://localhost:3004/${ roomId } ` , roomId , new Y . Doc ( ) ) ;
51
+ if ( ! roomId ) return ;
52
+ const ydoc = new Y . Doc ( ) ;
53
+ const provider = new WebsocketProvider ( `ws://localhost:3004/${ roomId } ` , roomId , ydoc ) ;
58
54
setProvider ( provider ) ;
59
55
60
56
provider . awareness . setLocalStateField ( USERNAME , username ) ;
61
- provider . awareness . on ( "change" , ( update : any ) => {
57
+ provider . awareness . on ( "change" , ( ) => {
62
58
const users = Array . from ( provider . awareness . getStates ( ) . values ( ) ) ;
63
59
setConnectedUsers ( users . map ( ( user ) => user [ USERNAME ] ) ) ;
64
- // TODO: Some UI feedback about connection status of the other user
65
60
} ) ;
66
61
67
- return ( ) => {
68
- provider ?. destroy ( ) ;
69
- } ;
70
- } , [ roomId ] ) ;
62
+ return ( ) => provider . destroy ( ) ;
63
+ } , [ roomId , username , USERNAME ] ) ;
71
64
72
- // Set up Monaco editor with server-managed Yjs document useEffect(() => {
73
- if ( ! provider || ! editor ?. getModel ( ) ) return ;
65
+ useEffect ( ( ) => {
66
+ if ( ! provider || ! editor ) return ;
74
67
75
- // Access the server-managed ydoc via provider.doc
76
68
const ytext = provider . doc . getText ( "monaco" ) ;
77
69
const binding = new MonacoBinding ( ytext , editor . getModel ( ) ! , new Set ( [ editor ] ) , provider . awareness ) ;
78
70
setBinding ( binding ) ;
79
71
80
- // Listen for changes in selected language from the shared Yjs map
81
72
const ymap = provider . doc . getMap ( "sharedMap" ) ;
82
73
ymap . observe ( ( event ) => {
83
- event . changes . keys . forEach ( ( change , key ) => {
84
- if ( key === SELECTED_LANGUAGE ) {
85
- const language : Language = ymap . get ( SELECTED_LANGUAGE ) as Language ;
86
- setSelectedLanguage ( language ) ;
87
- monaco . editor . setModelLanguage ( editor . getModel ( ) ! , language . language ) ;
88
- }
89
- } ) ;
74
+ if ( event . changes . keys . has ( SELECTED_LANGUAGE ) ) {
75
+ const language = ymap . get ( SELECTED_LANGUAGE ) as Language ;
76
+ setSelectedLanguage ( language ) ;
77
+ monaco . editor . setModelLanguage ( editor . getModel ( ) ! , language . language ) ;
78
+ }
90
79
} ) ;
91
80
92
-
93
- // Initialize editor language from the shared Yjs map
94
- const language = ymap . get ( SELECTED_LANGUAGE ) as Language ;
95
- const model = editor . getModel ( ) ;
96
- monaco . editor . setModelLanguage ( model ! , language ?. language ?? "javascript" ) ;
81
+ const initialLanguage = ymap . get ( SELECTED_LANGUAGE ) as Language ;
82
+ if ( initialLanguage ) {
83
+ setSelectedLanguage ( initialLanguage ) ;
84
+ monaco . editor . setModelLanguage ( editor . getModel ( ) ! , initialLanguage . language ) ;
85
+ }
97
86
98
87
return ( ) => binding . destroy ( ) ;
99
- } , [ provider , editor ] ) ;
88
+ } , [ provider , editor , SELECTED_LANGUAGE ] ) ;
100
89
101
90
useEffect ( ( ) => {
102
- console . log ( "Initialising Languages!" ) ;
91
+ const initialiseLanguages = async ( ) => {
92
+ const allLanguages = monaco . languages . getLanguages ( ) ;
93
+ const pistonLanguageVersions = await PistonClient . getLanguageVersions ( ) ;
94
+ setLanguages (
95
+ allLanguages
96
+ . filter ( ( lang ) => pistonLanguageVersions . some ( ( pistonLang : any ) => pistonLang . language === lang . id ) )
97
+ . map ( ( lang ) => ( {
98
+ alias : lang . aliases ?. [ 0 ] || lang . id ,
99
+ language : lang . id ,
100
+ version : pistonLanguageVersions . find ( ( pistonLang : any ) => pistonLang . language === lang . id )
101
+ ?. version
102
+ } ) )
103
+ ) ;
104
+ } ;
103
105
initialiseLanguages ( ) ;
104
106
} , [ ] ) ;
105
107
106
- const initialiseLanguages = async ( ) => {
107
- const allLanguages = monaco . languages . getLanguages ( ) ;
108
- const pistonLanguageVersions = await PistonClient . getLanguageVersions ( ) ;
109
- setLanguages (
110
- allLanguages
111
- . filter ( ( lang ) => pistonLanguageVersions . some ( ( pistonLang : any ) => pistonLang . language === lang . id ) )
112
- . map ( ( lang ) => ( {
113
- alias : lang . aliases ?. [ 0 ] || lang . id ,
114
- language : lang . id ,
115
- version : pistonLanguageVersions . find ( ( pistonLang : any ) => pistonLang . language === lang . id ) ?. version
116
- } ) )
117
- ) ;
118
- } ;
119
-
120
108
const handleChangeLanguage = ( lang : Language ) => {
121
- const ymap = provider ?. doc . getMap ( "sharedMap" ) ;
122
- ymap ?. set ( SELECTED_LANGUAGE , lang ) ;
109
+ provider ?. doc . getMap ( "sharedMap" ) ?. set ( SELECTED_LANGUAGE , lang ) ;
123
110
} ;
124
111
125
112
const handleExecuteCode = async ( ) => {
@@ -130,16 +117,14 @@ export const CollaborationProvider: React.FC<{ children: ReactNode }> = ({ child
130
117
131
118
const output = await PistonClient . executeCode ( selectedLanguage , sourceCode ) ;
132
119
setExecResult ( output ) ;
133
- } catch ( e ) {
120
+ } catch {
134
121
toast . error ( "There was an issue running the code" ) ;
135
122
} finally {
136
123
setIsExecuting ( false ) ;
137
124
}
138
125
} ;
139
126
140
- const onEditorIsMounted = ( editor : monaco . editor . IStandaloneCodeEditor ) => {
141
- setEditor ( editor ) ;
142
- } ;
127
+ const onEditorIsMounted = ( editor : monaco . editor . IStandaloneCodeEditor ) => setEditor ( editor ) ;
143
128
144
129
return (
145
130
< CollaborationContext . Provider
@@ -153,7 +138,7 @@ export const CollaborationProvider: React.FC<{ children: ReactNode }> = ({ child
153
138
isExecuting,
154
139
execResult,
155
140
connectedUsers,
156
- disconnect
141
+ disconnect : ( ) => provider ?. disconnect ( )
157
142
} }
158
143
>
159
144
{ children }
0 commit comments