Create a New Course

Enter a clear and engaging title for your course.
Describe what students will learn in this course.
Choose the category that best fits your course.
Specify the main topic or focus of the course.
Select the difficulty level of your course.
Set the price in USD (e.g., 49.99).
Estimate the total hours to complete the course.
Choose the format of your course.
Upload a high-quality image to represent your course.

Live Session Schedule

Schedule the date and time for the live session.
Set the deadline for students to enroll.
Allow students to sync the session to their calendar.
Limit the number of students who can enroll (optional).

Course Modules

Add and reorder modules to structure your course content.

Accessibility Options

Upload caption files for video accessibility.
Allow students to adjust audio playback speed.

Interactive Elements

Add quizzes to test student knowledge.
Enter quiz questions in JSON format.
Define how students complete the course.

Marketing Tools

Create a promo code for discounts.
Set a discount percentage for the course.
Select the primary language for the course content.
WhatsApp Instructor Dashboard - Elora Tech Institute

Welcome, ! Shape the Future with Your Courses 🚀

Total Earnings: $0.00

Create Course

Build a new course with videos, ebooks, or live sessions.

Manage Courses

Edit, delete, or upload content.

View Students

Monitor student progress.

Course Analytics

Track enrollments and reviews.

Your Courses

Your Students

Course Analytics

