update error

This commit is contained in:
5t4l1n
2025-07-29 00:13:52 +05:30
parent 8816091e63
commit f72bcc69aa
7 changed files with 670 additions and 341 deletions
+353 -100
View File
@@ -1,121 +1,374 @@
"use client"
import { useAuth } from "@/context/auth-context"
import { useEffect, useState } from "react"
import { useRouter } from "next/navigation"
import { useAuth } from "@/context/auth-context"
import { DashboardStatsOverview } from "@/components/dashboard-stats"
import { Loader2, AlertCircle } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
User,
LogOut,
Settings,
Trophy,
BookOpen,
Target,
TrendingUp,
Wallet,
Mail,
Calendar,
Award,
BarChart3,
Activity,
Edit3,
Save,
X
} from "lucide-react"
export default function DashboardPage() {
const { isLoadingAuth, walletConnected, walletAddress, firebaseUser, authMethod } = useAuth()
const { user, firebaseUser, walletConnected, logout, authMethod } = useAuth()
const router = useRouter()
const [showDashboard, setShowDashboard] = useState(false)
const [debugInfo, setDebugInfo] = useState<any>(null)
const [isEditingProfile, setIsEditingProfile] = useState(false)
const [profileData, setProfileData] = useState({
name: user?.name || '',
bio: user?.bio || '',
avatar: user?.avatar || ''
})
const [stats, setStats] = useState({
coursesCompleted: 12,
totalXP: 2450,
currentStreak: 7,
rank: 156,
certificatesEarned: 3,
hoursLearned: 45
})
useEffect(() => {
// Debug authentication state
const authState = {
isLoadingAuth,
walletConnected,
walletAddress: !!walletAddress,
firebaseUser: !!firebaseUser,
authMethod,
localStorage: {
token: !!localStorage.getItem('openlearnx_jwt_token'),
wallet: !!localStorage.getItem('openlearnx_wallet'),
user: !!localStorage.getItem('openlearnx_user')
}
if (!user && !firebaseUser) {
router.replace("/auth/login")
}
setDebugInfo(authState)
console.log('📊 Dashboard auth state:', authState)
}, [user, firebaseUser, router])
// Give auth some time to initialize
const timer = setTimeout(() => {
const isAuthenticated = (walletConnected && walletAddress) || firebaseUser
if (isAuthenticated) {
console.log('✅ User authenticated, showing dashboard')
setShowDashboard(true)
} else if (!isLoadingAuth) {
console.log('❌ User not authenticated, redirecting to login')
router.replace("/auth/login")
}
}, 2000) // Wait 2 seconds for auth to stabilize
const handleProfileUpdate = async () => {
try {
// Here you would call your API to update profile
// await updateProfile(profileData)
setIsEditingProfile(false)
console.log("Profile updated:", profileData)
} catch (error) {
console.error("Failed to update profile:", error)
}
}
return () => clearTimeout(timer)
}, [isLoadingAuth, walletConnected, walletAddress, firebaseUser, authMethod, router])
// Show loading state
if (isLoadingAuth || !showDashboard) {
if (!user && !firebaseUser) {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 dark:from-gray-900 dark:via-blue-900 dark:to-purple-900">
<div className="text-center space-y-4 max-w-md mx-auto p-6">
<Loader2 className="w-12 h-12 animate-spin mx-auto text-purple-600" />
<div className="space-y-2">
<h3 className="text-xl font-semibold text-gray-900 dark:text-gray-100">
Loading Dashboard...
</h3>
<p className="text-gray-600 dark:text-gray-400">
{walletConnected ? `Connected to ${walletAddress?.slice(0, 6)}...${walletAddress?.slice(-4)}` :
firebaseUser ? `Logged in as ${firebaseUser.email}` :
'Verifying authentication...'}
</p>
</div>
{/* Debug info in development */}
{process.env.NODE_ENV === 'development' && debugInfo && (
<details className="text-left text-xs text-gray-500 bg-gray-100 dark:bg-gray-800 p-2 rounded mt-4">
<summary>Debug Info</summary>
<pre>{JSON.stringify(debugInfo, null, 2)}</pre>
</details>
)}
</div>
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-600"></div>
</div>
)
}
// Show error state if no auth after loading
if (!walletConnected && !firebaseUser && !isLoadingAuth) {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 dark:from-gray-900 dark:via-blue-900 dark:to-purple-900">
<div className="text-center space-y-4 max-w-md mx-auto p-6">
<AlertCircle className="w-16 h-16 text-red-500 mx-auto" />
<h3 className="text-xl font-semibold text-gray-900 dark:text-gray-100">
Authentication Required
</h3>
<p className="text-gray-600 dark:text-gray-400">
Please log in to access your dashboard.
</p>
<div className="space-y-2">
<Button onClick={() => router.push("/auth/login")} className="w-full">
Go to Login
</Button>
<Button
variant="outline"
onClick={() => {
localStorage.clear()
window.location.href = "/auth/login"
}}
className="w-full"
>
Clear Data & Login
</Button>
return (
<div className="min-h-screen bg-gradient-to-br from-gray-50 to-blue-50">
{/* Professional Header */}
<header className="bg-white shadow-lg border-b border-gray-100">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
<div className="flex items-center space-x-4">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 bg-gradient-to-r from-indigo-600 via-purple-600 to-blue-600 rounded-xl flex items-center justify-center shadow-lg">
<BookOpen className="w-6 h-6 text-white" />
</div>
<div>
<h1 className="text-xl font-bold bg-gradient-to-r from-indigo-600 to-purple-600 bg-clip-text text-transparent">
OpenLearnX
</h1>
<p className="text-xs text-gray-500">Learn Earn Grow</p>
</div>
</div>
</div>
<div className="flex items-center space-x-3">
<button className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-xl transition-all duration-200">
<Settings className="w-5 h-5" />
</button>
<button
onClick={logout}
className="flex items-center space-x-2 px-4 py-2 text-red-600 hover:text-white hover:bg-red-600 rounded-xl transition-all duration-200 border border-red-200 hover:border-red-600"
>
<LogOut className="w-4 h-4" />
<span className="text-sm font-medium">Logout</span>
</button>
</div>
</div>
{/* Debug info */}
{process.env.NODE_ENV === 'development' && (
<details className="text-left text-xs text-gray-500 bg-gray-100 dark:bg-gray-800 p-2 rounded mt-4">
<summary>Debug Info</summary>
<pre>{JSON.stringify(debugInfo, null, 2)}</pre>
</details>
)}
</div>
</div>
)
}
</header>
// Show dashboard if authenticated
return <DashboardStatsOverview />
{/* Main Dashboard Content */}
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{/* Welcome Section */}
<div className="mb-8">
<div className="bg-gradient-to-r from-indigo-600 via-purple-600 to-blue-600 rounded-2xl p-8 text-white shadow-xl">
<div className="flex items-center justify-between">
<div>
<h2 className="text-3xl font-bold mb-2">
Welcome back! 👋
</h2>
<p className="text-indigo-100 text-lg">
Ready to continue your learning journey?
</p>
{authMethod === "metamask" && user ? (
<div className="mt-3 flex items-center space-x-2">
<Wallet className="w-4 h-4 text-orange-300" />
<span className="text-sm text-indigo-100">
Connected: {user.wallet_address.slice(0, 6)}...{user.wallet_address.slice(-4)}
</span>
</div>
) : firebaseUser && (
<div className="mt-3 flex items-center space-x-2">
<Mail className="w-4 h-4 text-blue-300" />
<span className="text-sm text-indigo-100">
{firebaseUser.email}
</span>
</div>
)}
</div>
<div className="hidden md:block">
<div className="w-32 h-32 bg-white/10 rounded-full flex items-center justify-center backdrop-blur-sm">
<Trophy className="w-16 h-16 text-yellow-300" />
</div>
</div>
</div>
</div>
</div>
{/* Stats Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<div className="bg-white rounded-2xl shadow-lg border border-gray-100 p-6 hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-semibold text-gray-600 uppercase tracking-wide">Total XP</p>
<p className="text-3xl font-bold text-gray-900 mt-1">{stats.totalXP.toLocaleString()}</p>
</div>
<div className="p-4 bg-gradient-to-r from-indigo-500 to-purple-500 rounded-xl shadow-lg">
<Trophy className="w-8 h-8 text-white" />
</div>
</div>
<div className="flex items-center mt-4">
<TrendingUp className="w-4 h-4 text-green-500 mr-2" />
<span className="text-sm text-green-600 font-medium">+12% from last week</span>
</div>
</div>
<div className="bg-white rounded-2xl shadow-lg border border-gray-100 p-6 hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-semibold text-gray-600 uppercase tracking-wide">Courses</p>
<p className="text-3xl font-bold text-gray-900 mt-1">{stats.coursesCompleted}</p>
</div>
<div className="p-4 bg-gradient-to-r from-green-500 to-teal-500 rounded-xl shadow-lg">
<BookOpen className="w-8 h-8 text-white" />
</div>
</div>
<div className="flex items-center mt-4">
<Activity className="w-4 h-4 text-blue-500 mr-2" />
<span className="text-sm text-blue-600 font-medium">3 in progress</span>
</div>
</div>
<div className="bg-white rounded-2xl shadow-lg border border-gray-100 p-6 hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-semibold text-gray-600 uppercase tracking-wide">Streak</p>
<p className="text-3xl font-bold text-gray-900 mt-1">{stats.currentStreak} days</p>
</div>
<div className="p-4 bg-gradient-to-r from-orange-500 to-red-500 rounded-xl shadow-lg">
<Target className="w-8 h-8 text-white" />
</div>
</div>
<div className="flex items-center mt-4">
<span className="text-sm text-orange-600 font-medium">🔥 Keep it up!</span>
</div>
</div>
<div className="bg-white rounded-2xl shadow-lg border border-gray-100 p-6 hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1">
<div className="flex items-center justify-between">
<div>
<p className="text-sm font-semibold text-gray-600 uppercase tracking-wide">Global Rank</p>
<p className="text-3xl font-bold text-gray-900 mt-1">#{stats.rank}</p>
</div>
<div className="p-4 bg-gradient-to-r from-purple-500 to-pink-500 rounded-xl shadow-lg">
<BarChart3 className="w-8 h-8 text-white" />
</div>
</div>
<div className="flex items-center mt-4">
<Award className="w-4 h-4 text-purple-500 mr-2" />
<span className="text-sm text-purple-600 font-medium">Top 5% learner</span>
</div>
</div>
</div>
{/* Main Content Grid */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Profile Card with Edit Functionality */}
<div className="lg:col-span-1">
<div className="bg-white rounded-2xl shadow-lg border border-gray-100 p-6">
<div className="flex items-center justify-between mb-6">
<h3 className="text-xl font-bold text-gray-900">Profile</h3>
<button
onClick={() => setIsEditingProfile(!isEditingProfile)}
className="p-2 text-gray-500 hover:text-indigo-600 hover:bg-indigo-50 rounded-lg transition-all duration-200"
>
{isEditingProfile ? <X className="w-5 h-5" /> : <Edit3 className="w-5 h-5" />}
</button>
</div>
<div className="text-center mb-6">
<div className="w-20 h-20 bg-gradient-to-r from-indigo-600 to-purple-600 rounded-full flex items-center justify-center mx-auto mb-4 shadow-lg">
<User className="w-10 h-10 text-white" />
</div>
{isEditingProfile ? (
<div className="space-y-3">
<input
type="text"
value={profileData.name}
onChange={(e) => setProfileData({...profileData, name: e.target.value})}
placeholder="Your name"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 text-center"
/>
<textarea
value={profileData.bio}
onChange={(e) => setProfileData({...profileData, bio: e.target.value})}
placeholder="Your bio"
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 text-center h-20 resize-none"
/>
<button
onClick={handleProfileUpdate}
className="flex items-center space-x-2 px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors mx-auto"
>
<Save className="w-4 h-4" />
<span>Save</span>
</button>
</div>
) : (
<div>
<h4 className="text-lg font-semibold text-gray-900">
{profileData.name || "Your Name"}
</h4>
<p className="text-gray-600 text-sm mt-1">
{profileData.bio || "Add a bio to tell others about yourself"}
</p>
</div>
)}
</div>
<div className="space-y-4">
<div className="flex items-center justify-between p-4 bg-gradient-to-r from-indigo-50 to-purple-50 rounded-xl border border-indigo-100">
<div className="flex items-center space-x-3">
{authMethod === "metamask" ? (
<Wallet className="w-6 h-6 text-orange-600" />
) : (
<Mail className="w-6 h-6 text-blue-600" />
)}
<div>
<p className="text-sm font-semibold text-gray-900">Auth Method</p>
<p className="text-xs text-gray-600">
{authMethod === "metamask" ? "MetaMask Wallet" : "Email Account"}
</p>
</div>
</div>
<div className="flex items-center space-x-2">
<div className="w-3 h-3 bg-green-500 rounded-full animate-pulse"></div>
<span className="text-xs text-green-600 font-medium">Connected</span>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="text-center p-4 bg-blue-50 rounded-xl">
<Calendar className="w-6 h-6 text-blue-600 mx-auto mb-2" />
<p className="text-2xl font-bold text-blue-900">{stats.hoursLearned}</p>
<p className="text-xs text-blue-600 font-medium">Hours Learned</p>
</div>
<div className="text-center p-4 bg-green-50 rounded-xl">
<Award className="w-6 h-6 text-green-600 mx-auto mb-2" />
<p className="text-2xl font-bold text-green-900">{stats.certificatesEarned}</p>
<p className="text-xs text-green-600 font-medium">Certificates</p>
</div>
</div>
</div>
</div>
</div>
{/* Recent Activity */}
<div className="lg:col-span-2">
<div className="bg-white rounded-2xl shadow-lg border border-gray-100 p-6">
<div className="flex items-center justify-between mb-6">
<h3 className="text-xl font-bold text-gray-900">Recent Activity</h3>
<button className="text-sm text-indigo-600 hover:text-indigo-800 font-semibold hover:bg-indigo-50 px-3 py-1 rounded-lg transition-all duration-200">
View all
</button>
</div>
<div className="space-y-4">
{[
{
type: "course",
title: "Completed React Fundamentals",
time: "2 hours ago",
icon: BookOpen,
color: "green",
bgColor: "bg-green-100",
textColor: "text-green-600"
},
{
type: "quiz",
title: "Scored 95% on JavaScript Quiz",
time: "1 day ago",
icon: Award,
color: "blue",
bgColor: "bg-blue-100",
textColor: "text-blue-600"
},
{
type: "streak",
title: "7-day learning streak!",
time: "Today",
icon: Target,
color: "orange",
bgColor: "bg-orange-100",
textColor: "text-orange-600"
},
{
type: "rank",
title: "Moved up 5 positions in leaderboard",
time: "2 days ago",
icon: TrendingUp,
color: "purple",
bgColor: "bg-purple-100",
textColor: "text-purple-600"
},
].map((activity, index) => (
<div key={index} className="flex items-center space-x-4 p-4 hover:bg-gray-50 rounded-xl transition-all duration-200 border border-gray-100 hover:border-gray-200 hover:shadow-md">
<div className={`p-3 rounded-xl ${activity.bgColor} shadow-sm`}>
<activity.icon className={`w-5 h-5 ${activity.textColor}`} />
</div>
<div className="flex-1">
<p className="text-sm font-semibold text-gray-900">{activity.title}</p>
<p className="text-xs text-gray-500 mt-1">{activity.time}</p>
</div>
<div className="w-2 h-2 bg-gray-300 rounded-full"></div>
</div>
))}
</div>
<div className="mt-6 p-4 bg-gradient-to-r from-indigo-50 to-purple-50 rounded-xl border border-indigo-100">
<h4 className="text-sm font-semibold text-indigo-900 mb-2">🚀 Keep Learning!</h4>
<p className="text-xs text-indigo-700">
You're doing great! Complete 2 more courses this week to maintain your streak.
</p>
</div>
</div>
</div>
</div>
</main>
</div>
)
}