import { useState, useEffect } from 'react' import { useNavigate, useSearchParams } from 'react-router-dom' import { useAuth } from '../contexts/AuthContext' import { Shield, ChevronDown, AlertCircle, Check, X, Info, Database, User, Mail, Calendar, FileText, Settings, Lock } from 'lucide-react' interface Permission { id: string name: string description: string icon: React.ElementType required: boolean } const AuthorizePage = () => { const [searchParams] = useSearchParams() const navigate = useNavigate() const { user } = useAuth() const [isLoading, setIsLoading] = useState(false) const [appInfo, setAppInfo] = useState(null) const [selectedPermissions, setSelectedPermissions] = useState>(new Set()) const [showDetails, setShowDetails] = useState(false) // OAuth parameters const clientId = searchParams.get('client_id') const redirectUri = searchParams.get('redirect_uri') const responseType = searchParams.get('response_type') const scope = searchParams.get('scope') const state = searchParams.get('state') const permissions: Permission[] = [ { id: 'profile', name: '프로필 정보', description: '이름, 이메일, 프로필 사진 등 기본 정보', icon: User, required: true }, { id: 'email', name: '이메일 주소', description: '이메일 주소 확인 및 알림 전송', icon: Mail, required: true }, { id: 'offline_access', name: '오프라인 액세스', description: '사용자가 오프라인일 때도 액세스 유지', icon: Database, required: false }, { id: 'calendar', name: '캘린더 접근', description: '캘린더 일정 읽기 및 수정', icon: Calendar, required: false }, { id: 'files', name: '파일 접근', description: '파일 읽기, 쓰기 및 공유', icon: FileText, required: false }, { id: 'settings', name: '설정 관리', description: '애플리케이션 설정 읽기 및 수정', icon: Settings, required: false } ] useEffect(() => { if (!user) { // Redirect to login with return URL const returnUrl = encodeURIComponent(window.location.href) navigate(`/login?return_url=${returnUrl}`) return } if (!clientId) { // Invalid request navigate('/error?type=invalid_request') return } // Fetch application information fetchAppInfo(clientId) // Parse requested scopes and set initial permissions if (scope) { const requestedScopes = scope.split(' ') const initialPermissions = new Set() permissions.forEach(perm => { if (perm.required || requestedScopes.includes(perm.id)) { initialPermissions.add(perm.id) } }) setSelectedPermissions(initialPermissions) } }, [user, clientId, scope, navigate]) const fetchAppInfo = async (clientId: string) => { try { const response = await fetch(`/api/v1/applications/${clientId}`) if (response.ok) { const data = await response.json() setAppInfo(data) } } catch (error) { console.error('Failed to fetch app info:', error) // Use default app info for demo setAppInfo({ name: 'Project Default Service Account', developer: 'AiMond Developer', website: 'https://aimond.io', verified: true }) } } const handleAccept = async () => { setIsLoading(true) try { // Send authorization request to backend const response = await fetch('/api/v1/auth/authorize', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('access_token')}` }, body: JSON.stringify({ client_id: clientId, redirect_uri: redirectUri, response_type: responseType, scope: Array.from(selectedPermissions).join(' '), state: state }) }) if (response.ok) { const data = await response.json() // Redirect back to the application with authorization code const redirectUrl = new URL(redirectUri || '/') redirectUrl.searchParams.append('code', data.code) if (state) { redirectUrl.searchParams.append('state', state) } window.location.href = redirectUrl.toString() } } catch (error) { console.error('Authorization error:', error) } finally { setIsLoading(false) } } const handleCancel = () => { // Redirect back to the application with error const redirectUrl = new URL(redirectUri || '/') redirectUrl.searchParams.append('error', 'access_denied') if (state) { redirectUrl.searchParams.append('state', state) } window.location.href = redirectUrl.toString() } const togglePermission = (permId: string) => { const permission = permissions.find(p => p.id === permId) if (permission?.required) return // Can't uncheck required permissions const newPermissions = new Set(selectedPermissions) if (newPermissions.has(permId)) { newPermissions.delete(permId) } else { newPermissions.add(permId) } setSelectedPermissions(newPermissions) } if (!user || !appInfo) { return (
) } return (
{/* Header */}
AiMond
{user.email}
{/* Main Content */}
{/* App Info Card */}
{/* App Header */}

{appInfo.name}

이 앱에서 다음 권한을 요청합니다:

{/* Permissions List */}
{permissions.map(permission => { const Icon = permission.icon const isSelected = selectedPermissions.has(permission.id) const isRequired = permission.required return (
!isRequired && togglePermission(permission.id)} >
{isRequired ? (
) : ( togglePermission(permission.id)} className="w-5 h-5 text-blue-600 border-gray-300 rounded focus:ring-blue-500" onClick={(e) => e.stopPropagation()} /> )}

{permission.name}

{isRequired && ( 필수 )}

{permission.description}

) })}
{/* Info Box */}

앱 권한 정보

이 앱은 선택한 권한에만 접근할 수 있으며, 언제든지 계정 설정에서 권한을 취소할 수 있습니다.

{/* Action Buttons */}
{/* Additional Info */} {showDetails && (
개발자: {appInfo.developer}
웹사이트: {appInfo.website}
인증 상태: {appInfo.verified ? ( <> 인증됨 ) : ( <> 미인증 )}
)}
{/* Privacy Notice */}

계속 진행하면 AiMond의{' '} 서비스 약관 및{' '} 개인정보처리방침에 동의하는 것입니다.

{/* Footer */}
) } export default AuthorizePage