'use client'
import { useEffect, useState, Suspense } from 'react'
import { useRouter, useSearchParams } from 'next/navigation'
import { supabase } from '@/lib/supabase'
interface Repository {
id: number
name: string
full_name: string
private: boolean
updated_at: string
description?: string
}
interface OAuthData {
bookId: string
accessToken: string
githubUsername: string
redirectUrl: string
repositories: Repository[]
}
function GitHubCompleteContent() {
const router = useRouter()
const searchParams = useSearchParams()
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
const handleOAuthComplete = async () => {
try {
// Get the OAuth data from URL params
const dataParam = searchParams.get('data')
if (!dataParam) {
throw new Error('Missing OAuth data')
}
const oauthData: OAuthData = JSON.parse(Buffer.from(dataParam, 'base64').toString())
const { bookId, accessToken, githubUsername, redirectUrl, repositories } = oauthData
// Verify user is authenticated
const { data: { user }, error: authError } = await supabase.auth.getUser()
if (authError || !user) {
const loginUrl = new URL('/auth/login', window.location.origin)
loginUrl.searchParams.set('error', 'Please log in to your account first, then connect GitHub')
router.push(loginUrl.toString())
return
}
// Verify user owns the book
const { data: book, error: bookError } = await supabase
.from('books')
.select('id, user_id, title')
.eq('id', bookId)
.eq('user_id', user.id)
.single()
if (bookError || !book) {
const errorUrl = new URL('/dashboard', window.location.origin)
errorUrl.searchParams.set('error', 'Book not found or access denied')
router.push(errorUrl.toString())
return
}
// Redirect back to the book editor with OAuth data as parameters
const bookUrl = new URL(`/books/${bookId}`, window.location.origin)
bookUrl.searchParams.set('accessToken', accessToken)
bookUrl.searchParams.set('githubUsername', githubUsername)
bookUrl.searchParams.set('repositories', Buffer.from(JSON.stringify(repositories)).toString('base64'))
router.push(bookUrl.toString())
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to complete GitHub connection')
setLoading(false)
}
}
handleOAuthComplete()
}, [searchParams, router])
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50">
<div className="text-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto mb-4"></div>
<h2 className="text-xl font-semibold text-gray-900 mb-2">Completing GitHub Connection</h2>
<p className="text-gray-600">Please wait while we set up your GitHub integration...</p>
</div>
</div>
)
}
if (error) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50">
<div className="text-center bg-white p-8 rounded-lg shadow-md max-w-md">
<h2 className="text-xl font-semibold text-red-600 mb-2">Connection Failed</h2>
<p className="text-gray-600 mb-4">{error}</p>
<button
onClick={() => router.push('/dashboard')}
className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors"
>
Return to Dashboard
</button>
</div>
</div>
)
}
return null
}
export default function GitHubCompletePage() {
return (
<Suspense fallback={
<div className="min-h-screen flex items-center justify-center bg-gray-50">
<div className="text-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto mb-4"></div>
<h2 className="text-xl font-semibold text-gray-900 mb-2">Loading...</h2>
<p className="text-gray-600">Please wait...</p>
</div>
</div>
}>
<GitHubCompleteContent />
</Suspense>
)
}