WhatsApp const user = JSON.parse(localStorage.getItem('user')); if (!user || user.role !== 'instructor') { window.location.href = 'tutor-signup-login.html'; } document.getElementById('userName').textContent = user.name; async function fetchWithAuth(url, options = {}) { const token = localStorage.getItem('token'); if (!token) { showError('No authentication token found. Please log in again.'); setTimeout(() => window.location.href = 'tutor-signup-login.html', 2000); throw new Error('No token'); } const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, ...options.headers }; const response = await fetch(url, { ...options, headers }); if (response.status === 401) { showError('Session expired. Please log in again.'); localStorage.removeItem('token'); localStorage.removeItem('user'); setTimeout(() => window.location.href = 'tutor-signup-login.html', 1000); throw new Error('Unauthorized'); } if (!response.ok) { const data = await response.json(); throw new Error(data.error || `HTTP error ${response.status}`); } return response.json(); } function openModal(modalId) { const modal = document.getElementById(modalId); modal.style.display = 'flex'; modal.querySelector('input, textarea, select').focus(); } function closeModal(modalId) { const modal = document.getElementById(modalId); modal.style.display = 'none'; if (modalId === 'editCourseModal') { document.getElementById('edit-course-id').value = ''; document.getElementById('edit-course-title').value = ''; document.getElementById('edit-course-description').value = ''; document.getElementById('edit-course-price').value = ''; document.getElementById('edit-course-duration').value = ''; document.getElementById('edit-course-type').value = 'live'; } else if (modalId === 'uploadContentModal') { document.getElementById('upload-course-id').value = ''; document.getElementById('content-title').value = ''; document.getElementById('content-type').value = 'video'; document.getElementById('content-file').value = ''; } else if (modalId === 'notificationModal') { document.getElementById('notification-course-id').value = ''; document.getElementById('notification-message').value = ''; } } function scrollToSection(sectionId) { document.getElementById(sectionId).scrollIntoView({ behavior: 'smooth' }); } function logout() { localStorage.removeItem('user'); localStorage.removeItem('token'); localStorage.removeItem('refreshToken'); window.location.href = 'tutor-signup-login.html'; } function showError(message, color = '#dc3545') { const errorDiv = document.getElementById('error'); errorDiv.textContent = message; errorDiv.style.color = color; errorDiv.focus(); setTimeout(() => errorDiv.textContent = '', 3000); } async function uploadProfilePicture(event) { const file = event.target.files[0]; if (!file) return; const formData = new FormData(); formData.append('profile_picture', file); try { const data = await fetchWithAuth(`http://localhost:3000/api/users/${user.id}/profile-picture`, { method: 'POST', body: formData, headers: {} }); document.getElementById('dashboard-profile-picture').src = data.profile_picture_url; showError('Profile picture updated successfully! 📸', '#28a745'); } catch (err) { showError('Failed to upload profile picture: ' + err.message); } } function openEditCourse(course) { document.getElementById('edit-course-id').value = course.id; document.getElementById('edit-course-title').value = course.title; document.getElementById('edit-course-description').value = course.description; document.getElementById('edit-course-price').value = course.price; document.getElementById('edit-course-duration').value = course.duration || ''; document.getElementById('edit-course-type').value = course.course_type; openModal('editCourseModal'); } async function updateCourse() { const form = document.getElementById('edit-course-form'); if (!form.checkValidity()) { showError('Please fill out all required fields correctly.'); return; } const id = document.getElementById('edit-course-id').value; const title = document.getElementById('edit-course-title').value; const description = document.getElementById('edit-course-description').value; const price = parseFloat(document.getElementById('edit-course-price').value); const duration = parseInt(document.getElementById('edit-course-duration').value); const course_type = document.getElementById('edit-course-type').value; try { await fetchWithAuth(`http://localhost:3000/api/courses/${id}`, { method: 'PATCH', body: JSON.stringify({ title, description, price, duration, course_type }) }); fetchCourses(); closeModal('editCourseModal'); showError('Course updated successfully!', '#28a745'); } catch (err) { showError('Failed to update course: ' + err.message); } } async function deleteCourse(courseId) { if (confirm('Are you sure you want to delete this course?')) { try { await fetchWithAuth(`http://localhost:3000/api/courses/${courseId}`, { method: 'DELETE' }); fetchCourses(); showError('Course deleted successfully!', '#28a745'); } catch (err) { showError('Failed to delete course: ' + err.message); } } } function openUploadContent(courseId) { document.getElementById('upload-course-id').value = courseId; openModal('uploadContentModal'); } async function uploadContent() { const form = document.getElementById('upload-content-form'); if (!form.checkValidity()) { showError('Please fill out all required fields correctly.'); return; } const course_id = document.getElementById('upload-course-id').value; const title = document.getElementById('content-title').value; const file_type = document.getElementById('content-type').value; const file = document.getElementById('content-file').files[0]; const formData = new FormData(); formData.append('title', title); formData.append('file_type', file_type); if (file) formData.append('file', file); try { await fetchWithAuth(`http://localhost:3000/api/courses/${course_id}/content`, { method: 'POST', body: formData, headers: {} }); closeModal('uploadContentModal'); showError('Content uploaded successfully!', '#28a745'); } catch (err) { showError('Failed to upload content: ' + err.message); } } function openNotification(courseId) { document.getElementById('notification-course-id').value = courseId; openModal('notificationModal'); } async function sendNotification() { const form = document.getElementById('notification-form'); if (!form.checkValidity()) { showError('Please fill out all required fields correctly.'); return; } const course_id = document.getElementById('notification-course-id').value; const message = document.getElementById('notification-message').value; try { await fetchWithAuth('http://localhost:3000/api/notifications', { method: 'POST', body: JSON.stringify({ course_id, message, notification_type: 'course_notification' }) }); closeModal('notificationModal'); showError('Notification sent successfully!', '#28a745'); } catch (err) { showError('Failed to send notification: ' + err.message); } } async function downloadCalendar(courseId) { try { const course = await fetchWithAuth(`http://localhost:3000/api/courses/${courseId}`); if (course.course_type === 'live' && course.live_schedule) { const icsContent = ` BEGIN:VCALENDAR VERSION:2.0 BEGIN:VEVENT SUMMARY:${course.title} DTSTART:${new Date(course.live_schedule.date).toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z'} DTEND:${new Date(new Date(course.live_schedule.date).getTime() + course.duration * 60 * 60 * 1000).toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z'} DESCRIPTION:${course.description} END:VEVENT END:VCALENDAR `; const blob = new Blob([icsContent], { type: 'text/calendar' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${course.title}.ics`; a.click(); URL.revokeObjectURL(url); } else { showError('No live schedule available for this course.'); } } catch (err) { showError('Failed to download calendar: ' + err.message); } } async function previewAudio(contentId) { try { const content = await fetchWithAuth(`http://localhost:3000/api/courses/content/${contentId}`); if (content.file_type === 'ebook' || content.file_type === 'pdf') { const text = content.text_content || 'Sample text'; const utterance = new SpeechSynthesisUtterance(text); utterance.lang = content.language || 'en-US'; window.speechSynthesis.speak(utterance); } else { showError('Audio preview only available for ebooks or PDFs.'); } } catch (err) { showError('Failed to preview audio: ' + err.message); } } async function fetchCommunity(courseId) { try { const discussions = await fetchWithAuth(`http://localhost:3000/api/courses/${courseId}/discussions`); const communityList = document.createElement('div'); communityList.setAttribute('role', 'region'); communityList.setAttribute('aria-label', 'Discussion forum'); communityList.innerHTML = `

Discussion Forum for ${courseId}

Post a message to the discussion forum.
`; document.getElementById('courses').appendChild(communityList); } catch (err) { showError('Failed to load discussions: ' + err.message); } } async function postDiscussion(courseId) { const form = document.getElementById('discussion-form'); if (!form.checkValidity()) { showError('Please enter a valid message.'); return; } const message = document.getElementById('new-discussion').value; try { await fetchWithAuth(`http://localhost:3000/api/courses/${courseId}/discussions`, { method: 'POST', body: JSON.stringify({ message }) }); fetchCommunity(courseId); } catch (err) { showError('Failed to post discussion: ' + err.message); } } async function fetchCourses() { try { const courses = await fetchWithAuth(`http://localhost:3000/api/courses?user_id=${user.id}`); const courseList = document.getElementById('course-list'); courseList.innerHTML = ''; if (!Array.isArray(courses) || courses.length === 0) { courseList.innerHTML = '
  • No courses found
  • '; return; } courses.forEach(course => { const li = document.createElement('li'); li.innerHTML = `
    ${course.title}
    ${course.description || 'No description'}
    Category: ${course.category || 'N/A'} | Topic: ${course.topic || 'N/A'}
    Level: ${course.level || 'N/A'} | Price: $${course.price} | Duration: ${course.duration || 'N/A'} hours
    Type: ${course.course_type} | Enrollment Limit: ${course.enrollment_limit || 'Unlimited'}
    Status: ${course.status}
    ${course.status === 'pending' || course.status === 'draft' ? ` ` : ''} ${course.status === 'approved' ? ` ${course.course_type === 'live' ? `` : ''} ${course.course_type === 'ebook' ? `` : ''} ` : ''}
    `; courseList.appendChild(li); }); } catch (err) { document.getElementById('course-list').innerHTML = '
  • Error loading courses: ' + err.message + '
  • '; } } async function fetchStudents() { try { const students = await fetchWithAuth(`http://localhost:3000/api/users?role=student`); const studentList = document.getElementById('student-list'); studentList.innerHTML = ''; if (!Array.isArray(students) || students.length === 0) { studentList.innerHTML = '
  • No students found
  • '; return; } students.forEach(student => { const li = document.createElement('li'); li.innerHTML = `
    ${student.name} (${student.email})
    `; li.onclick = () => fetchStudentProgress(student.id); li.style.cursor = 'pointer'; li.setAttribute('role', 'button'); li.setAttribute('aria-label', `View progress for ${student.name}`); studentList.appendChild(li); }); } catch (err) { document.getElementById('student-list').innerHTML = '
  • Error loading students: ' + err.message + '
  • '; } } async function fetchStudentProgress(studentId) { try { const courses = await fetchWithAuth(`http://localhost:3000/api/courses?user_id=${user.id}`); let progressHtml = `

    Student Progress

    `; for (const course of courses) { const progress = await fetchWithAuth(`http://localhost:3000/api/courses/${course.id}/progress?user_id=${studentId}`); if (progress.progress !== undefined) { progressHtml += `

    ${course.title}: ${progress.progress}% complete

    `; } } document.getElementById('student-list').innerHTML = progressHtml + ''; } catch (err) { showError('Error loading student progress: ' + err.message); } } async function fetchAnalytics() { try { const courses = await fetchWithAuth(`http://localhost:3000/api/courses?user_id=${user.id}`); const analyticsList = document.getElementById('analytics-list'); analyticsList.innerHTML = ''; if (!Array.isArray(courses) || courses.length === 0) { analyticsList.innerHTML = '
  • No analytics available
  • '; return; } for (const course of courses) { const analytics = await fetchWithAuth(`http://localhost:3000/api/courses/${course.id}/analytics`); const li = document.createElement('li'); li.innerHTML = `
    ${course.title}
    Enrollments: ${analytics.enrollment_count}
    Average Rating: ${analytics.avg_rating ? analytics.avg_rating.toFixed(1) : 'N/A'}/5 (${analytics.review_count || 0} reviews)
    Completions: ${analytics.completion_count}
    Drop-off Rate: ${analytics.dropoff_rate ? analytics.dropoff_rate.toFixed(1) : 'N/A'}%
    `; analyticsList.appendChild(li); } const enrollmentData = courses.map(c => ({ label: c.title, data: (await fetchWithAuth(`http://localhost:3000/api/courses/${c.id}/analytics`)).enrollment_count })); displayEnrollmentChart(enrollmentData); } catch (err) { document.getElementById('analytics-list').innerHTML = '
  • Error loading analytics: ' + err.message + '
  • '; } } function displayEnrollmentChart(data) { const chartDiv = document.createElement('div'); chartDiv.setAttribute('role', 'img'); chartDiv.setAttribute('aria-label', 'Bar chart of course enrollments'); chartDiv.innerHTML = ` `; document.getElementById('analytics-list').appendChild(chartDiv); } async function initializeDashboard() { try { const profile = await fetchWithAuth(`http://localhost:3000/api/users/${user.id}`); document.getElementById('dashboard-profile-picture').src = profile.profile_picture_url || 'images/avatars/default.jpg'; await Promise.all([ fetchCourses(), fetchStudents(), fetchAnalytics(), fetchEarnings() ]); } catch (err) { showError('Failed to initialize dashboard: ' + err.message); } } async function fetchEarnings() { try { const data = await fetchWithAuth(`http://localhost:3000/api/users/${user.id}/earnings`); document.getElementById('totalEarnings').textContent = data.total_earnings.toFixed(2); } catch (err) { document.getElementById('totalEarnings').textContent = 'N/A'; showError('Error loading earnings: ' + err.message); } } initializeDashboard();