|
|
class LearningPlatform { |
|
|
constructor() { |
|
|
this.currentDay = 1; |
|
|
this.maxDays = 3; |
|
|
this.isInitialized = false; |
|
|
this.components = {}; |
|
|
} |
|
|
|
|
|
async initialize() { |
|
|
try { |
|
|
console.log('🚀 Initializing Learning Platform...'); |
|
|
|
|
|
|
|
|
this.initializeAuth(); |
|
|
|
|
|
|
|
|
this.debugAuth(); |
|
|
|
|
|
|
|
|
this.loadComponents(); |
|
|
|
|
|
|
|
|
this.setupEventListeners(); |
|
|
|
|
|
|
|
|
await this.loadInitialContent(); |
|
|
|
|
|
|
|
|
this.updateUI(); |
|
|
|
|
|
this.isInitialized = true; |
|
|
console.log('✅ Platform initialized successfully'); |
|
|
|
|
|
} catch (error) { |
|
|
console.error('❌ Failed to initialize platform:', error); |
|
|
this.showError('خطا در بارگذاری برنامه. لطفاً صفحه را رفرش کنید.'); |
|
|
} |
|
|
} |
|
|
|
|
|
initializeAuth() { |
|
|
console.log('🔐 Initializing authentication system...'); |
|
|
|
|
|
|
|
|
if (typeof authManager !== 'undefined') { |
|
|
authManager.initializeDefaultUsers(); |
|
|
console.log('👥 Default users initialized'); |
|
|
} else { |
|
|
console.error('❌ authManager is not defined'); |
|
|
} |
|
|
|
|
|
|
|
|
if (typeof AuthMiddleware !== 'undefined') { |
|
|
AuthMiddleware.initializeApp(); |
|
|
} |
|
|
|
|
|
|
|
|
const savedTheme = localStorage.getItem('theme'); |
|
|
if (savedTheme) { |
|
|
document.body.setAttribute('data-theme', savedTheme); |
|
|
} |
|
|
} |
|
|
|
|
|
debugAuth() { |
|
|
console.log('🔍 Auth Debug Info:'); |
|
|
console.log('- Token:', authManager?.getToken()); |
|
|
console.log('- Current User:', authManager?.getCurrentUser()); |
|
|
console.log('- All Users:', authManager?.getUsers()); |
|
|
console.log('- Is Authenticated:', authManager?.isAuthenticated()); |
|
|
} |
|
|
|
|
|
loadComponents() { |
|
|
console.log('🔧 Loading components...'); |
|
|
|
|
|
|
|
|
this.components = { |
|
|
header: typeof HeaderComponent !== 'undefined' ? new HeaderComponent() : null, |
|
|
modal: typeof ModalComponent !== 'undefined' ? new ModalComponent() : null, |
|
|
navigation: typeof NavigationComponent !== 'undefined' ? new NavigationComponent() : null, |
|
|
lessonUI: typeof LessonUI !== 'undefined' ? new LessonUI() : null, |
|
|
quizUI: typeof QuizUI !== 'undefined' ? new QuizUI() : null, |
|
|
exerciseUI: typeof ExerciseUI !== 'undefined' ? new ExerciseUI() : null |
|
|
}; |
|
|
|
|
|
console.log('✅ Components loaded:', Object.keys(this.components)); |
|
|
|
|
|
|
|
|
if (this.components.header) { |
|
|
this.components.header.render(); |
|
|
} |
|
|
|
|
|
if (this.components.navigation) { |
|
|
this.components.navigation.render(); |
|
|
} |
|
|
} |
|
|
|
|
|
setupEventListeners() { |
|
|
console.log('🎯 Setting up event listeners...'); |
|
|
|
|
|
|
|
|
document.addEventListener('dayChanged', (event) => { |
|
|
this.handleDayChange(event.detail.day); |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('authStateChanged', () => { |
|
|
this.handleAuthStateChange(); |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('lessonCompleted', (event) => { |
|
|
this.handleLessonCompleted(event.detail); |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('exerciseSubmitted', (event) => { |
|
|
this.handleExerciseSubmitted(event.detail); |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('progressUpdated', () => { |
|
|
this.handleProgressUpdate(); |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('click', (e) => { |
|
|
if (e.target.matches('[data-day]')) { |
|
|
const day = parseInt(e.target.getAttribute('data-day')); |
|
|
this.handleDayChange(day); |
|
|
} |
|
|
|
|
|
if (e.target.matches('.next-day')) { |
|
|
this.nextDay(); |
|
|
} |
|
|
|
|
|
if (e.target.matches('.prev-day')) { |
|
|
this.previousDay(); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
document.addEventListener('submit', (e) => { |
|
|
if (e.target.tagName === 'FORM') { |
|
|
e.preventDefault(); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
window.addEventListener('error', (event) => { |
|
|
console.error('Global error:', event.error); |
|
|
}); |
|
|
|
|
|
window.addEventListener('unhandledrejection', (event) => { |
|
|
console.error('Unhandled promise rejection:', event.reason); |
|
|
}); |
|
|
} |
|
|
|
|
|
async loadInitialContent() { |
|
|
console.log('📚 Loading initial content...'); |
|
|
|
|
|
|
|
|
this.showLoadingState(); |
|
|
|
|
|
try { |
|
|
|
|
|
await this.loadLesson(); |
|
|
await this.loadQuiz(); |
|
|
await this.loadExercise(); |
|
|
} catch (error) { |
|
|
console.error('Error loading content:', error); |
|
|
} finally { |
|
|
|
|
|
this.hideLoadingState(); |
|
|
} |
|
|
} |
|
|
|
|
|
async loadLesson() { |
|
|
try { |
|
|
console.log(`📖 Loading lesson for day ${this.currentDay}...`); |
|
|
|
|
|
|
|
|
const lessonData = await this.simulateLessonLoad(); |
|
|
|
|
|
const lessonContent = document.getElementById('lessonContent'); |
|
|
if (lessonContent) { |
|
|
lessonContent.innerHTML = this.renderLesson(lessonData); |
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
console.error('Error loading lesson:', error); |
|
|
this.showContentError('lessonContent', 'خطا در بارگذاری درس'); |
|
|
} |
|
|
} |
|
|
|
|
|
async loadQuiz() { |
|
|
try { |
|
|
console.log(`❓ Loading quiz for day ${this.currentDay}...`); |
|
|
|
|
|
|
|
|
const quizData = await this.simulateQuizLoad(); |
|
|
|
|
|
const quizForm = document.getElementById('quizForm'); |
|
|
if (quizForm) { |
|
|
quizForm.innerHTML = this.renderQuiz(quizData); |
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
console.error('Error loading quiz:', error); |
|
|
this.showContentError('quizForm', 'خطا در بارگذاری آزمون'); |
|
|
} |
|
|
} |
|
|
|
|
|
async loadExercise() { |
|
|
try { |
|
|
console.log(`✏️ Loading exercise for day ${this.currentDay}...`); |
|
|
|
|
|
|
|
|
const exerciseData = await this.simulateExerciseLoad(); |
|
|
|
|
|
const exerciseContent = document.getElementById('exerciseContent'); |
|
|
if (exerciseContent) { |
|
|
exerciseContent.innerHTML = this.renderExercise(exerciseData); |
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
console.error('Error loading exercise:', error); |
|
|
this.showContentError('exerciseContent', 'خطا در بارگذاری تمرین'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
simulateLessonLoad() { |
|
|
return new Promise((resolve) => { |
|
|
setTimeout(() => { |
|
|
resolve({ |
|
|
title: `درس روز ${this.currentDay}: مقدمات توسعه وب`, |
|
|
content: `این محتوای آموزشی برای روز ${this.currentDay} است. در این درس با مفاهیم پایه توسعه وب آشنا میشوید.`, |
|
|
points: 10 |
|
|
}); |
|
|
}, 500); |
|
|
}); |
|
|
} |
|
|
|
|
|
simulateQuizLoad() { |
|
|
return new Promise((resolve) => { |
|
|
setTimeout(() => { |
|
|
resolve({ |
|
|
question: `سوال روز ${this.currentDay}: HTML چیست؟`, |
|
|
options: [ |
|
|
'زبان برنامهنویسی', |
|
|
'زبان نشانهگذاری', |
|
|
'پایگاه داده', |
|
|
'فریمورک CSS' |
|
|
], |
|
|
correctAnswer: 1 |
|
|
}); |
|
|
}, 500); |
|
|
}); |
|
|
} |
|
|
|
|
|
simulateExerciseLoad() { |
|
|
return new Promise((resolve) => { |
|
|
setTimeout(() => { |
|
|
resolve({ |
|
|
title: `تمرین روز ${this.currentDay}`, |
|
|
description: 'یک صفحه HTML ساده ایجاد کنید.', |
|
|
keywords: ['html', 'body', 'title'], |
|
|
points: 15 |
|
|
}); |
|
|
}, 500); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
renderLesson(data) { |
|
|
return ` |
|
|
<div class="lesson-container"> |
|
|
<h2>${data.title}</h2> |
|
|
<div class="lesson-content"> |
|
|
<p>${data.content}</p> |
|
|
</div> |
|
|
<div class="lesson-meta"> |
|
|
<span class="points">🏆 ${data.points} امتیاز</span> |
|
|
</div> |
|
|
<button class="btn btn-primary complete-lesson" onclick="app.completeLesson(${this.currentDay})"> |
|
|
تکمیل درس |
|
|
</button> |
|
|
</div> |
|
|
`; |
|
|
} |
|
|
|
|
|
renderQuiz(data) { |
|
|
return ` |
|
|
<div class="quiz-container"> |
|
|
<h3>آزمون کوتاه</h3> |
|
|
<p>${data.question}</p> |
|
|
<form id="quizFormElement"> |
|
|
${data.options.map((option, index) => ` |
|
|
<div class="quiz-option"> |
|
|
<input type="radio" id="option${index}" name="quiz" value="${index}"> |
|
|
<label for="option${index}">${option}</label> |
|
|
</div> |
|
|
`).join('')} |
|
|
<button type="submit" class="btn btn-primary">ارسال پاسخ</button> |
|
|
</form> |
|
|
</div> |
|
|
`; |
|
|
} |
|
|
|
|
|
renderExercise(data) { |
|
|
return ` |
|
|
<div class="exercise-container"> |
|
|
<h3>${data.title}</h3> |
|
|
<p>${data.description}</p> |
|
|
<form id="exerciseFormElement"> |
|
|
<div class="form-group"> |
|
|
<label for="exerciseAnswer">پاسخ خود را وارد کنید:</label> |
|
|
<textarea id="exerciseAnswer" rows="4" placeholder="کد یا پاسخ خود را اینجا بنویسید..."></textarea> |
|
|
</div> |
|
|
<button type="submit" class="btn btn-primary">ارسال تمرین</button> |
|
|
</form> |
|
|
<div class="exercise-info"> |
|
|
<small>کلیدواژههای مهم: ${data.keywords.join(', ')}</small> |
|
|
<br> |
|
|
<small>🏅 ${data.points} امتیاز</small> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
} |
|
|
|
|
|
async handleDayChange(newDay) { |
|
|
if (newDay < 1 || newDay > this.maxDays) { |
|
|
console.warn('Invalid day number:', newDay); |
|
|
return; |
|
|
} |
|
|
|
|
|
console.log(`📅 Changing to day ${newDay}`); |
|
|
this.currentDay = newDay; |
|
|
|
|
|
|
|
|
this.showLoadingState(); |
|
|
|
|
|
try { |
|
|
|
|
|
await this.loadLesson(); |
|
|
await this.loadQuiz(); |
|
|
await this.loadExercise(); |
|
|
|
|
|
|
|
|
this.updateNavigation(); |
|
|
|
|
|
|
|
|
window.scrollTo({ top: 0, behavior: 'smooth' }); |
|
|
|
|
|
} catch (error) { |
|
|
console.error('Error changing day:', error); |
|
|
} finally { |
|
|
|
|
|
this.hideLoadingState(); |
|
|
} |
|
|
} |
|
|
|
|
|
handleAuthStateChange() { |
|
|
console.log('🔄 Auth state changed'); |
|
|
this.updateAuthDisplay(); |
|
|
this.updateProgressDisplay(); |
|
|
} |
|
|
|
|
|
handleLessonCompleted(detail) { |
|
|
console.log('📚 Lesson completed:', detail); |
|
|
|
|
|
|
|
|
if (authManager.isAuthenticated()) { |
|
|
const user = authManager.getCurrentUser(); |
|
|
userManager.updateUserProgress(detail.points || 10, this.currentDay); |
|
|
} |
|
|
|
|
|
this.updateProgressDisplay(); |
|
|
this.showMessage('🎉 درس تکمیل شد! امتیاز شما به روز شد.', 'success'); |
|
|
} |
|
|
|
|
|
handleExerciseSubmitted(detail) { |
|
|
console.log('✏️ Exercise submitted:', detail); |
|
|
this.updateProgressDisplay(); |
|
|
this.showMessage('✅ تمرین ارسال شد!', 'success'); |
|
|
} |
|
|
|
|
|
handleProgressUpdate() { |
|
|
this.updateProgressDisplay(); |
|
|
} |
|
|
|
|
|
updateUI() { |
|
|
this.updateAuthDisplay(); |
|
|
this.updateProgressDisplay(); |
|
|
this.updateNavigation(); |
|
|
} |
|
|
|
|
|
updateAuthDisplay() { |
|
|
const authSection = document.getElementById('authSection'); |
|
|
if (!authSection) return; |
|
|
|
|
|
const user = authManager.getCurrentUser(); |
|
|
|
|
|
if (user) { |
|
|
authSection.innerHTML = ` |
|
|
<div class="user-welcome"> |
|
|
<div class="user-info"> |
|
|
<span class="welcome-text">خوش آمدید, ${user.profile.fullName || user.username}!</span> |
|
|
<span class="user-role">${this.getRoleText(user.role)}</span> |
|
|
</div> |
|
|
<button onclick="app.logout()" class="btn btn-outline">خروج</button> |
|
|
</div> |
|
|
`; |
|
|
} else { |
|
|
authSection.innerHTML = ` |
|
|
<div class="auth-actions"> |
|
|
<p>برای ذخیره پیشرفت وارد شوید</p> |
|
|
<div class="auth-buttons"> |
|
|
<button onclick="app.showLogin()" class="btn btn-primary">ورود</button> |
|
|
<button onclick="app.showRegister()" class="btn btn-secondary">ثبت نام</button> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
} |
|
|
} |
|
|
|
|
|
updateProgressDisplay() { |
|
|
const progressContent = document.getElementById('progressContent'); |
|
|
if (!progressContent) return; |
|
|
|
|
|
const user = authManager.getCurrentUser(); |
|
|
|
|
|
if (user) { |
|
|
const progress = user.progress || { totalScore: 0, completedLessons: [] }; |
|
|
const completedCount = progress.completedLessons?.length || 0; |
|
|
|
|
|
progressContent.innerHTML = ` |
|
|
<div class="progress-stats"> |
|
|
<div class="stat-card"> |
|
|
<div class="stat-value">${Math.floor(completedCount / 3 * 100)}%</div> |
|
|
<div class="stat-label">پیشرفت کل</div> |
|
|
</div> |
|
|
<div class="stat-card"> |
|
|
<div class="stat-value">${progress.totalScore || 0}</div> |
|
|
<div class="stat-label">امتیاز کل</div> |
|
|
</div> |
|
|
<div class="stat-card"> |
|
|
<div class="stat-value">${completedCount}</div> |
|
|
<div class="stat-label">درس تکمیل شده</div> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
} else { |
|
|
progressContent.innerHTML = ` |
|
|
<div class="guest-progress"> |
|
|
<p>👋 برای مشاهده پیشرفت خود وارد شوید</p> |
|
|
</div> |
|
|
`; |
|
|
} |
|
|
} |
|
|
|
|
|
updateNavigation() { |
|
|
const navigation = document.getElementById('dayNavigation'); |
|
|
if (navigation) { |
|
|
navigation.innerHTML = this.createDayNavigation(); |
|
|
} |
|
|
} |
|
|
|
|
|
createDayNavigation() { |
|
|
let navigationHTML = '<div class="day-navigation">'; |
|
|
|
|
|
for (let day = 1; day <= this.maxDays; day++) { |
|
|
const isActive = day === this.currentDay; |
|
|
navigationHTML += ` |
|
|
<button class="day-btn ${isActive ? 'active' : ''}" data-day="${day}"> |
|
|
روز ${day} |
|
|
</button> |
|
|
`; |
|
|
} |
|
|
|
|
|
navigationHTML += '</div>'; |
|
|
return navigationHTML; |
|
|
} |
|
|
|
|
|
getRoleText(role) { |
|
|
const roles = { |
|
|
'student': 'دانشجو', |
|
|
'instructor': 'مربی', |
|
|
'admin': 'مدیر' |
|
|
}; |
|
|
return roles[role] || role; |
|
|
} |
|
|
|
|
|
showLoadingState() { |
|
|
const sections = ['lessonContent', 'quizForm', 'exerciseContent']; |
|
|
sections.forEach(sectionId => { |
|
|
const element = document.getElementById(sectionId); |
|
|
if (element) { |
|
|
element.style.opacity = '0.6'; |
|
|
element.style.pointerEvents = 'none'; |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
hideLoadingState() { |
|
|
const sections = ['lessonContent', 'quizForm', 'exerciseContent']; |
|
|
sections.forEach(sectionId => { |
|
|
const element = document.getElementById(sectionId); |
|
|
if (element) { |
|
|
element.style.opacity = '1'; |
|
|
element.style.pointerEvents = 'auto'; |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
showContentError(elementId, message) { |
|
|
const element = document.getElementById(elementId); |
|
|
if (element) { |
|
|
element.innerHTML = ` |
|
|
<div class="error-state"> |
|
|
<div class="error-message">${message}</div> |
|
|
<button onclick="app.retryLoading()" class="btn btn-outline"> |
|
|
تلاش مجدد |
|
|
</button> |
|
|
</div> |
|
|
`; |
|
|
} |
|
|
} |
|
|
|
|
|
showMessage(message, type = 'info') { |
|
|
|
|
|
const notification = document.createElement('div'); |
|
|
notification.className = `notification ${type}`; |
|
|
notification.innerHTML = ` |
|
|
<div class="notification-content"> |
|
|
<span>${message}</span> |
|
|
<button onclick="this.parentElement.parentElement.remove()">×</button> |
|
|
</div> |
|
|
`; |
|
|
|
|
|
document.body.appendChild(notification); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
if (notification.parentElement) { |
|
|
notification.remove(); |
|
|
} |
|
|
}, 5000); |
|
|
} |
|
|
|
|
|
|
|
|
showLogin() { |
|
|
window.location.href = 'login.html'; |
|
|
} |
|
|
|
|
|
showRegister() { |
|
|
window.location.href = 'register.html'; |
|
|
} |
|
|
|
|
|
logout() { |
|
|
authManager.logout(); |
|
|
this.handleAuthStateChange(); |
|
|
this.showMessage('با موفقیت از سیستم خارج شدید.', 'info'); |
|
|
} |
|
|
|
|
|
nextDay() { |
|
|
if (this.currentDay < this.maxDays) { |
|
|
this.handleDayChange(this.currentDay + 1); |
|
|
} |
|
|
} |
|
|
|
|
|
previousDay() { |
|
|
if (this.currentDay > 1) { |
|
|
this.handleDayChange(this.currentDay - 1); |
|
|
} |
|
|
} |
|
|
|
|
|
completeLesson(day) { |
|
|
document.dispatchEvent(new CustomEvent('lessonCompleted', { |
|
|
detail: { day: day, points: 10 } |
|
|
})); |
|
|
} |
|
|
|
|
|
async retryLoading() { |
|
|
await this.loadInitialContent(); |
|
|
} |
|
|
|
|
|
showError(message) { |
|
|
this.showMessage(message, 'error'); |
|
|
} |
|
|
|
|
|
showSuccess(message) { |
|
|
this.showMessage(message, 'success'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const app = new LearningPlatform(); |
|
|
|
|
|
|
|
|
window.app = app; |
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
app.initialize(); |
|
|
}); |