update for shape rendering in prod
This commit is contained in:
parent
bda2523e3b
commit
b5463d4d64
|
|
@ -1,6 +1,6 @@
|
||||||
import { useAutomergeSync } from "@/automerge/useAutomergeSync"
|
import { useAutomergeSync } from "@/automerge/useAutomergeSync"
|
||||||
import { AutomergeHandleProvider } from "@/context/AutomergeHandleContext"
|
import { AutomergeHandleProvider } from "@/context/AutomergeHandleContext"
|
||||||
import { useMemo, useEffect, useState } from "react"
|
import { useMemo, useEffect, useState, useRef } from "react"
|
||||||
import { Tldraw, Editor, TLShapeId } from "tldraw"
|
import { Tldraw, Editor, TLShapeId } from "tldraw"
|
||||||
import { useParams } from "react-router-dom"
|
import { useParams } from "react-router-dom"
|
||||||
import { ChatBoxTool } from "@/tools/ChatBoxTool"
|
import { ChatBoxTool } from "@/tools/ChatBoxTool"
|
||||||
|
|
@ -211,6 +211,9 @@ export function Board() {
|
||||||
}
|
}
|
||||||
const automergeHandle = (storeWithHandle as any).handle
|
const automergeHandle = (storeWithHandle as any).handle
|
||||||
const [editor, setEditor] = useState<Editor | null>(null)
|
const [editor, setEditor] = useState<Editor | null>(null)
|
||||||
|
|
||||||
|
// Ref for production polling interval
|
||||||
|
const statusCheckIntervalRef = useRef<NodeJS.Timeout | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const value = localStorage.getItem("makereal_settings_2")
|
const value = localStorage.getItem("makereal_settings_2")
|
||||||
|
|
@ -235,20 +238,40 @@ export function Board() {
|
||||||
const checkAndFixMissingShapes = () => {
|
const checkAndFixMissingShapes = () => {
|
||||||
if (!editor || !store.store) return
|
if (!editor || !store.store) return
|
||||||
|
|
||||||
// Only check if store is synced
|
// In production, be more lenient - check if store has shapes even if not fully synced
|
||||||
if (store.status !== 'synced-remote') {
|
// This handles timing issues where shapes are loaded but status hasn't updated yet
|
||||||
|
const storeShapes = store.store.allRecords().filter((r: any) => r.typeName === 'shape') || []
|
||||||
|
const hasShapes = storeShapes.length > 0
|
||||||
|
|
||||||
|
// Only check if store is synced OR if we have shapes (production workaround)
|
||||||
|
// In dev, we can be strict, but in production we need to be more lenient
|
||||||
|
const isProduction = import.meta.env.PROD || import.meta.env.MODE === 'production'
|
||||||
|
if (store.status !== 'synced-remote' && (!isProduction || !hasShapes)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const editorShapes = editor.getCurrentPageShapes()
|
const editorShapes = editor.getCurrentPageShapes()
|
||||||
const storeShapes = store.store.allRecords().filter((r: any) => r.typeName === 'shape') || []
|
|
||||||
const currentPageId = editor.getCurrentPageId()
|
const currentPageId = editor.getCurrentPageId()
|
||||||
|
|
||||||
// Get shapes on current page from store
|
// Get shapes on current page from store
|
||||||
const storeShapesOnCurrentPage = storeShapes.filter((s: any) => s.parentId === currentPageId)
|
const storeShapesOnCurrentPage = storeShapes.filter((s: any) => s.parentId === currentPageId)
|
||||||
|
|
||||||
|
// Debug: Log page information
|
||||||
|
const allPages = store.store.allRecords().filter((r: any) => r.typeName === 'page')
|
||||||
|
console.log(`📊 Board: Current page ID: ${currentPageId}`)
|
||||||
|
console.log(`📊 Board: Available pages:`, allPages.map((p: any) => ({ id: p.id, name: p.name })))
|
||||||
console.log(`📊 Board: Store has ${storeShapes.length} total shapes, ${storeShapesOnCurrentPage.length} on current page. Editor sees ${editorShapes.length} shapes on current page.`)
|
console.log(`📊 Board: Store has ${storeShapes.length} total shapes, ${storeShapesOnCurrentPage.length} on current page. Editor sees ${editorShapes.length} shapes on current page.`)
|
||||||
|
|
||||||
|
// Debug: Log shape parent IDs to see if there's a mismatch
|
||||||
|
if (storeShapes.length > 0 && editorShapes.length === 0) {
|
||||||
|
const parentIdCounts = new Map<string, number>()
|
||||||
|
storeShapes.forEach((s: any) => {
|
||||||
|
const pid = s.parentId || 'no-parent'
|
||||||
|
parentIdCounts.set(pid, (parentIdCounts.get(pid) || 0) + 1)
|
||||||
|
})
|
||||||
|
console.log(`📊 Board: Shape parent ID distribution:`, Array.from(parentIdCounts.entries()))
|
||||||
|
}
|
||||||
|
|
||||||
// Check if there are shapes in store on current page that editor can't see
|
// Check if there are shapes in store on current page that editor can't see
|
||||||
if (storeShapesOnCurrentPage.length > editorShapes.length) {
|
if (storeShapesOnCurrentPage.length > editorShapes.length) {
|
||||||
const editorShapeIds = new Set(editorShapes.map(s => s.id))
|
const editorShapeIds = new Set(editorShapes.map(s => s.id))
|
||||||
|
|
@ -279,6 +302,28 @@ export function Board() {
|
||||||
} else {
|
} else {
|
||||||
// Shapes don't exist in editor - might be a sync issue
|
// Shapes don't exist in editor - might be a sync issue
|
||||||
console.error(`📊 Board: ${missingShapes.length} shapes are in store but don't exist in editor - possible sync issue`)
|
console.error(`📊 Board: ${missingShapes.length} shapes are in store but don't exist in editor - possible sync issue`)
|
||||||
|
|
||||||
|
// Try to force a refresh by updating the store
|
||||||
|
// This might help if shapes are stuck in a validation error state
|
||||||
|
console.log(`📊 Board: Attempting to refresh store to make shapes visible`)
|
||||||
|
try {
|
||||||
|
// Force a store update by reading and re-putting the shapes
|
||||||
|
const shapesToRefresh = missingShapes.slice(0, 10) // Limit to first 10 to avoid performance issues
|
||||||
|
const refreshedShapes = shapesToRefresh.map((s: any) => {
|
||||||
|
const shapeFromStore = store.store.get(s.id)
|
||||||
|
if (shapeFromStore) {
|
||||||
|
return shapeFromStore
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}).filter((s): s is NonNullable<typeof s> => s !== null)
|
||||||
|
|
||||||
|
if (refreshedShapes.length > 0) {
|
||||||
|
console.log(`📊 Board: Refreshing ${refreshedShapes.length} shapes in store`)
|
||||||
|
store.store.put(refreshedShapes)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`📊 Board: Error refreshing shapes:`, error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if shapes are outside viewport
|
// Check if shapes are outside viewport
|
||||||
|
|
@ -315,7 +360,7 @@ export function Board() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also check for shapes on other pages
|
// Also check for shapes on other pages
|
||||||
const shapesOnOtherPages = storeShapes.filter((s: any) => s.parentId !== currentPageId)
|
const shapesOnOtherPages = storeShapes.filter((s: any) => s.parentId && s.parentId !== currentPageId)
|
||||||
if (shapesOnOtherPages.length > 0) {
|
if (shapesOnOtherPages.length > 0) {
|
||||||
console.log(`📊 Board: ${shapesOnOtherPages.length} shapes exist on other pages (not current page ${currentPageId})`)
|
console.log(`📊 Board: ${shapesOnOtherPages.length} shapes exist on other pages (not current page ${currentPageId})`)
|
||||||
|
|
||||||
|
|
@ -327,6 +372,23 @@ export function Board() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Also check for shapes with no parentId or invalid parentId
|
||||||
|
const shapesWithInvalidParent = storeShapes.filter((s: any) => !s.parentId || (s.parentId && !allPages.find((p: any) => p.id === s.parentId)))
|
||||||
|
if (shapesWithInvalidParent.length > 0) {
|
||||||
|
console.warn(`📊 Board: ${shapesWithInvalidParent.length} shapes have invalid or missing parentId. Fixing...`)
|
||||||
|
// Fix shapes with invalid parentId by assigning them to current page
|
||||||
|
const fixedShapes = shapesWithInvalidParent.map((s: any) => ({
|
||||||
|
...s,
|
||||||
|
parentId: currentPageId
|
||||||
|
}))
|
||||||
|
try {
|
||||||
|
store.store.put(fixedShapes)
|
||||||
|
console.log(`📊 Board: Fixed ${fixedShapes.length} shapes by assigning them to current page ${currentPageId}`)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`📊 Board: Error fixing shapes with invalid parentId:`, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find the page with the most shapes
|
// Find the page with the most shapes
|
||||||
let maxShapes = 0
|
let maxShapes = 0
|
||||||
let pageWithMostShapes: string | null = null
|
let pageWithMostShapes: string | null = null
|
||||||
|
|
@ -345,6 +407,7 @@ export function Board() {
|
||||||
// Focus camera on shapes after switching
|
// Focus camera on shapes after switching
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const newPageShapes = editor.getCurrentPageShapes()
|
const newPageShapes = editor.getCurrentPageShapes()
|
||||||
|
console.log(`📊 Board: After page switch, editor sees ${newPageShapes.length} shapes on page ${pageWithMostShapes}`)
|
||||||
if (newPageShapes.length > 0) {
|
if (newPageShapes.length > 0) {
|
||||||
const bounds = editor.getShapePageBounds(newPageShapes[0])
|
const bounds = editor.getShapePageBounds(newPageShapes[0])
|
||||||
if (bounds) {
|
if (bounds) {
|
||||||
|
|
@ -354,6 +417,27 @@ export function Board() {
|
||||||
z: editor.getCamera().z
|
z: editor.getCamera().z
|
||||||
}, { animation: { duration: 300 } })
|
}, { animation: { duration: 300 } })
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Still no shapes after switching - might be a validation issue
|
||||||
|
console.warn(`📊 Board: After switching to page ${pageWithMostShapes}, still no shapes visible. Checking store...`)
|
||||||
|
const shapesOnNewPage = storeShapes.filter((s: any) => s.parentId === pageWithMostShapes)
|
||||||
|
console.log(`📊 Board: Store has ${shapesOnNewPage.length} shapes on page ${pageWithMostShapes}`)
|
||||||
|
if (shapesOnNewPage.length > 0) {
|
||||||
|
// Try to manually add shapes that might have validation issues
|
||||||
|
console.log(`📊 Board: Attempting to force visibility by selecting all shapes on page`)
|
||||||
|
const shapeIds = shapesOnNewPage.map((s: any) => s.id).filter((id): id is TLShapeId => id !== undefined)
|
||||||
|
if (shapeIds.length > 0) {
|
||||||
|
// Try to get shapes from editor to see if they exist
|
||||||
|
const existingShapes = shapeIds
|
||||||
|
.map(id => editor.getShape(id))
|
||||||
|
.filter((s): s is NonNullable<typeof s> => s !== undefined)
|
||||||
|
console.log(`📊 Board: ${existingShapes.length} of ${shapeIds.length} shapes exist in editor`)
|
||||||
|
if (existingShapes.length > 0) {
|
||||||
|
editor.setSelectedShapes(existingShapes.map(s => s.id))
|
||||||
|
editor.zoomToFit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, 100)
|
}, 100)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -369,18 +453,45 @@ export function Board() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial check
|
// Initial check - with delay in production to handle timing issues
|
||||||
checkAndFixMissingShapes()
|
const isProduction = import.meta.env.PROD || import.meta.env.MODE === 'production'
|
||||||
|
const initialDelay = isProduction ? 1000 : 0
|
||||||
|
setTimeout(checkAndFixMissingShapes, initialDelay)
|
||||||
|
|
||||||
// Listen to store changes to continuously monitor for missing shapes
|
// Listen to store changes to continuously monitor for missing shapes
|
||||||
// Listen to ALL sources (user, remote, etc.) to catch shapes loaded from Automerge
|
// Listen to ALL sources (user, remote, etc.) to catch shapes loaded from Automerge
|
||||||
const unsubscribe = store.store.listen(() => {
|
const unsubscribe = store.store.listen(() => {
|
||||||
// Debounce the check to avoid excessive calls
|
// In production, use longer debounce to ensure shapes are fully loaded
|
||||||
setTimeout(checkAndFixMissingShapes, 500)
|
const debounceDelay = isProduction ? 1000 : 500
|
||||||
|
setTimeout(checkAndFixMissingShapes, debounceDelay)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Also listen to store status changes - critical for production
|
||||||
|
// In production, shapes might load after status changes
|
||||||
|
if (isProduction) {
|
||||||
|
// Poll every 2 seconds in production until shapes are visible
|
||||||
|
statusCheckIntervalRef.current = setInterval(() => {
|
||||||
|
const storeShapes = store.store?.allRecords().filter((r: any) => r.typeName === 'shape') || []
|
||||||
|
const editorShapes = editor?.getCurrentPageShapes() || []
|
||||||
|
if (storeShapes.length > 0 && editorShapes.length === 0) {
|
||||||
|
console.log(`📊 Production: Store has ${storeShapes.length} shapes but editor sees 0. Running fix...`)
|
||||||
|
checkAndFixMissingShapes()
|
||||||
|
} else if (editorShapes.length > 0) {
|
||||||
|
// Shapes are visible, stop polling
|
||||||
|
if (statusCheckIntervalRef.current) {
|
||||||
|
clearInterval(statusCheckIntervalRef.current)
|
||||||
|
statusCheckIntervalRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
|
if (statusCheckIntervalRef.current) {
|
||||||
|
clearInterval(statusCheckIntervalRef.current)
|
||||||
|
statusCheckIntervalRef.current = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [editor, store.store, store.status])
|
}, [editor, store.store, store.status])
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue