fix(frontend): layers/blocks local-first merge + push effects (quality review fixes)
This commit is contained in:
+34
-26
@@ -334,42 +334,36 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
|||||||
setElements(merged);
|
setElements(merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never overwrite local layers with empty remote layers (prevents losing initialLayers)
|
// Merge layers: local-first, update changed from remote, append remote-only
|
||||||
if (collab.layers.length > 0) {
|
if (collab.layers.length > 0) {
|
||||||
// Compare by ID set, not by index ordering. Update if any layer properties differ.
|
|
||||||
const localLayerMap = new Map(layers.map(l => [l.id, l]));
|
const localLayerMap = new Map(layers.map(l => [l.id, l]));
|
||||||
let layersChanged = false;
|
const remoteLayerMap = new Map(collab.layers.map(l => [l.id, l]));
|
||||||
const mergedLayers = collab.layers.map(rl => {
|
const mergedLayers = layers.map(ll => {
|
||||||
const local = localLayerMap.get(rl.id);
|
const remote = remoteLayerMap.get(ll.id);
|
||||||
if (!local || JSON.stringify(local) !== JSON.stringify(rl)) {
|
return remote ? (JSON.stringify(remote) !== JSON.stringify(ll) ? remote : ll) : ll;
|
||||||
layersChanged = true;
|
|
||||||
}
|
|
||||||
return rl;
|
|
||||||
});
|
});
|
||||||
// Also check if local has layers not in remote
|
collab.layers.forEach(rl => {
|
||||||
if (!layersChanged && layers.length !== collab.layers.length) {
|
if (!localLayerMap.has(rl.id)) mergedLayers.push(rl);
|
||||||
layersChanged = true;
|
});
|
||||||
|
if (mergedLayers.length !== layers.length || mergedLayers.some((ml, i) => ml !== layers[i])) {
|
||||||
|
setLayers(mergedLayers);
|
||||||
}
|
}
|
||||||
if (layersChanged) setLayers(mergedLayers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Never overwrite local blocks with empty remote blocks (prevents losing defaultBlocks)
|
// Merge blocks: local-first, update changed from remote, append remote-only
|
||||||
if (collab.blocks.length > 0) {
|
if (collab.blocks.length > 0) {
|
||||||
// Compare by ID set, not by index ordering. Update if any block properties differ.
|
|
||||||
const localBlockMap = new Map(blocks.map(b => [b.id, b]));
|
const localBlockMap = new Map(blocks.map(b => [b.id, b]));
|
||||||
let blocksChanged = false;
|
const remoteBlockMap = new Map(collab.blocks.map(b => [b.id, b]));
|
||||||
const mergedBlocks = collab.blocks.map(rb => {
|
const mergedBlocks = blocks.map(lb => {
|
||||||
const local = localBlockMap.get(rb.id);
|
const remote = remoteBlockMap.get(lb.id);
|
||||||
if (!local || JSON.stringify(local) !== JSON.stringify(rb)) {
|
return remote ? (JSON.stringify(remote) !== JSON.stringify(lb) ? remote : lb) : lb;
|
||||||
blocksChanged = true;
|
|
||||||
}
|
|
||||||
return rb;
|
|
||||||
});
|
});
|
||||||
// Also check if local has blocks not in remote
|
collab.blocks.forEach(rb => {
|
||||||
if (!blocksChanged && blocks.length !== collab.blocks.length) {
|
if (!localBlockMap.has(rb.id)) mergedBlocks.push(rb);
|
||||||
blocksChanged = true;
|
});
|
||||||
|
if (mergedBlocks.length !== blocks.length || mergedBlocks.some((mb, i) => mb !== blocks[i])) {
|
||||||
|
setBlocks(mergedBlocks);
|
||||||
}
|
}
|
||||||
if (blocksChanged) setBlocks(mergedBlocks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync groups from remote → local
|
// Sync groups from remote → local
|
||||||
@@ -409,6 +403,20 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [bgConfig, collab.status]);
|
}, [bgConfig, collab.status]);
|
||||||
|
|
||||||
|
// Sync local → remote: push local layers to Yjs when layers change
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (collab.status !== 'connected') return;
|
||||||
|
for (const layer of layers) collab.setLayer(layer);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [layers, collab.status]);
|
||||||
|
|
||||||
|
// Sync local → remote: push local blocks to Yjs when blocks change
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (collab.status !== 'connected') return;
|
||||||
|
for (const block of blocks) collab.setBlock(block);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [blocks, collab.status]);
|
||||||
|
|
||||||
const handleElementCreated = useCallback((el: CADElement) => {
|
const handleElementCreated = useCallback((el: CADElement) => {
|
||||||
const elWithLayer = el.layerId ? el : { ...el, layerId: activeLayerId };
|
const elWithLayer = el.layerId ? el : { ...el, layerId: activeLayerId };
|
||||||
setElements((prev) => {
|
setElements((prev) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user