@@ -41,6 +41,14 @@ export const AccountButton = ({ logo, children, connected = false, connectedLabe
4141 }
4242 } ;
4343
44+ useEffect ( ( ) => {
45+ return ( ) => {
46+ clearTimer ( ) ;
47+ if ( popupRef . current && ! popupRef . current . closed ) {
48+ popupRef . current . close ( ) ;
49+ }
50+ } ;
51+ } , [ ] ) ;
4452 const fetchAndApply = async ( opts : { showToast : boolean } ) : Promise < boolean > => {
4553 if ( ! responseId || ! questionId ) return false ;
4654 try {
@@ -108,10 +116,49 @@ export const AccountButton = ({ logo, children, connected = false, connectedLabe
108116 setIsConnecting ( true ) ;
109117 clearTimer ( ) ;
110118
119+ const handleMessage = async ( event : MessageEvent ) => {
120+ // Only handle messages from this popup and same origin
121+ if ( event . source !== popup ) return ;
122+ if ( event . origin !== window . location . origin ) return ;
123+
124+ const data : any = event . data ;
125+ if ( ! data || data . type !== "FORM_OAUTH_CONNECTED" ) return ;
126+ if ( data . questionId !== questionId || data . responseId !== responseId ) return ;
127+
128+ // Mark this popup as handled so the interval callback does not re-fetch
129+ ( popup as any ) . __oauthHandled = true ;
130+
131+ clearTimer ( ) ;
132+ window . removeEventListener ( "message" , handleMessage ) ;
133+
134+ try {
135+ if ( data . error ) {
136+ const errorMessage = typeof data . error === "string" ? data . error : "綁定失敗,請再試一次" ;
137+ pushToast ( { title : "綁定失敗" , description : errorMessage , variant : "error" } ) ;
138+ onConnectErrorRef . current ?.( errorMessage ) ;
139+ } else {
140+ await fetchAndApply ( { showToast : true } ) ;
141+ }
142+ } finally {
143+ setIsConnecting ( false ) ;
144+ try {
145+ popup . close ( ) ;
146+ } catch {
147+ // ignore
148+ }
149+ }
150+ } ;
151+
152+ window . addEventListener ( "message" , handleMessage ) ;
153+
111154 timerRef . current = window . setInterval ( async ( ) => {
112155 if ( popup . closed ) {
113156 clearTimer ( ) ;
114- await fetchAndApply ( { showToast : true } ) ;
157+ window . removeEventListener ( "message" , handleMessage ) ;
158+ // If no FORM_OAUTH_CONNECTED message was handled, fall back to fetching
159+ if ( ! ( popup as any ) . __oauthHandled ) {
160+ await fetchAndApply ( { showToast : true } ) ;
161+ }
115162 setIsConnecting ( false ) ;
116163 }
117164 } , 500 ) ;
0 commit comments