`;
taskListContainer.insertAdjacentHTML('beforeend', item);
});
};
/**
* Updates the summary cards on the dashboard.
*/
const updateSummaryCards = () => {
const total = tasks.length;
const completed = tasks.filter(t => t.status === 'Completed').length;
const pending = tasks.filter(t => t.status === 'In Progress' || t.status === 'Not Started').length;
const overdue = tasks.filter(t => t.status === 'Overdue').length;
document.getElementById('total-tasks').textContent = total;
document.getElementById('completed-tasks').textContent = completed;
document.getElementById('pending-tasks').textContent = pending;
document.getElementById('overdue-tasks').textContent = overdue;
};
/**
* A master render function to update the entire UI based on the current state.
*/
const refreshUI = () => {
// Check for overdue tasks before rendering
const today = new Date().toISOString().split('T')[0];
tasks.forEach(task => {
if (task.dueDate < today && task.status !== 'Completed') {
task.status = 'Overdue';
}
});
renderComplianceTable();
renderTaskList();
updateSummaryCards();
};
// --- CORE LOGIC & EVENT HANDLERS ---
/**
* Handles form submission for adding or updating a task.
* @param {Event} e - The form submission event.
*/
const handleFormSubmit = (e) => {
e.preventDefault();
const id = document.getElementById('task-id').value;
const taskData = {
name: document.getElementById('task-name').value,
category: document.getElementById('task-category').value,
dueDate: document.getElementById('task-due-date').value,
responsible: document.getElementById('task-responsible').value,
status: document.getElementById('task-status').value,
};
if (id) {
// Update existing task
const index = tasks.findIndex(t => t.id == id);
if (index !== -1) {
tasks[index] = { ...tasks[index], ...taskData };
}
} else {
// Add new task
taskData.id = tasks.length > 0 ? Math.max(...tasks.map(t => t.id)) + 1 : 1;
tasks.push(taskData);
}
resetForm();
refreshUI();
};
/**
* Resets the form to its default state for adding a new task.
*/
const resetForm = () => {
taskForm.reset();
document.getElementById('task-id').value = '';
formTitle.textContent = 'Add New Compliance Task';
saveTaskBtn.textContent = 'Save Task';
cancelEditBtn.classList.add('hidden');
};
// --- GLOBAL FUNCTIONS FOR INLINE ONCLICK ---
// To adhere to the specification allowing inline onclick, functions are attached to a global object.
window.globalFuncs = {
/**
* Prepares the form for editing a specific task.
* @param {number} id - The ID of the task to edit.
*/
editTask: (id) => {
const task = tasks.find(t => t.id === id);
if (!task) return;
document.getElementById('task-id').value = task.id;
document.getElementById('task-name').value = task.name;
document.getElementById('task-category').value = task.category;
document.getElementById('task-due-date').value = task.dueDate;
document.getElementById('task-responsible').value = task.responsible;
document.getElementById('task-status').value = task.status;
formTitle.textContent = 'Edit Compliance Task';
saveTaskBtn.textContent = 'Update Task';
cancelEditBtn.classList.remove('hidden');
// Scroll to the form for better UX on small screens
formTitle.scrollIntoView({ behavior: 'smooth' });
},
/**
* Shows the delete confirmation modal.
* @param {number} id - The ID of the task to be deleted.
*/
confirmDelete: (id) => {
taskToDeleteId = id;
deleteModal.classList.add('visible');
},
/**
* Deletes the task after confirmation.
*/
deleteTask: () => {
if (taskToDeleteId !== null) {
tasks = tasks.filter(t => t.id !== taskToDeleteId);
taskToDeleteId = null;
deleteModal.classList.remove('visible');
refreshUI();
}
}
};
// --- TAB NAVIGATION LOGIC ---
/**
* Switches the visible tab content.
* @param {string} tabName - The name of the tab to switch to ('dashboard' or 'config').
*/
window.switchTab = (tabName) => {
currentTab = tabName;
// Update button styles
Object.keys(tabs).forEach(key => {
tabs[key].classList.toggle('active', key === tabName);
tabs[key].classList.toggle('inactive', key !== tabName);
});
// Show/hide content
Object.keys(contents).forEach(key => {
contents[key].classList.toggle('hidden', key !== tabName);
});
updateNavButtons();
};
/**
* Handles "Next" and "Previous" button clicks.
* @param {string} direction - 'next' or 'prev'.
*/
window.navigateTabs = (direction) => {
const tabKeys = Object.keys(tabs);
const currentIndex = tabKeys.indexOf(currentTab);
let newIndex;
if (direction === 'next' && currentIndex < tabKeys.length - 1) {
newIndex = currentIndex + 1;
} else if (direction === 'prev' && currentIndex > 0) {
newIndex = currentIndex - 1;
} else {
return; // Should not happen if buttons are disabled correctly
}
switchTab(tabKeys[newIndex]);
};
/**
* Updates the enabled/disabled state of the Next/Previous buttons.
*/
const updateNavButtons = () => {
const tabKeys = Object.keys(tabs);
const currentIndex = tabKeys.indexOf(currentTab);
navButtons.prev.disabled = currentIndex === 0;
navButtons.next.disabled = currentIndex === tabKeys.length - 1;
};
// --- PDF GENERATION ---
/**
* Generates and downloads a PDF report of the compliance dashboard.
*/
const generatePdf = () => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
// Set document title
doc.setFontSize(18);
doc.text('Corporate Governance Compliance Report', 14, 22);
doc.setFontSize(11);
doc.setTextColor(100);
const reportDate = `Report generated on: ${new Date().toLocaleDateString()}`;
doc.text(reportDate, 14, 30);
// Add summary stats
const summaryText = `Total Tasks: ${tasks.length} | Completed: ${tasks.filter(t=>t.status==='Completed').length} | Pending: ${tasks.filter(t=>t.status==='In Progress' || t.status==='Not Started').length} | Overdue: ${tasks.filter(t=>t.status==='Overdue').length}`;
doc.setFontSize(12);
doc.text(summaryText, 14, 40);
// Prepare table data
const tableColumn = ["Task / Requirement", "Category", "Due Date", "Responsible", "Status"];
const tableRows = [];
tasks.forEach(task => {
const taskData = [
task.name,
task.category,
task.dueDate,
task.responsible,
task.status,
];
tableRows.push(taskData);
});
// Add table to PDF
doc.autoTable({
head: [tableColumn],
body: tableRows,
startY: 50,
theme: 'grid',
headStyles: { fillColor: [79, 70, 229] }, // Indigo color for header
didParseCell: function (data) {
// Custom styling for status cells to match UI
if (data.column.index === 4 && data.cell.section === 'body') {
const status = data.cell.raw;
if (status === 'Completed') data.cell.styles.textColor = [22, 163, 74]; // Green
if (status === 'Overdue') data.cell.styles.textColor = [220, 38, 38]; // Red
if (status === 'In Progress') data.cell.styles.textColor = [217, 119, 6]; // Yellow
}
}
});
// Save the PDF
doc.save('Corporate_Compliance_Report.pdf');
};
// --- INITIALIZATION & EVENT LISTENERS ---
taskForm.addEventListener('submit', handleFormSubmit);
cancelEditBtn.addEventListener('click', resetForm);
downloadPdfBtn.addEventListener('click', generatePdf);
// Modal event listeners
modalCancelBtn.addEventListener('click', () => deleteModal.classList.remove('visible'));
modalConfirmBtn.addEventListener('click', window.globalFuncs.deleteTask);
deleteModal.addEventListener('click', (e) => {
if (e.target === deleteModal) {
deleteModal.classList.remove('visible');
}
});
// Initial load
tasks = [...sampleTasks];
refreshUI();
updateNavButtons();
});