@@ -25,7 +25,6 @@ type DeepLinkHandlerProps = {
2525 */
2626function DeepLinkHandler ( { onInitialUrl} : DeepLinkHandlerProps ) {
2727 const linkingChangeListener = useRef < NativeEventSubscription | null > ( null ) ;
28- const initialUrlProcessed = useRef ( false ) ;
2928
3029 const [ allReports ] = useOnyx ( ONYXKEYS . COLLECTION . REPORT ) ;
3130 const [ , sessionMetadata ] = useOnyx ( ONYXKEYS . SESSION ) ;
@@ -38,57 +37,24 @@ function DeepLinkHandler({onInitialUrl}: DeepLinkHandlerProps) {
3837 if ( isLoadingOnyxValue ( sessionMetadata ) ) {
3938 return ;
4039 }
40+ // If the app is opened from a deep link, get the reportID (if exists) from the deep link and navigate to the chat report
41+ Linking . getInitialURL ( ) . then ( ( url ) => {
42+ onInitialUrl ( url as Route ) ;
4143
42- // Guard against stale closures: when deps change and the effect re-runs, the previous
43- // getInitialURL() promise may still be in-flight. Without this guard, its .then() would
44- // fire with stale conciergeReportID/introSelected values, causing a duplicate
45- // openReportFromDeepLink() call.
46- let cancelled = false ;
47-
48- // If the app is opened from a deep link, get the reportID (if exists) from the deep link and navigate to the chat report.
49- // We race against a timeout to prevent permanently blocking NavigationRoot if getInitialURL() never resolves
50- // (e.g. in HybridApp when OldDot fails to send the URL via native bridge).
51- Promise . race ( [
52- Linking . getInitialURL ( ) ,
53- new Promise < null > ( ( resolve ) => {
54- setTimeout ( ( ) => resolve ( null ) , CONST . TIMING . GET_INITIAL_URL_TIMEOUT ) ;
55- } ) ,
56- ] )
57- . then ( ( url ) => {
58- if ( cancelled ) {
59- return ;
44+ if ( url ) {
45+ if ( conciergeReportID === undefined ) {
46+ Log . info ( '[Deep link] conciergeReportID is undefined when processing initial URL' , false , { url} ) ;
6047 }
61-
62- initialUrlProcessed . current = true ;
63- onInitialUrl ( url as Route ) ;
64-
65- if ( url ) {
66- if ( conciergeReportID === undefined ) {
67- Log . info ( '[Deep link] conciergeReportID is undefined when processing initial URL' , false , { url} ) ;
68- }
69- if ( introSelected === undefined ) {
70- Log . info ( '[Deep link] introSelected is undefined when processing initial URL' , false , { url} ) ;
71- }
72- // Use hasAuthToken() for the latest auth state at call time, since the isAuthenticated
73- // closure value may be stale on cold start (useOnyx reports 'loaded' before storage completes).
74- const isCurrentlyAuthenticated = hasAuthToken ( ) ;
75- openReportFromDeepLink ( url , allReports , isCurrentlyAuthenticated , conciergeReportID , introSelected , betas ) ;
76- } else {
77- Report . doneCheckingPublicRoom ( ) ;
48+ if ( introSelected === undefined ) {
49+ Log . info ( '[Deep link] introSelected is undefined when processing initial URL' , false , { url} ) ;
7850 }
79-
80- endSpan ( CONST . TELEMETRY . SPAN_BOOTSPLASH . DEEP_LINK ) ;
81- } )
82- . catch ( ( ) => {
83- if ( cancelled ) {
84- return ;
85- }
86-
87- initialUrlProcessed . current = true ;
88- onInitialUrl ( null ) ;
51+ openReportFromDeepLink ( url , allReports , isAuthenticated , conciergeReportID , introSelected , betas ) ;
52+ } else {
8953 Report . doneCheckingPublicRoom ( ) ;
90- endSpan ( CONST . TELEMETRY . SPAN_BOOTSPLASH . DEEP_LINK ) ;
91- } ) ;
54+ }
55+
56+ endSpan ( CONST . TELEMETRY . SPAN_BOOTSPLASH . DEEP_LINK ) ;
57+ } ) ;
9258
9359 // Open chat report from a deep link (only mobile native)
9460 linkingChangeListener . current = Linking . addEventListener ( 'url' , ( state ) => {
@@ -103,25 +69,11 @@ function DeepLinkHandler({onInitialUrl}: DeepLinkHandlerProps) {
10369 } ) ;
10470
10571 return ( ) => {
106- cancelled = true ;
10772 linkingChangeListener . current ?. remove ( ) ;
10873 } ;
10974 // eslint-disable-next-line react-hooks/exhaustive-deps -- we only want this effect to re-run when conciergeReportID changes
11075 } , [ sessionMetadata ?. status , conciergeReportID , introSelected , betas ] ) ;
11176
112- // Safety net: if getInitialURL() resolves before the session loads, hasAuthToken() may return false
113- // for an authenticated user, causing openReportFromDeepLink to take the wrong path. Once isAuthenticated
114- // settles to true, unblock the UI. The initialUrlProcessed guard ensures this doesn't fire before URL
115- // resolution. In the common case (isAuthenticated settles first), this is a no-op because
116- // openReportFromDeepLink's own doneCheckingPublicRoom() call handles it.
117- useEffect ( ( ) => {
118- if ( ! isAuthenticated || ! initialUrlProcessed . current ) {
119- return ;
120- }
121-
122- Report . doneCheckingPublicRoom ( ) ;
123- } , [ isAuthenticated ] ) ;
124-
12577 return null ;
12678}
12779
0 commit comments