'use client'
import { useEffect, useState } from 'react'
import { useRouter } from 'next/navigation'
import { supabase } from '@/lib/supabase'
import { SparklesIcon, CheckCircleIcon, ExclamationTriangleIcon } from '@heroicons/react/24/outline'
import { motion, AnimatePresence } from 'framer-motion'
import Image from 'next/image'
// Magical floating orbs component - matching login page
const MagicalOrbs = () => {
return (
<div className="absolute inset-0 overflow-hidden pointer-events-none">
{[...Array(12)].map((_, i) => (
<div
key={i}
className="absolute rounded-full animate-pulse"
style={{
left: `${Math.random() * 100}%`,
top: `${Math.random() * 100}%`,
width: `${4 + Math.random() * 8}px`,
height: `${4 + Math.random() * 8}px`,
background: `radial-gradient(circle, rgba(20, 184, 166, 0.6) 0%, rgba(6, 182, 212, 0.3) 50%, transparent 100%)`,
animationDelay: `${Math.random() * 4}s`,
animationDuration: `${3 + Math.random() * 2}s`,
}}
/>
))}
</div>
)
}
// Enhanced loading spinner
const LoadingSpinner = () => (
<div className="relative">
<div className="animate-spin rounded-full h-12 w-12 border-2 border-teal-200/20">
<div className="absolute inset-0 rounded-full border-2 border-transparent border-t-teal-400 animate-spin"></div>
</div>
<div className="absolute inset-0 rounded-full border-2 border-transparent border-r-cyan-400 animate-spin animation-delay-75"></div>
</div>
)
export default function CompleteSessionPage() {
const router = useRouter()
const [status, setStatus] = useState<'processing' | 'success' | 'error'>('processing')
const [error, setError] = useState<string>('')
const [progress, setProgress] = useState(0)
useEffect(() => {
// Simulate progress for better UX
const progressInterval = setInterval(() => {
setProgress(prev => {
if (prev >= 90) return prev
return prev + Math.random() * 15
})
}, 100)
const completeSession = async () => {
try {
// Get tokens from sessionStorage
const tokensString = sessionStorage.getItem('supabase_auth_tokens')
if (!tokensString) {
throw new Error('No authentication tokens found')
}
const tokens = JSON.parse(tokensString)
if (!tokens.access_token || !tokens.refresh_token) {
throw new Error('Invalid token data')
}
console.log('Setting up session with tokens...')
setProgress(70)
// Set the session in Supabase
const { data, error: sessionError } = await supabase.auth.setSession({
access_token: tokens.access_token,
refresh_token: tokens.refresh_token
})
if (sessionError) {
throw new Error(`Session setup failed: ${sessionError.message}`)
}
if (data.session) {
console.log('Session established successfully for:', data.user?.email)
// Clean up stored tokens
sessionStorage.removeItem('supabase_auth_tokens')
setProgress(100)
clearInterval(progressInterval)
setStatus('success')
// Redirect to dashboard after a brief delay
setTimeout(() => {
router.push('/dashboard')
}, 1500)
} else {
throw new Error('No session created despite valid tokens')
}
} catch (err) {
clearInterval(progressInterval)
console.error('Session completion failed:', err)
setError(err instanceof Error ? err.message : 'Unknown error')
setStatus('error')
// Clean up stored tokens on error
sessionStorage.removeItem('supabase_auth_tokens')
// Redirect to error page after delay
setTimeout(() => {
router.push(`/auth/auth-code-error?error=session_setup_failed&description=${encodeURIComponent(error)}`)
}, 3000)
}
}
// Add a small delay for better UX
setTimeout(() => {
completeSession()
}, 500)
return () => clearInterval(progressInterval)
}, [router, error])
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800 relative overflow-hidden">
<MagicalOrbs />
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-teal-500/5 via-transparent to-transparent" />
<div className="max-w-md w-full mx-4">
<AnimatePresence mode="wait">
<motion.div
key={status}
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
transition={{ duration: 0.5 }}
className="w-full bg-white/10 dark:bg-slate-800/30 backdrop-blur-xl rounded-2xl shadow-2xl border border-white/20 dark:border-teal-600/20 p-8 text-center"
style={{
boxShadow: '0 0 30px rgba(15, 118, 110, 0.15), 0 0 60px rgba(124, 58, 237, 0.1)'
}}
>
{status === 'processing' && (
<>
<motion.div
className="flex justify-center mb-6"
initial={{ scale: 0, rotate: -180 }}
animate={{ scale: 1, rotate: 0 }}
transition={{ delay: 0.2, duration: 0.5, type: "spring", stiffness: 260, damping: 20 }}
>
<LoadingSpinner />
</motion.div>
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3, duration: 0.5 }}
>
<div className="flex justify-center mb-4">
<Image
src="/images/logo-glyph-white.png"
alt="Bookwiz Glyph"
width={32}
height={32}
className="opacity-80"
style={{ filter: 'drop-shadow(0 0 8px rgba(124, 58, 237, 0.4))' }}
/>
</div>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white mb-2">
Completing Sign-In
</h1>
<p className="text-gray-600 dark:text-gray-300 mb-6">
Setting up your magical session...
</p>
{/* Progress bar */}
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2 mb-4 overflow-hidden">
<motion.div
className="h-2 bg-gradient-to-r from-teal-500 to-cyan-500 rounded-full"
initial={{ width: 0 }}
animate={{ width: `${progress}%` }}
transition={{ duration: 0.3 }}
/>
</div>
<p className="text-sm text-gray-500 dark:text-gray-400">
{progress < 30 ? 'Authenticating...' :
progress < 70 ? 'Validating tokens...' :
progress < 95 ? 'Creating session...' : 'Almost ready...'}
</p>
</motion.div>
</>
)}
{status === 'success' && (
<>
<motion.div
className="flex justify-center mb-6"
initial={{ scale: 0, rotate: -180 }}
animate={{ scale: 1, rotate: 0 }}
transition={{ delay: 0.2, duration: 0.5, type: "spring", stiffness: 260, damping: 20 }}
>
<CheckCircleIcon className="h-12 w-12 text-green-500" />
</motion.div>
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3, duration: 0.5 }}
>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white mb-2">
✨ Welcome to Bookwiz!
</h1>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Your account is ready. Redirecting to your spellbooks...
</p>
<div className="flex justify-center">
<div className="animate-pulse text-teal-500">
<SparklesIcon className="h-6 w-6" />
</div>
</div>
</motion.div>
</>
)}
{status === 'error' && (
<>
<motion.div
className="flex justify-center mb-6"
initial={{ scale: 0, rotate: -180 }}
animate={{ scale: 1, rotate: 0 }}
transition={{ delay: 0.2, duration: 0.5, type: "spring", stiffness: 260, damping: 20 }}
>
<ExclamationTriangleIcon className="h-12 w-12 text-red-500" />
</motion.div>
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3, duration: 0.5 }}
>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white mb-4">
🚫 Session Setup Failed
</h1>
<p className="text-gray-600 dark:text-gray-300 mb-4">
There was an issue completing your sign-in:
</p>
<div className="text-sm text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20 rounded-lg p-3 mb-4">
{error}
</div>
<p className="text-xs text-gray-500 dark:text-gray-400">
Redirecting to error page...
</p>
</motion.div>
</>
)}
</motion.div>
</AnimatePresence>
</div>
</div>
)
}