bookwiz.io / app / auth / github / complete / page.tsx
page.tsx
Raw
'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>
  )
}