${badgesHtml}
`;
container.appendChild(studentDiv);
});
}
function getBadgeName(icon) {
const badge = state.badges.find(b => b.icon === icon);
return badge ? badge.name : '';
}
function renderStudentList() {
const list = document.getElementById('studentList');
list.innerHTML = '';
state.students.forEach(student => {
const li = document.createElement('li');
li.className = 'flex justify-between items-center p-2 bg-gray-50 rounded-md';
li.innerHTML = `
${student.name}
`;
list.appendChild(li);
});
}
function renderBadgeList() {
const list = document.getElementById('badgeList');
list.innerHTML = '';
state.badges.forEach((badge, index) => {
const li = document.createElement('li');
li.className = 'flex justify-between items-center p-2 bg-gray-50 rounded-md';
li.innerHTML = `
${badge.name} (${badge.points} pts)
`;
list.appendChild(li);
});
}
function renderSelectors() {
const studentSelector = document.getElementById('studentSelector');
const activitySelector = document.getElementById('activitySelector');
studentSelector.innerHTML = state.students.map(s => ``).join('');
activitySelector.innerHTML = state.activities.map(a => ``).join('');
}
// --- Event Handlers ---
function bindEventListeners() {
tabContainer.addEventListener('click', handleTabClick);
addStudentBtn.addEventListener('click', handleAddStudent);
addBadgeBtn.addEventListener('click', handleAddBadge);
awardPointsBtn.addEventListener('click', handleAwardPoints);
downloadPdfBtn.addEventListener('click', downloadPDF);
document.getElementById('studentList').addEventListener('click', (e) => {
if (e.target.closest('.delete-student-btn')) {
const studentId = e.target.closest('.delete-student-btn').dataset.id;
handleDeleteStudent(parseInt(studentId));
}
});
document.getElementById('badgeList').addEventListener('click', (e) => {
if (e.target.closest('.delete-badge-btn')) {
const index = e.target.closest('.delete-badge-btn').dataset.index;
handleDeleteBadge(parseInt(index));
}
});
}
function handleTabClick(e) {
if (!e.target.matches('.tab-button')) return;
document.querySelectorAll('.tab-button').forEach(btn => btn.classList.remove('active'));
e.target.classList.add('active');
document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
document.getElementById(`${e.target.dataset.tab}Content`).classList.add('active');
}
function handleAddStudent() {
const input = document.getElementById('newStudentName');
const name = input.value.trim();
if (name) {
state.students.push({ id: Date.now(), name, points: 0, badges: [] });
input.value = '';
saveState();
renderAll();
}
}
function handleDeleteStudent(id) {
state.students = state.students.filter(s => s.id !== id);
saveState();
renderAll();
}
function handleAddBadge() {
const nameInput = document.getElementById('newBadgeName');
const pointsInput = document.getElementById('newBadgePoints');
const iconInput = document.getElementById('newBadgeIcon');
const name = nameInput.value.trim();
const points = parseInt(pointsInput.value);
const icon = iconInput.value;
if (name && points > 0) {
state.badges.push({ name, points, icon });
nameInput.value = '';
pointsInput.value = '';
saveState();
renderAll();
}
}
function handleDeleteBadge(index) {
state.badges.splice(index, 1);
saveState();
renderAll();
}
function handleAwardPoints() {
const studentId = parseInt(document.getElementById('studentSelector').value);
const points = parseInt(document.getElementById('activitySelector').value);
const student = state.students.find(s => s.id === studentId);
if (student) {
student.points += points;
// Check for new badges
state.badges.forEach(badge => {
if (student.points >= badge.points && !student.badges.includes(badge.icon)) {
student.badges.push(badge.icon);
}
});
saveState();
renderLeaderboard();
alert(`Awarded ${points} points to ${student.name}!`);
}
}
// --- PDF Generation ---
function downloadPDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
const sortedStudents = [...state.students].sort((a, b) => b.points - a.points);
doc.setFont('helvetica', 'bold');
doc.setFontSize(18);
doc.text('Classroom Leaderboard Report', 14, 22);
const tableBody = sortedStudents.map((student, index) => {
const badgeNames = student.badges.map(icon => getBadgeName(icon)).join(', ');
return [index + 1, student.name, student.points, badgeNames || 'None'];
});
doc.autoTable({
startY: 30,
head: [['Rank', 'Student Name', 'Points', 'Badges Earned']],
body: tableBody,
headStyles: { fillColor: [37, 99, 235] }
});
doc.save('Classroom_Report.pdf');
}
// --- Run on Load ---
initialize();
});
