@@ -32,7 +32,9 @@ export default function OnboardingTokenPage() {
3232 const [ error , setError ] = useState < string | null > ( null )
3333 const [ issued , setIssued ] = useState < WorkspaceIssue | null > ( null )
3434 const [ pairStatus , setPairStatus ] = useState < string | null > ( null )
35+ const [ extensionStatus , setExtensionStatus ] = useState < string | null > ( null )
3536 const pairTimeoutRef = useRef < number | null > ( null )
37+ const pingTimeoutRef = useRef < number | null > ( null )
3638
3739 const token = issued ?. workspace_token ?? ''
3840 const expiresAt = issued ?. expires_at ?? ''
@@ -119,8 +121,28 @@ export default function OnboardingTokenPage() {
119121 window . postMessage ( { type : 'EASYRELOCATE_PAIR_REQUEST' , token : t } , window . location . origin )
120122 }
121123
122- const onPairAndContinue = ( ) => {
124+ const waitForPairResult = ( ) : Promise < boolean > =>
125+ new Promise ( ( resolve ) => {
126+ const timeout = window . setTimeout ( ( ) => {
127+ window . removeEventListener ( 'message' , onResult )
128+ resolve ( false )
129+ } , 3500 )
130+ const onResult = ( event : MessageEvent ) => {
131+ if ( event . source !== window ) return
132+ if ( event . origin !== window . location . origin ) return
133+ const data = event . data as { type ?: string ; ok ?: boolean } | null
134+ if ( ! data || data . type !== 'EASYRELOCATE_PAIR_RESULT' ) return
135+ window . clearTimeout ( timeout )
136+ window . removeEventListener ( 'message' , onResult )
137+ resolve ( ! ! data . ok )
138+ }
139+ window . addEventListener ( 'message' , onResult )
140+ } )
141+
142+ const onPairAndContinue = async ( ) => {
123143 onPairExtension ( )
144+ const ok = await waitForPairResult ( )
145+ if ( ! ok ) return
124146 navigate ( '/compare' )
125147 }
126148
@@ -129,6 +151,14 @@ export default function OnboardingTokenPage() {
129151 if ( event . source !== window ) return
130152 if ( event . origin !== window . location . origin ) return
131153 const data = event . data as { type ?: string ; ok ?: boolean ; error ?: string } | null
154+ if ( data ?. type === 'EASYRELOCATE_PING_RESULT' ) {
155+ if ( pingTimeoutRef . current ) {
156+ window . clearTimeout ( pingTimeoutRef . current )
157+ pingTimeoutRef . current = null
158+ }
159+ setExtensionStatus ( 'Extension detected.' )
160+ return
161+ }
132162 if ( ! data || data . type !== 'EASYRELOCATE_PAIR_RESULT' ) return
133163 if ( pairTimeoutRef . current ) {
134164 window . clearTimeout ( pairTimeoutRef . current )
@@ -141,12 +171,20 @@ export default function OnboardingTokenPage() {
141171 }
142172 }
143173 window . addEventListener ( 'message' , handler )
174+ pingTimeoutRef . current = window . setTimeout ( ( ) => {
175+ setExtensionStatus ( 'Extension not detected. Install or reload it, then refresh this page.' )
176+ } , 1200 )
177+ window . postMessage ( { type : 'EASYRELOCATE_PING_REQUEST' } , window . location . origin )
144178 return ( ) => {
145179 window . removeEventListener ( 'message' , handler )
146180 if ( pairTimeoutRef . current ) {
147181 window . clearTimeout ( pairTimeoutRef . current )
148182 pairTimeoutRef . current = null
149183 }
184+ if ( pingTimeoutRef . current ) {
185+ window . clearTimeout ( pingTimeoutRef . current )
186+ pingTimeoutRef . current = null
187+ }
150188 }
151189 } , [ ] )
152190
@@ -231,12 +269,12 @@ export default function OnboardingTokenPage() {
231269 < button className = "button secondary" onClick = { ( ) => void onCopy ( ) } >
232270 Copy
233271 </ button >
234- < button className = "button" onClick = { onPairAndContinue } >
235- Pair & Continue
236- </ button >
237272 < button className = "button secondary" onClick = { onContinue } >
238273 Continue to map
239274 </ button >
275+ < button className = "button" onClick = { onPairAndContinue } >
276+ Pair & Continue
277+ </ button >
240278 </ div >
241279 </ >
242280 ) : null }
@@ -246,18 +284,23 @@ export default function OnboardingTokenPage() {
246284 < button className = "button secondary" onClick = { ( ) => void doIssue ( ) } >
247285 Generate token
248286 </ button >
249- < button className = "button" onClick = { onPairAndContinue } >
250- Pair & Continue
251- </ button >
252287 < button className = "button secondary" onClick = { onContinue } >
253288 Continue to map
254289 </ button >
290+ < button className = "button" onClick = { onPairAndContinue } >
291+ Pair & Continue
292+ </ button >
255293 </ div >
256294 ) : null }
257295
258296 { pairStatus ? (
259297 < div style = { { marginTop : 12 , color : '#475569' , fontSize : 13 } } > { pairStatus } </ div >
260298 ) : null }
299+ { extensionStatus ? (
300+ < div style = { { marginTop : 6 , color : '#475569' , fontSize : 13 } } >
301+ { extensionStatus }
302+ </ div >
303+ ) : null }
261304 </ div >
262305 </ section >
263306 </ main >
0 commit comments