'use client' import React, { useState, useEffect } from 'react' import { useRouter } from 'next/navigation' import { Plus, Edit, Trash2, Eye, RefreshCw } from 'lucide-react' interface Course { id: string title: string subject: string description: string difficulty: string mentor: string video_url: string students: number status: 'published' | 'draft' created_at: string } export default function AdminDashboard() { const [isClient, setIsClient] = useState(false) const [isAuthenticated, setIsAuthenticated] = useState(false) const [authChecked, setAuthChecked] = useState(false) const [courses, setCourses] = useState([]) const [loading, setLoading] = useState(true) const [showAddForm, setShowAddForm] = useState(false) const [editingCourse, setEditingCourse] = useState(null) const [stats, setStats] = useState({ total_courses: 0, total_lessons: 0, active_students: 0, completion_rate: 0 }) const router = useRouter() // Enhanced authentication with API verification to prevent redirect loops useEffect(() => { setIsClient(true) const checkAuth = async () => { try { // Add delay to prevent race conditions await new Promise(resolve => setTimeout(resolve, 500)) const token = localStorage.getItem('admin_token') console.log('Dashboard - checking token:', token) if (!token) { console.log('Dashboard - no token found') router.push('/admin/login') return } if (token === 'admin-secret-key') { console.log('Dashboard - token format valid, verifying with API...') try { const response = await fetch('http://127.0.0.1:5000/api/admin/courses', { headers: { 'Authorization': `Bearer ${token}` } }) if (response.ok) { console.log('✅ Dashboard - API confirms token valid') setIsAuthenticated(true) fetchData() } else { console.log('❌ Dashboard - API rejects token') localStorage.removeItem('admin_token') router.push('/admin/login') } } catch (apiError) { console.error('Dashboard - API check failed:', apiError) // Don't redirect on API error, might be temporary network issue setIsAuthenticated(true) fetchData() } } else { console.log('Dashboard - invalid token format') localStorage.removeItem('admin_token') router.push('/admin/login') } } catch (error) { console.error('Dashboard - auth check error:', error) router.push('/admin/login') } finally { setAuthChecked(true) } } checkAuth() }, [router]) const fetchData = async () => { await Promise.all([fetchCourses(), fetchStats()]) } const fetchCourses = async () => { try { console.log('Fetching courses...') const response = await fetch('http://127.0.0.1:5000/api/admin/courses', { headers: { 'Authorization': 'Bearer admin-secret-key', 'Content-Type': 'application/json' } }) console.log('Response status:', response.status) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`) } const data = await response.json() console.log('Received data:', data) if (Array.isArray(data)) { setCourses(data) console.log('✅ Courses set successfully:', data.length, 'courses') } else { console.error('❌ API returned non-array data:', data) setCourses([]) } } catch (error) { console.error('❌ Error fetching courses:', error) setCourses([]) } finally { setLoading(false) } } const fetchStats = async () => { try { const response = await fetch('http://127.0.0.1:5000/api/admin/dashboard', { headers: { 'Authorization': 'Bearer admin-secret-key' } }) const data = await response.json() setStats(data) } catch (error) { console.error('Error fetching stats:', error) } } const handleCreateCourse = async (formData: any) => { try { const response = await fetch('http://127.0.0.1:5000/api/admin/courses', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer admin-secret-key' }, body: JSON.stringify(formData) }) if (response.ok) { await fetchData() setShowAddForm(false) alert('Course created successfully!') } else { const error = await response.json() alert(`Error: ${error.error}`) } } catch (error) { console.error('Error creating course:', error) alert('Failed to create course') } } const handleUpdateCourse = async (courseId: string, formData: any) => { try { const response = await fetch(`http://127.0.0.1:5000/api/admin/courses/${courseId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer admin-secret-key' }, body: JSON.stringify(formData) }) if (response.ok) { await fetchData() setEditingCourse(null) alert('Course updated successfully!') } else { const error = await response.json() alert(`Error: ${error.error}`) } } catch (error) { console.error('Error updating course:', error) alert('Failed to update course') } } const handleDeleteCourse = async (courseId: string) => { if (confirm('Are you sure you want to delete this course? This action cannot be undone.')) { try { const response = await fetch(`http://127.0.0.1:5000/api/admin/courses/${courseId}`, { method: 'DELETE', headers: { 'Authorization': 'Bearer admin-secret-key' } }) if (response.ok) { await fetchData() alert('Course deleted successfully!') } else { const error = await response.json() alert(`Error: ${error.error}`) } } catch (error) { console.error('Error deleting course:', error) alert('Failed to delete course') } } } const initializeDefaultCourses = async () => { try { const response = await fetch('http://127.0.0.1:5000/api/admin/initialize', { method: 'POST', headers: { 'Authorization': 'Bearer admin-secret-key' } }) if (response.ok) { await fetchData() alert('Default courses initialized!') } } catch (error) { console.error('Error initializing courses:', error) } } const handleLogout = () => { localStorage.removeItem('admin_token') router.push('/') } // Show loading until auth is checked if (!isClient || !authChecked) { return (

Checking authentication...

) } // Show redirect message if not authenticated if (!isAuthenticated) { return (

Redirecting to login...

) } return (
{/* Header */}
OL

OpenLearnX Admin Panel

DYNAMIC
Welcome, 5t4l1n! 👋
{/* Action Buttons */}

Course Management

Add, edit, or remove courses dynamically

{/* Stats Cards */}

Total Courses

{stats.total_courses}

Active Students

{stats.active_students}

Total Lessons

{stats.total_lessons}

Completion Rate

{stats.completion_rate}%

{/* Course Table */}

All Courses

{loading ? (

Loading courses...

) : !Array.isArray(courses) || courses.length === 0 ? (

No courses found. Initialize default courses or add a new one.

) : (
{courses.map((course) => ( ))}
Course Mentor Students Actions
{course.title}
{course.subject} • {course.difficulty}
{course.mentor} {course.students?.toLocaleString() || 0}
)}
{/* Add Course Modal */} {showAddForm && ( setShowAddForm(false)} onSubmit={handleCreateCourse} /> )} {/* Edit Course Modal */} {editingCourse && ( setEditingCourse(null)} onSubmit={(data) => handleUpdateCourse(editingCourse.id, data)} /> )}
) } // Course Form Modal Component function CourseFormModal({ title, course, onClose, onSubmit }: { title: string course?: Course onClose: () => void onSubmit: (data: any) => void }) { const [formData, setFormData] = useState({ title: course?.title || '', subject: course?.subject || 'Programming', description: course?.description || '', difficulty: course?.difficulty || 'Beginner', mentor: course?.mentor || '5t4l1n', video_url: course?.video_url || '' }) const handleSubmit = (e: React.FormEvent) => { e.preventDefault() onSubmit(formData) } const getEmbedUrl = (videoUrl: string) => { if (!videoUrl) return null let videoId = '' if (videoUrl.includes('youtu.be/')) { videoId = videoUrl.split('youtu.be/')[1]?.split('?')[0] } else if (videoUrl.includes('youtube.com/watch?v=')) { videoId = videoUrl.split('v=')[1]?.split('&')[0] } else if (videoUrl.includes('youtube.com/embed/')) { return videoUrl } return videoId ? `https://www.youtube.com/embed/${videoId}?rel=0&modestbranding=1` : null } return (

{title}

setFormData({...formData, title: e.target.value})} className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="e.g., Advanced React Development" />
setFormData({...formData, mentor: e.target.value})} className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Instructor name" />