incname commited on
Commit
dc30d5f
·
1 Parent(s): e01d526
client/src/components/BlockEditor/BlockEditor.tsx CHANGED
@@ -795,9 +795,9 @@ export default function BlockEditor() {
795
  const block = ws.getBlockById(e.blockId);
796
  if (block && !block.getParent()) {
797
  try {
798
- const dom = Blockly.Xml.blockToDomWithXY(block);
799
  const xml = Blockly.Xml.domToText(dom);
800
- emitBlockCreateEvent(e.blockId, activeFileId, xml);
801
  } catch {}
802
  }
803
  }
 
795
  const block = ws.getBlockById(e.blockId);
796
  if (block && !block.getParent()) {
797
  try {
798
+ const dom = Blockly.Xml.blockToDom(block, { xy: true } as any);
799
  const xml = Blockly.Xml.domToText(dom);
800
+ emitBlockCreateEvent(e.blockId, xml);
801
  } catch {}
802
  }
803
  }
client/src/hooks/useWebSocket.ts CHANGED
@@ -112,25 +112,12 @@ export function useWebSocket() {
112
  useCollaborationStore.getState().updateElementHover(userId, elementId);
113
  });
114
 
115
- s.on('block_state_synced', (data: { fileId: string; xml: string; updatedBy: string; initialBlocksXml?: Record<string, { xml: string; updatedBy: string; updatedAt: number }> }) => {
116
- // Handle initial block state for new joiners (sent on join_project).
117
- // server sends initialBlocksXml as { fileId: { xml, updatedBy, updatedAt } }
118
- if (data.initialBlocksXml) {
119
- const store = useEditorStore.getState();
120
- for (const [fid, entry] of Object.entries(data.initialBlocksXml)) {
121
- if (entry.xml) store.setBlocksXml(fid, entry.xml);
122
- }
123
- if (store.activeFileId && data.initialBlocksXml[store.activeFileId]?.xml) {
124
- store.setVisualElements(store.elementRegistry[store.activeFileId] || []);
125
- }
126
- return;
127
- }
128
- // Real-time sync update
129
- if (data.updatedBy === useAuthStore.getState().user?.id) return;
130
- useEditorStore.getState().setBlocksXml(data.fileId, data.xml);
131
  const store = useEditorStore.getState();
132
- if (store.activeFileId === data.fileId) {
133
- store.setVisualElements(store.elementRegistry[data.fileId] || []);
134
  }
135
  });
136
 
@@ -161,14 +148,8 @@ export function useWebSocket() {
161
  useCollaborationStore.getState().pushPendingBlockChange({ blockId, name, value });
162
  });
163
 
164
- s.on('collaborator_block_create_event', ({ blockId, fileId, xml }: { blockId: string; fileId: string; xml: string }) => {
165
- const store = useEditorStore.getState();
166
- // Only apply to the currently active file; otherwise the block would appear
167
- // on the wrong file's workspace. The full XML sync (block_state_synced) will
168
- // handle it when the collaborator switches to that file.
169
- if (store.activeFileId === fileId) {
170
- useCollaborationStore.getState().pushPendingBlockCreate({ blockId, xml });
171
- }
172
  });
173
 
174
  s.on('file_updated', ({ fileId, content }: { fileId: string; content: string }) => {
@@ -448,10 +429,10 @@ export function useProjectSocket(projectId: string | undefined) {
448
  }
449
  }, [projectId]);
450
 
451
- const emitBlockCreateEvent = useCallback((blockId: string, fileId: string, xml: string) => {
452
  const s = globalSocket;
453
  if (s?.connected && projectId) {
454
- s.emit('block_create_event', { projectId, fileId, blockId, xml });
455
  }
456
  }, [projectId]);
457
 
 
112
  useCollaborationStore.getState().updateElementHover(userId, elementId);
113
  });
114
 
115
+ s.on('block_state_synced', ({ fileId, xml, updatedBy }: { fileId: string; xml: string; updatedBy: string }) => {
116
+ if (updatedBy === useAuthStore.getState().user?.id) return;
117
+ useEditorStore.getState().setBlocksXml(fileId, xml);
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  const store = useEditorStore.getState();
119
+ if (store.activeFileId === fileId) {
120
+ store.setVisualElements(store.elementRegistry[fileId] || []);
121
  }
122
  });
123
 
 
148
  useCollaborationStore.getState().pushPendingBlockChange({ blockId, name, value });
149
  });
150
 
151
+ s.on('collaborator_block_create_event', ({ blockId, xml }: { blockId: string; xml: string }) => {
152
+ useCollaborationStore.getState().pushPendingBlockCreate({ blockId, xml });
 
 
 
 
 
 
153
  });
154
 
155
  s.on('file_updated', ({ fileId, content }: { fileId: string; content: string }) => {
 
429
  }
430
  }, [projectId]);
431
 
432
+ const emitBlockCreateEvent = useCallback((blockId: string, xml: string) => {
433
  const s = globalSocket;
434
  if (s?.connected && projectId) {
435
+ s.emit('block_create_event', { projectId, blockId, xml });
436
  }
437
  }, [projectId]);
438
 
server/src/services/realtime.ts CHANGED
@@ -506,12 +506,11 @@ export function initRealtime(httpServer: HttpServer): Server {
506
  });
507
  });
508
 
509
- socket.on('block_create_event', (data: { projectId: string; fileId: string; blockId: string; xml: string }) => {
510
  const session = sessions.get(socket.id);
511
  if (!session) return;
512
  socket.to(`project:${data.projectId}`).emit('collaborator_block_create_event', {
513
  userId: session.userId,
514
- fileId: data.fileId,
515
  blockId: data.blockId,
516
  xml: data.xml,
517
  });
 
506
  });
507
  });
508
 
509
+ socket.on('block_create_event', (data: { projectId: string; blockId: string; xml: string }) => {
510
  const session = sessions.get(socket.id);
511
  if (!session) return;
512
  socket.to(`project:${data.projectId}`).emit('collaborator_block_create_event', {
513
  userId: session.userId,
 
514
  blockId: data.blockId,
515
  xml: data.xml,
516
  });