Role-Specific Task Games

Role-Specific Task Games

Your Progress

0 / 0 Points

Manage Roles

Existing Roles

Manage Tasks

Existing Tasks

No tasks found for this role. Add tasks in the Data Configuration tab.

'; return; } tasks.forEach(task => { const isCompleted = task.status === 'completed'; const itemClass = isCompleted ? 'rstg-task-item rstg-completed' : 'rstg-task-item'; const buttonClass = isCompleted ? 'rstg-btn-secondary' : 'rstg-btn-success'; const buttonText = isCompleted ? 'Mark Pending' : 'Mark Complete'; const taskHTML = `

${task.desc}

Points: ${task.points} Priority: ${task.priority}
`; rstg_taskList.innerHTML += taskHTML; }); } // Calculates and displays the score function rstg_renderScore(roleId) { if (!rstg_scoreText || !rstg_scoreBar) return; const tasks = rstg_data.tasks.filter(task => task.roleId == roleId); const totalPoints = tasks.reduce((sum, task) => sum + task.points, 0); const achievedPoints = tasks .filter(task => task.status === 'completed') .reduce((sum, task) => sum + task.points, 0); const percentage = totalPoints > 0 ? (achievedPoints / totalPoints) * 100 : 0; rstg_scoreText.textContent = `${achievedPoints} / ${totalPoints} Points`; rstg_scoreBar.style.width = `${percentage}%`; rstg_scoreBar.textContent = percentage > 10 ? `${Math.round(percentage)}%` : ''; } // Handles role selection change window.rstg_handleRoleChange = function() { if (!rstg_roleSelect) return; const selectedRoleId = rstg_roleSelect.value; rstg_renderTaskList(selectedRoleId); rstg_renderScore(selectedRoleId); } // Toggles task status window.rstg_toggleTaskStatus = function(taskId) { const task = rstg_data.tasks.find(t => t.id === taskId); if (task) { task.status = (task.status === 'pending') ? 'completed' : 'pending'; // Re-render dashboard rstg_handleRoleChange(); } } // --- CONFIGURATION FUNCTIONS --- function rstg_renderConfigUI() { if (!rstg_roleList || !rstg_allTasksList) return; // Render roles list rstg_roleList.innerHTML = ''; if (rstg_data.roles.length === 0) { rstg_roleList.innerHTML = '

No roles defined.

'; } rstg_data.roles.forEach(role => { rstg_roleList.innerHTML += `
${role.name}
`; }); // Render tasks list rstg_allTasksList.innerHTML = ''; if (rstg_data.tasks.length === 0) { rstg_allTasksList.innerHTML = '

No tasks defined.

'; } rstg_data.tasks.forEach(task => { const role = rstg_data.roles.find(r => r.id === task.roleId); const roleName = role ? role.name : 'Unknown Role'; rstg_allTasksList.innerHTML += `
${task.desc} (${roleName})
Priority: ${task.priority}, Points: ${task.points}
`; }); } window.rstg_addRole = function(event) { event.preventDefault(); if (!rstg_newRoleName) return; const name = rstg_newRoleName.value.trim(); if (name) { const newId = rstg_data.roles.length > 0 ? Math.max(...rstg_data.roles.map(r => r.id)) + 1 : 1; rstg_data.roles.push({ id: newId, name: name }); rstg_newRoleName.value = ''; rstg_renderAllRoles(); rstg_renderConfigUI(); } } window.rstg_deleteRole = function(roleId) { // Confirmation before deleting if (!confirm(`Are you sure you want to delete this role? All associated tasks (${rstg_data.tasks.filter(t => t.roleId === roleId).length}) will also be deleted.`)) { return; } rstg_data.roles = rstg_data.roles.filter(r => r.id !== roleId); // Also delete associated tasks rstg_data.tasks = rstg_data.tasks.filter(t => t.roleId !== roleId); rstg_renderAllRoles(); rstg_renderConfigUI(); rstg_handleRoleChange(); // Update dashboard } window.rstg_addTask = function(event) { event.preventDefault(); if (!rstg_taskRoleSelect || !rstg_newTaskDesc || !rstg_newTaskPriority || !rstg_newTaskPoints) return; const roleId = parseInt(rstg_taskRoleSelect.value); const desc = rstg_newTaskDesc.value.trim(); const priority = rstg_newTaskPriority.value; const points = parseInt(rstg_newTaskPoints.value); if (roleId && desc && priority && points > 0) { const newId = rstg_data.tasks.length > 0 ? Math.max(...rstg_data.tasks.map(t => t.id)) + 1 : 101; rstg_data.tasks.push({ id: newId, roleId, desc, priority, points, status: 'pending' }); // Reset form rstg_newTaskDesc.value = ''; rstg_newTaskPoints.value = '10'; rstg_newTaskPriority.value = 'Medium'; rstg_renderConfigUI(); rstg_handleRoleChange(); // Update dashboard } } window.rstg_deleteTask = function(taskId) { rstg_data.tasks = rstg_data.tasks.filter(t => t.id !== taskId); rstg_renderConfigUI(); rstg_handleRoleChange(); // Update dashboard } // --- TAB & NAVIGATION FUNCTIONS --- window.rstg_switchTab = function(tabName) { rstg_currentTab = tabName; rstg_tabContents.forEach(content => { content.classList.remove('rstg-active'); }); rstg_tabs.forEach(tab => { tab.classList.remove('rstg-active'); }); const activeContent = document.getElementById(`rstg-${tabName}-tab`); const activeTab = document.querySelector(`.rstg-tab-button[onclick="rstg_switchTab('${tabName}')"]`); if (activeContent) activeContent.classList.add('rstg-active'); if (activeTab) activeTab.classList.add('rstg-active'); rstg_updateNavButtons(); } window.rstg_navigateTabs = function(direction) { const tabNames = ['dashboard', 'config']; const currentIndex = tabNames.indexOf(rstg_currentTab); if (direction === 'next' && currentIndex < tabNames.length - 1) { rstg_switchTab(tabNames[currentIndex + 1]); } else if (direction === 'prev' && currentIndex > 0) { rstg_switchTab(tabNames[currentIndex - 1]); } } function rstg_updateNavButtons() { if (!rstg_prevBtn || !rstg_nextBtn) return; if (rstg_currentTab === 'dashboard') { rstg_prevBtn.style.visibility = 'hidden'; rstg_nextBtn.style.visibility = 'visible'; } else if (rstg_currentTab === 'config') { rstg_prevBtn.style.visibility = 'visible'; rstg_nextBtn.style.visibility = 'hidden'; } } // --- PDF GENERATION --- window.rstg_generatePdf = function() { // Check if jsPDF and autoTable are loaded if (typeof jspdf === 'undefined' || typeof jspdf.jsPDF === 'undefined') { alert('Error: PDF generation library (jsPDF) not loaded.'); return; } if (typeof window.jspdf.plugin.autotable === 'undefined') { alert('Error: PDF generation library (jsPDF-AutoTable) not loaded.'); return; } try { const { jsPDF } = jspdf; const doc = new jsPDF(); const selectedRoleId = rstg_roleSelect ? rstg_roleSelect.value : null; const selectedRole = rstg_data.roles.find(r => r.id == selectedRoleId); if (!selectedRole) { alert('Please select a role first.'); return; } // Get data for PDF const tasks = rstg_data.tasks.filter(task => task.roleId == selectedRoleId); const totalPoints = tasks.reduce((sum, task) => sum + task.points, 0); const achievedPoints = tasks .filter(task => task.status === 'completed') .reduce((sum, task) => sum + task.points, 0); // --- PDF Content --- doc.setFont('helvetica', 'bold'); doc.setFontSize(20); doc.setTextColor(40); doc.text("Role-Specific Task Progress Report", 105, 20, { align: 'center' }); doc.setFont('helvetica', 'normal'); doc.setFontSize(16); doc.text(`Role: ${selectedRole.name}`, 14, 35); doc.setFontSize(14); doc.text(`Total Progress: ${achievedPoints} / ${totalPoints} Points`, 14, 45); // PDF Table const tableColumn = ["Task Description", "Priority", "Points", "Status"]; const tableRows = []; tasks.forEach(task => { const taskData = [ task.desc, task.priority, task.points, task.status.charAt(0).toUpperCase() + task.status.slice(1) // Capitalize status ]; tableRows.push(taskData); }); // Auto-generate table doc.autoTable({ head: [tableColumn], body: tableRows, startY: 55, theme: 'striped', // 'striped', 'grid', 'plain' headStyles: { fillColor: [0, 115, 230], // --rstg-primary-color textColor: [255, 255, 255] // --rstg-text-light }, styles: { font: 'helvetica', cellPadding: 3, }, alternateRowStyles: { fillColor: [240, 240, 240] // --rstg-secondary-color }, // Apply conditional styling for 'Completed' status didDrawCell: (data) => { if (data.column.index === 3 && data.cell.section === 'body') { if(data.cell.text[0] === 'Completed') { doc.setFont('helvetica', 'bold'); doc.setTextColor(40, 167, 69); // --rstg-success-color } else if (data.cell.text[0] === 'Pending') { doc.setFont('helvetica', 'normal'); doc.setTextColor(255, 193, 7); // --rstg-pending-color } } // Reset text color for other cells doc.setTextColor(51, 51, 51); // --rstg-text-color } }); // --- PDF Download --- // Generate a filename const safeRoleName = selectedRole.name.replace(/[^a-z0-9]/gi, '_').toLowerCase(); const fileName = `task_report_${safeRoleName}.pdf`; doc.save(fileName); } catch (e) { console.error("PDF Generation Error: ", e); alert("An error occurred while generating the PDF."); } } // --- RUN INITIALIZATION --- rstg_initTool(); }); // End of DOMContentLoaded