From 01c4c543fcef93ed907a8bf83e5a205d3fb27f33 Mon Sep 17 00:00:00 2001 From: syui Date: Thu, 19 Jun 2025 15:02:54 +0900 Subject: [PATCH] fix --- my-blog/static/js/ask-ai.js | 62 +++++---------- oauth/src/App.css | 106 ++++++++++++++++++++++++- oauth/src/App.jsx | 56 ++++++++++++- oauth/src/components/OAuthCallback.jsx | 80 ++++++++----------- oauth/src/hooks/useAuth.js | 31 ++++++++ oauth/src/services/oauth.js | 37 +++++++-- 6 files changed, 267 insertions(+), 105 deletions(-) diff --git a/my-blog/static/js/ask-ai.js b/my-blog/static/js/ask-ai.js index ab84092..824a3b4 100644 --- a/my-blog/static/js/ask-ai.js +++ b/my-blog/static/js/ask-ai.js @@ -253,6 +253,24 @@ function setupAskAIEventListeners() { handleAIResponse(event.detail); }); + // Listen for OAuth callback completion from iframe + window.addEventListener('message', function(event) { + if (event.data.type === 'oauth_success') { + console.log('Received OAuth success message:', event.data); + + // Close any OAuth popups/iframes + const oauthFrame = document.getElementById('oauth-frame'); + if (oauthFrame) { + oauthFrame.remove(); + } + + // Reload the page to refresh OAuth app state + setTimeout(() => { + window.location.reload(); + }, 500); + } + }); + // Track IME composition state let isComposing = false; const aiQuestionInput = document.getElementById('aiQuestion'); @@ -284,52 +302,8 @@ function setupAskAIEventListeners() { }); } -// OAuth Callback handling -function handleOAuthCallback() { - // Check if we're on the callback page - if (window.location.pathname === '/oauth/callback') { - const urlParams = new URLSearchParams(window.location.search); - const code = urlParams.get('code'); - const error = urlParams.get('error'); - - if (error) { - console.error('OAuth error:', error); - // Redirect to home page with error - setTimeout(() => { - window.location.href = '/?oauth_error=' + encodeURIComponent(error); - }, 1000); - return; - } - - if (code) { - console.log('OAuth callback successful, code received'); - - // Get the original page from localStorage or use home page - const originalPage = localStorage.getItem('oauth_original_page') || '/'; - localStorage.removeItem('oauth_original_page'); - - // Wait a bit for OAuth app to process the callback - setTimeout(() => { - console.log('Redirecting back to:', originalPage); - window.location.href = originalPage; - }, 2000); - - return; - } - } - - // Store current page before OAuth if we're not on callback page - if (window.location.pathname !== '/oauth/callback') { - localStorage.setItem('oauth_original_page', window.location.href); - } -} - // Initialize Ask AI when DOM is loaded document.addEventListener('DOMContentLoaded', function() { - // Handle OAuth callback first - handleOAuthCallback(); - - // Then initialize Ask AI setupAskAIEventListeners(); console.log('Ask AI initialized successfully'); }); diff --git a/oauth/src/App.css b/oauth/src/App.css index cbe6bfe..63f6085 100644 --- a/oauth/src/App.css +++ b/oauth/src/App.css @@ -44,7 +44,7 @@ body { .oauth-header-content { display: flex; - justify-content: flex-start; + justify-content: space-between; align-items: center; max-width: 800px; margin: 0 auto; @@ -62,7 +62,74 @@ body { display: flex; gap: 8px; align-items: center; - width: 100%; +} + +/* OAuth User Profile in Header */ +.oauth-user-profile { + display: flex; + align-items: center; + gap: 12px; + flex: 1; +} + +.profile-avatar-section { + flex-shrink: 0; +} + +.profile-avatar-section .profile-avatar { + width: 48px; + height: 48px; + border-radius: 50%; + object-fit: cover; + border: 2px solid var(--border); +} + +.profile-avatar-fallback { + width: 48px; + height: 48px; + border-radius: 50%; + background: var(--background-secondary); + border: 2px solid var(--border); + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + font-weight: 700; + color: var(--text-secondary); +} + +.profile-info { + flex: 1; + min-width: 0; +} + +.profile-display-name { + font-size: 18px; + font-weight: 700; + color: var(--text); + margin-bottom: 2px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.profile-handle { + font-size: 14px; + color: var(--text-secondary); + margin-bottom: 2px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.profile-did { + font-size: 11px; + color: var(--text-secondary); + font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + opacity: 0.7; } /* Buttons */ @@ -647,6 +714,41 @@ body { .chat-container { height: 300px; } + + /* OAuth User Profile Mobile */ + .oauth-user-profile { + gap: 8px; + } + + .profile-avatar-section .profile-avatar, + .profile-avatar-fallback { + width: 36px; + height: 36px; + font-size: 14px; + } + + .profile-display-name { + font-size: 14px; + } + + .profile-handle { + font-size: 12px; + } + + .profile-did { + font-size: 9px; + } + + .oauth-header-content { + flex-direction: column; + gap: 12px; + align-items: flex-start; + } + + .oauth-header-actions { + width: 100%; + justify-content: center; + } } /* Avatar Styles */ diff --git a/oauth/src/App.jsx b/oauth/src/App.jsx index 9ab8d20..11fac13 100644 --- a/oauth/src/App.jsx +++ b/oauth/src/App.jsx @@ -69,8 +69,32 @@ export default function App() { if (isLoading) { return ( -
-

