'use client'
import { useEffect, useState, Suspense } from 'react'
import { useRouter, useSearchParams } from 'next/navigation'
import { supabase } from '@/lib/supabase'
import { IoLogoGithub } from 'react-icons/io5'
function CreateRepoContent() {
const router = useRouter()
const searchParams = useSearchParams()
const [repoName, setRepoName] = useState('')
const [description, setDescription] = useState('')
const [isPrivate, setIsPrivate] = useState(true)
const [isCreating, setIsCreating] = useState(false)
const [error, setError] = useState<string | null>(null)
const bookId = searchParams.get('bookId')
const accessToken = searchParams.get('accessToken')
const githubUsername = searchParams.get('githubUsername')
const redirectUrl = searchParams.get('redirectUrl') || '/dashboard'
useEffect(() => {
if (!bookId || !accessToken) {
router.push('/dashboard?error=Missing authorization data')
}
}, [bookId, accessToken, router])
const handleCreateRepository = async (e: React.FormEvent) => {
e.preventDefault()
if (!repoName.trim() || !accessToken || !bookId) return
setIsCreating(true)
setError(null)
try {
// Create repository via GitHub API
const response = await fetch('https://api.github.com/user/repos', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Accept': 'application/vnd.github.v3+json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: repoName,
description: description || undefined,
private: isPrivate,
auto_init: true
}),
})
if (!response.ok) {
const errorData = await response.json()
throw new Error(errorData.message || 'Failed to create repository')
}
const newRepo = await response.json()
// Get current user
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
throw new Error('Please log in first')
}
// Create GitHub integration
const integration = {
provider: 'github',
repository_url: newRepo.html_url,
repository_name: newRepo.name,
repository_full_name: newRepo.full_name,
access_token: accessToken,
github_username: githubUsername,
repository_id: newRepo.id,
is_private: newRepo.private,
user_id: user.id
}
const integrationResponse = await fetch(`/api/books/${bookId}/github-integration`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ integration }),
})
if (!integrationResponse.ok) {
const errorData = await integrationResponse.json()
throw new Error(errorData.error || 'Failed to connect repository')
}
// Success! Redirect back to the book
const successUrl = new URL(redirectUrl, window.location.origin)
successUrl.searchParams.set('success', `Created and connected repository ${newRepo.full_name}`)
router.push(successUrl.toString())
} catch (error) {
setError(error instanceof Error ? error.message : 'Failed to create repository')
} finally {
setIsCreating(false)
}
}
if (!bookId || !accessToken) {
return (
<div className="min-h-screen flex items-center justify-center bg-slate-900">
<div className="text-center bg-slate-800 p-8 rounded-lg border border-slate-700">
<h1 className="text-2xl font-bold text-red-400 mb-2">Authorization Error</h1>
<p className="text-slate-400 mb-4">Missing required authorization data</p>
<button
onClick={() => router.push('/dashboard')}
className="bg-teal-600 text-white px-4 py-2 rounded-lg hover:bg-teal-700 transition-colors"
>
Return to Dashboard
</button>
</div>
</div>
)
}
return (
<div className="min-h-screen bg-slate-900 py-8">
<div className="max-w-2xl mx-auto px-4">
<div className="text-center mb-8">
<div className="flex items-center justify-center gap-3 mb-4">
<IoLogoGithub className="w-8 h-8 text-slate-200" />
<h1 className="text-2xl font-semibold text-slate-200">
Create New Repository
</h1>
</div>
<p className="text-slate-400">
Create a new GitHub repository for your book
</p>
{githubUsername && (
<div className="mt-2 inline-block bg-slate-800 border border-slate-700 px-3 py-1 rounded-full text-sm text-slate-300">
@{githubUsername}
</div>
)}
</div>
<div className="bg-slate-800/50 rounded-lg border border-slate-700 p-6">
<form onSubmit={handleCreateRepository} className="space-y-6">
<div>
<label htmlFor="repoName" className="block text-sm font-medium text-slate-300 mb-2">
Repository Name *
</label>
<input
type="text"
id="repoName"
value={repoName}
onChange={(e) => setRepoName(e.target.value)}
placeholder="my-awesome-book"
required
className="w-full px-4 py-2 bg-slate-800 border border-slate-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 text-slate-200 placeholder-slate-500"
/>
<p className="text-xs text-slate-500 mt-1">
Use lowercase letters, numbers, and hyphens only
</p>
</div>
<div>
<label htmlFor="description" className="block text-sm font-medium text-slate-300 mb-2">
Description (Optional)
</label>
<textarea
id="description"
value={description}
onChange={(e) => setDescription(e.target.value)}
placeholder="A brief description of your book..."
rows={3}
className="w-full px-4 py-2 bg-slate-800 border border-slate-700 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 text-slate-200 placeholder-slate-500 resize-none"
/>
</div>
<div>
<label className="block text-sm font-medium text-slate-300 mb-3">
Visibility
</label>
<div className="space-y-3">
<label className="flex items-center">
<input
type="radio"
value="private"
checked={isPrivate}
onChange={() => setIsPrivate(true)}
className="mr-3 accent-teal-500"
/>
<div>
<div className="font-medium text-slate-200">Private</div>
<div className="text-sm text-slate-400">Only you can see this repository</div>
</div>
</label>
<label className="flex items-center">
<input
type="radio"
value="public"
checked={!isPrivate}
onChange={() => setIsPrivate(false)}
className="mr-3 accent-teal-500"
/>
<div>
<div className="font-medium text-slate-200">Public</div>
<div className="text-sm text-slate-400">Anyone can see this repository</div>
</div>
</label>
</div>
</div>
{error && (
<div className="bg-red-500/10 border border-red-500/20 text-red-400 px-4 py-3 rounded-lg">
{error}
</div>
)}
<div className="flex gap-4 pt-4">
<button
type="submit"
disabled={!repoName.trim() || isCreating}
className="flex-1 bg-teal-600 text-white py-2 px-4 rounded-lg hover:bg-teal-700 disabled:bg-slate-700 disabled:text-slate-400 disabled:cursor-not-allowed transition-colors"
>
{isCreating ? 'Creating Repository...' : 'Create Repository'}
</button>
<button
type="button"
onClick={() => router.back()}
className="px-6 py-2 bg-slate-700 hover:bg-slate-600 text-slate-200 rounded-lg transition-colors"
>
Back
</button>
</div>
</form>
</div>
</div>
</div>
)
}
export default function CreateRepoPage() {
return (
<Suspense fallback={
<div className="min-h-screen flex items-center justify-center bg-slate-900">
<div className="text-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-teal-500 mx-auto mb-4"></div>
<h2 className="text-xl font-semibold text-slate-200 mb-2">Loading...</h2>
<p className="text-slate-400">Please wait...</p>
</div>
</div>
}>
<CreateRepoContent />
</Suspense>
)
}