@@ -8,8 +8,8 @@ import { createFileRoute } from '@tanstack/react-router';
88import { Effect , Exit } from 'effect' ;
99import * as Schema from 'effect/Schema' ;
1010import type {
11- EventMessage ,
1211 Invitation ,
12+ RequestAcceptInvitationEvent ,
1313 RequestCreateInvitationEvent ,
1414 RequestCreateSpaceEvent ,
1515 RequestListInvitations ,
@@ -80,13 +80,40 @@ const App = ({
8080 const [ spaces , setSpaces ] = useState < SpaceStorageEntry [ ] > ( [ ] ) ;
8181 const [ invitations , setInvitations ] = useState < Invitation [ ] > ( [ ] ) ;
8282
83+ // Create a stable WebSocket connection that only depends on accountId
8384 useEffect ( ( ) => {
84- // temporary until we have a way to create accounts and authenticate them
8585 const websocketConnection = new WebSocket ( `ws://localhost:3030/?accountId=${ accountId } ` ) ;
8686 setWebsocketConnection ( websocketConnection ) ;
8787
88+ const onOpen = ( ) => {
89+ console . log ( 'websocket connected' ) ;
90+ } ;
91+
92+ const onError = ( event : Event ) => {
93+ console . log ( 'websocket error' , event ) ;
94+ } ;
95+
96+ const onClose = ( event : CloseEvent ) => {
97+ console . log ( 'websocket close' , event ) ;
98+ } ;
99+
100+ websocketConnection . addEventListener ( 'open' , onOpen ) ;
101+ websocketConnection . addEventListener ( 'error' , onError ) ;
102+ websocketConnection . addEventListener ( 'close' , onClose ) ;
103+
104+ return ( ) => {
105+ websocketConnection . removeEventListener ( 'open' , onOpen ) ;
106+ websocketConnection . removeEventListener ( 'error' , onError ) ;
107+ websocketConnection . removeEventListener ( 'close' , onClose ) ;
108+ websocketConnection . close ( ) ;
109+ } ;
110+ } , [ accountId ] ) ; // Only recreate when accountId changes
111+
112+ // Handle WebSocket messages in a separate effect
113+ useEffect ( ( ) => {
114+ if ( ! websocketConnection ) return ;
115+
88116 const onMessage = async ( event : MessageEvent ) => {
89- console . log ( 'message received' , event . data ) ;
90117 const data = JSON . parse ( event . data ) ;
91118 const message = decodeResponseMessage ( data ) ;
92119 if ( message . _tag === 'Right' ) {
@@ -157,8 +184,31 @@ const App = ({
157184 ) ;
158185 break ;
159186 }
160- case 'event' : {
161- console . log ( 'event' , response ) ;
187+ case 'space-event' : {
188+ const space = spaces . find ( ( s ) => s . id === response . spaceId ) ;
189+ if ( ! space ) {
190+ console . error ( 'Space not found' , response . spaceId ) ;
191+ return ;
192+ }
193+ if ( ! space . state ) {
194+ console . error ( 'Space has no state' , response . spaceId ) ;
195+ return ;
196+ }
197+
198+ const applyEventResult = await Effect . runPromiseExit (
199+ applyEvent ( { event : response . event , state : space . state } ) ,
200+ ) ;
201+ if ( Exit . isSuccess ( applyEventResult ) ) {
202+ setSpaces ( ( spaces ) =>
203+ spaces . map ( ( space ) => {
204+ if ( space . id === response . spaceId ) {
205+ return { ...space , state : applyEventResult . value , events : [ ...space . events , response . event ] } ;
206+ }
207+ return space ;
208+ } ) ,
209+ ) ;
210+ }
211+
162212 break ;
163213 }
164214 case 'list-invitations' : {
@@ -170,31 +220,13 @@ const App = ({
170220 }
171221 }
172222 } ;
173- websocketConnection . addEventListener ( 'message' , onMessage ) ;
174223
175- const onOpen = ( ) => {
176- console . log ( 'websocket connected' ) ;
177- } ;
178- websocketConnection . addEventListener ( 'open' , onOpen ) ;
179-
180- const onError = ( event : Event ) => {
181- console . log ( 'websocket error' , event ) ;
182- } ;
183- websocketConnection . addEventListener ( 'error' , onError ) ;
184-
185- const onClose = ( event : CloseEvent ) => {
186- console . log ( 'websocket close' , event ) ;
187- } ;
188- websocketConnection . addEventListener ( 'close' , onClose ) ;
224+ websocketConnection . addEventListener ( 'message' , onMessage ) ;
189225
190226 return ( ) => {
191227 websocketConnection . removeEventListener ( 'message' , onMessage ) ;
192- websocketConnection . removeEventListener ( 'open' , onOpen ) ;
193- websocketConnection . removeEventListener ( 'error' , onError ) ;
194- websocketConnection . removeEventListener ( 'close' , onClose ) ;
195- websocketConnection . close ( ) ;
196228 } ;
197- } , [ accountId , encryptionPrivateKey ] ) ;
229+ } , [ websocketConnection , encryptionPrivateKey , spaces ] ) ;
198230
199231 return (
200232 < >
@@ -268,7 +300,11 @@ const App = ({
268300 console . error ( 'Failed to accept invitation' , spaceEvent ) ;
269301 return ;
270302 }
271- const message : EventMessage = { type : 'event' , event : spaceEvent . value , spaceId : invitation . spaceId } ;
303+ const message : RequestAcceptInvitationEvent = {
304+ type : 'accept-invitation-event' ,
305+ event : spaceEvent . value ,
306+ spaceId : invitation . spaceId ,
307+ } ;
272308 websocketConnection ?. send ( JSON . stringify ( message ) ) ;
273309
274310 // temporary until we have define a strategy for accepting invitations response
0 commit comments