@@ -48,10 +48,51 @@ function AppPage() {
4848 const { getViewReadOnlyStatus } = useViewOperations ( ) ;
4949
5050 const currentUser = useCurrentUser ( ) ;
51- const view = useMemo ( ( ) => {
51+ const service = useService ( ) ;
52+
53+ // View from outline (may be undefined if outline hasn't updated yet)
54+ const outlineView = useMemo ( ( ) => {
5255 if ( ! outline || ! viewId ) return ;
5356 return findView ( outline , viewId ) ;
5457 } , [ outline , viewId ] ) ;
58+
59+ // Fallback view fetched from server when not in outline
60+ const [ fallbackView , setFallbackView ] = React . useState < { view_id : string ; layout : ViewLayout } | null > ( null ) ;
61+
62+ // Fetch view metadata when not found in outline (handles race condition after creating new view)
63+ useEffect ( ( ) => {
64+ if ( outlineView || ! viewId || ! workspaceId || ! service ) {
65+ // Clear fallback when outline has the view
66+ if ( outlineView && fallbackView ?. view_id === viewId ) {
67+ setFallbackView ( null ) ;
68+ }
69+
70+ return ;
71+ }
72+
73+ // View not in outline - fetch from server directly
74+ let cancelled = false ;
75+
76+ service
77+ . getAppView ( workspaceId , viewId )
78+ . then ( ( fetchedView ) => {
79+ if ( ! cancelled && fetchedView ) {
80+ setFallbackView ( { view_id : fetchedView . view_id , layout : fetchedView . layout } ) ;
81+ }
82+ } )
83+ . catch ( ( e ) => {
84+ console . warn ( '[AppPage] Failed to fetch view metadata for' , viewId , e ) ;
85+ } ) ;
86+
87+ return ( ) => {
88+ cancelled = true ;
89+ } ;
90+ } , [ outlineView , viewId , workspaceId , service , fallbackView ?. view_id ] ) ;
91+
92+ // Use outline view if available, otherwise use fallback
93+ const view = outlineView ;
94+ const layout = outlineView ?. layout ?? fallbackView ?. layout ;
95+
5596 const rendered = useContext ( AppContext ) ?. rendered ;
5697
5798 const helmet = useMemo ( ( ) => {
@@ -61,8 +102,6 @@ function AppPage() {
61102 </ Suspense >
62103 ) : null ;
63104 } , [ rendered , view ] ) ;
64-
65- const layout = view ?. layout ;
66105 const [ doc , setDoc ] = React . useState < YDoc | undefined > ( undefined ) ;
67106 const [ error , setError ] = React . useState < AppError | null > ( null ) ;
68107 const loadPageDoc = useCallback (
@@ -141,7 +180,6 @@ function AppPage() {
141180 [ uploadFile , view ]
142181 ) ;
143182
144- const service = useService ( ) ;
145183 const requestInstance = service ?. getAxiosInstance ( ) ;
146184
147185 // Check if view is in shareWithMe and determine readonly status
@@ -151,7 +189,10 @@ function AppPage() {
151189 } , [ getViewReadOnlyStatus , viewId , outline ] ) ;
152190
153191 const viewDom = useMemo ( ( ) => {
154- if ( ! doc && layout === ViewLayout . AIChat && viewId ) {
192+ // Check if doc belongs to current viewId (handles race condition when doc from old view arrives after navigation)
193+ const docForCurrentView = doc && doc . id === viewId ? doc : undefined ;
194+
195+ if ( ! docForCurrentView && layout === ViewLayout . AIChat && viewId ) {
155196 return (
156197 < Suspense >
157198 < AIChat chatId = { viewId } onRendered = { onRendered } />
@@ -161,11 +202,11 @@ function AppPage() {
161202
162203 const View = layout === ViewLayout . Document ? Document : DatabaseView ;
163204
164- return doc && viewMeta && workspaceId && View ? (
205+ return docForCurrentView && viewMeta && workspaceId && View ? (
165206 < View
166207 requestInstance = { requestInstance }
167208 workspaceId = { workspaceId }
168- doc = { doc }
209+ doc = { docForCurrentView }
169210 readOnly = { isReadOnly }
170211 viewMeta = { viewMeta }
171212 navigateToView = { toView }
0 commit comments