読み込み中...

+
+
+

読み込み中...

+ +
) } @@ -115,6 +139,34 @@ export default function App() {
+ {user && ( +
+
+ {user.avatar ? ( + {user.displayName + ) : ( +
+ {(user.displayName || user.handle || '?').charAt(0).toUpperCase()} +
+ )} +
+
+
+ {user.displayName || user.handle} +
+
+ @{user.handle} +
+
+ {user.did} +
+
+
+ )}
{ - handleCallback() - }, []) - - const handleCallback = async () => { - try { - // BrowserOAuthClientが自動的にコールバックを処理します - // URLのパラメータを確認して成功を通知 - const urlParams = new URLSearchParams(window.location.search) - const code = urlParams.get('code') - const error = urlParams.get('error') - - if (error) { - throw new Error(`OAuth error: ${error}`) - } - - if (code) { - setStatus('認証成功!元のページに戻ります...') - - // Get the referring page or use root - const referrer = document.referrer || window.location.origin - const returnUrl = referrer.includes('/oauth/callback') ? window.location.origin : referrer - - // 少し待ってから元のページにリダイレクト - setTimeout(() => { - window.location.href = returnUrl - }, 1500) - } else { - setStatus('認証情報が見つかりません') - } - - } catch (error) { - console.error('Callback error:', error) - setStatus('認証エラー: ' + error.message) - } - } +import React from 'react' +export default function OAuthCallback() { return ( -
-

OAuth認証

-

{status}

- {status.includes('エラー') && ( - - )} +
+
+

OAuth認証処理中...

+

+ 認証が完了しましたら自動で元のページに戻ります +

+ +
) } \ No newline at end of file diff --git a/oauth/src/hooks/useAuth.js b/oauth/src/hooks/useAuth.js index 63a5b3c..2d3eca5 100644 --- a/oauth/src/hooks/useAuth.js +++ b/oauth/src/hooks/useAuth.js @@ -18,6 +18,32 @@ export function useAuth() { if (authResult) { setUser(authResult.user) setAgent(authResult.agent) + + // If we're on callback page and authentication succeeded, notify parent + if (window.location.pathname === '/oauth/callback') { + console.log('OAuth callback completed, notifying parent window') + + // Get referrer or use stored return URL + const returnUrl = sessionStorage.getItem('oauth_return_url') || + document.referrer || + window.location.origin + + sessionStorage.removeItem('oauth_return_url') + + // Notify parent window if in iframe, otherwise redirect directly + if (window.parent !== window) { + window.parent.postMessage({ + type: 'oauth_success', + returnUrl: returnUrl, + user: authResult.user + }, '*') + } else { + // Direct redirect + setTimeout(() => { + window.location.href = returnUrl + }, 1000) + } + } } } catch (error) { console.error('Auth initialization failed:', error) @@ -27,6 +53,11 @@ export function useAuth() { } const login = async (handle) => { + // Store current page URL for post-auth redirect + if (window.location.pathname !== '/oauth/callback') { + sessionStorage.setItem('oauth_return_url', window.location.href) + } + await oauthService.login(handle) } diff --git a/oauth/src/services/oauth.js b/oauth/src/services/oauth.js index 2cff4ac..239fe7d 100644 --- a/oauth/src/services/oauth.js +++ b/oauth/src/services/oauth.js @@ -65,6 +65,8 @@ export class OAuthService { async processSession(session) { const did = session.sub || session.did let handle = session.handle || 'unknown' + let displayName = null + let avatar = null // Create Agent directly with session (per official docs) try { @@ -77,21 +79,40 @@ export class OAuthService { }) } - this.sessionInfo = { did, handle } - - // Resolve handle if missing - if (handle === 'unknown' && this.agent) { + // Get profile information using authenticated agent + if (this.agent) { try { await new Promise(resolve => setTimeout(resolve, 300)) const profile = await this.agent.getProfile({ actor: did }) - handle = profile.data.handle - this.sessionInfo.handle = handle + handle = profile.data.handle || handle + displayName = profile.data.displayName || null + avatar = profile.data.avatar || null + + console.log('Profile fetched from session:', { + did, + handle, + displayName, + avatar: avatar ? 'present' : 'none' + }) } catch (error) { - console.log('Failed to resolve handle:', error) + console.log('Failed to get profile from session:', error) + // Keep the basic info we have } } - return { did, handle } + this.sessionInfo = { + did, + handle, + displayName, + avatar + } + + return { + did, + handle, + displayName, + avatar + } } async login(handle) {