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