Add, edit, or remove your medication details below. All changes will automatically update the dashboard.
Medication Name
Dosage
Frequency
Start Date
End Date
Notes
Actions
${totalMedications}
Active Medications
${activeMedications}
Upcoming Medications
${upcomingMedications}
Completed Medications
${completedMedications}
`;
}
/**
* Renders the current medications table in the Dashboard tab.
*/
function renderCurrentMedications() {
// Null check for the current medications table body
if (!currentMedicationsTableBody) {
console.error("Current medications table body not found.");
return;
}
currentMedicationsTableBody.innerHTML = ''; // Clear existing rows
medicationData.forEach(med => {
const status = getMedicationStatus(med.startDate, med.endDate);
const row = document.createElement('tr');
row.innerHTML = `
${med.medicationName}
${med.dosage}
${med.frequency}
${med.startDate || 'N/A'}
${med.endDate || 'N/A'}
${status}
${med.notes || 'N/A'}
`;
currentMedicationsTableBody.appendChild(row);
});
}
/**
* Renders the data input table in the Medication Management tab.
*/
function renderMedicationInputTable() {
// Null check for the medication input table body
if (!medicationInputTableBody) {
console.error("Medication input table body not found.");
return;
}
medicationInputTableBody.innerHTML = ''; // Clear existing rows
medicationData.forEach(med => {
const row = document.createElement('tr');
row.innerHTML = `
`;
medicationInputTableBody.appendChild(row);
});
// Attach event listeners to newly created input fields and delete buttons
document.querySelectorAll('.medication-input').forEach(input => {
input.addEventListener('change', handleInputChange);
});
document.querySelectorAll('.delete-row-btn').forEach(button => {
button.addEventListener('click', handleDeleteRow);
});
}
/**
* Updates all dashboard and management views.
*/
function updateViews() {
renderMedicationSummary();
renderCurrentMedications();
renderMedicationInputTable();
}
// --- Event Handlers ---
/**
* Handles tab button clicks to switch between tabs.
* @param {Event} event - The click event.
*/
function handleTabClick(event) {
// Null check for event target
if (!event.target) {
console.error("Event target is null.");
return;
}
const targetTab = event.target.dataset.tab;
// Remove 'active' class from all tab buttons and content
tabButtons.forEach(button => button.classList.remove('active'));
tabContents.forEach(content => content.classList.remove('active'));
// Add 'active' class to the clicked tab button and corresponding content
event.target.classList.add('active');
const activeTabContent = document.getElementById(`${targetTab}-tab`);
if (activeTabContent) { // Null check for activeTabContent
activeTabContent.classList.add('active');
} else {
console.error(`Tab content for ${targetTab} not found.`);
}
updateViews(); // Update views whenever tab changes
}
/**
* Handles changes in data input fields.
* @param {Event} event - The change event.
*/
function handleInputChange(event) {
// Null check for event target
if (!event.target) {
console.error("Event target is null.");
return;
}
const input = event.target;
const id = parseInt(input.dataset.id);
const field = input.dataset.field;
let value = input.value;
const medicationIndex = medicationData.findIndex(d => d.id === id);
if (medicationIndex !== -1) {
medicationData[medicationIndex][field] = value;
updateViews(); // Re-render tables
} else {
console.error(`Medication with ID ${id} not found.`);
}
}
/**
* Adds a new empty row to the medication input table.
*/
function handleAddMedication() {
const newMedication = {
id: nextId++,
medicationName: 'New Medication',
dosage: '',
frequency: 'Once Daily',
startDate: '',
endDate: '',
notes: ''
};
medicationData.push(newMedication);
updateViews(); // Re-render data input table
}
/**
* Deletes a row from the medication input table.
* @param {Event} event - The click event.
*/
function handleDeleteRow(event) {
// Null check for event target
if (!event.target) {
console.error("Event target is null.");
return;
}
const idToDelete = parseInt(event.target.dataset.id);
medicationData = medicationData.filter(d => d.id !== idToDelete);
updateViews(); // Re-render data input table
}
/**
* Handles navigation to the previous tab.
*/
function handlePrevTab() {
const currentActiveTab = document.querySelector('.tab-button.active');
if (!currentActiveTab) {
console.error("No active tab found.");
return;
}
const currentIndex = Array.from(tabButtons).indexOf(currentActiveTab);
if (currentIndex > 0) {
tabButtons[currentIndex - 1].click(); // Simulate click on previous tab
}
}
/**
* Handles navigation to the next tab.
*/
function handleNextTab() {
const currentActiveTab = document.querySelector('.tab-button.active');
if (!currentActiveTab) {
console.error("No active tab found.");
return;
}
const currentIndex = Array.from(tabButtons).indexOf(currentActiveTab);
if (currentIndex < tabButtons.length - 1) {
tabButtons[currentIndex + 1].click(); // Simulate click on next tab
}
}
/**
* Handles the PDF download functionality.
* It uses html2canvas to capture the dashboard content and jsPDF to generate the PDF.
*/
async function handleDownloadPdf() {
const dashboardContent = document.querySelector('.dashboard-content-for-pdf');
if (!dashboardContent) {
console.error("Dashboard content for PDF not found.");
return;
}
// Add a temporary title for the PDF
const tempTitle = document.createElement('h1');
tempTitle.textContent = "Medication Dashboard";
tempTitle.style.textAlign = 'center';
tempTitle.style.marginBottom = '20px';
tempTitle.style.fontSize = '2em';
tempTitle.style.fontWeight = 'bold';
tempTitle.style.color = '#333';
dashboardContent.prepend(tempTitle); // Prepend to capture
// Temporarily hide tab navigation and buttons for PDF capture
const elementsToHide = document.querySelectorAll('.tab-nav, .tab-navigation-buttons, .add-row-btn, .delete-row-btn, .pdf-download-section .btn-primary');
elementsToHide.forEach(el => el.style.display = 'none');
// Ensure the dashboard tab is active before capturing for PDF
const dashboardTabButton = document.querySelector('.tab-button[data-tab="dashboard"]');
if (dashboardTabButton && !dashboardTabButton.classList.contains('active')) {
dashboardTabButton.click(); // Activate dashboard tab if not already active
// A small delay might be needed here if content takes time to render after tab switch
await new Promise(resolve => setTimeout(resolve, 100));
}
try {
const canvas = await html2canvas(dashboardContent, {
scale: 2, // Increase scale for better resolution
useCORS: true, // Required if images are from different origin (though we don't use external images)
windowWidth: dashboardContent.scrollWidth,
windowHeight: dashboardContent.scrollHeight
});
const imgData = canvas.toDataURL('image/png');
const { jsPDF } = window.jspdf;
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'px',
format: 'a4'
});
const imgWidth = pdf.internal.pageSize.getWidth();
const pageHeight = pdf.internal.pageSize.getHeight();
const imgHeight = canvas.height * imgWidth / canvas.width;
let heightLeft = imgHeight;
let position = 0;
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
heightLeft -= pageHeight;
while (heightLeft >= 0) {
position = heightLeft - imgHeight;
pdf.addPage();
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
heightLeft -= pageHeight;
}
pdf.save('medication_dashboard.pdf');
} catch (error) {
console.error("Error generating PDF:", error);
// Using alert as a fallback for critical error feedback, as per standard specification
alert("Failed to generate PDF. Please try again.");
} finally {
// Restore hidden elements and remove temporary title
elementsToHide.forEach(el => el.style.display = '');
if (tempTitle.parentNode) {
tempTitle.parentNode.removeChild(tempTitle);
}
}
}
// --- Event Listener Attachments ---
tabButtons.forEach(button => {
// Null check for button
if (button) {
button.addEventListener('click', handleTabClick);
}
});
// Null checks before attaching listeners
if (addMedicationBtn) {
addMedicationBtn.addEventListener('click', handleAddMedication);
} else {
console.error("Add Medication button not found.");
}
if (downloadPdfBtn) {
downloadPdfBtn.addEventListener('click', handleDownloadPdf);
} else {
console.error("Download PDF button not found.");
}
if (prevTabBtn) {
prevTabBtn.addEventListener('click', handlePrevTab);
} else {
console.error("Previous Tab button not found.");
}
if (nextTabBtn) {
nextTabBtn.addEventListener('click', handleNextTab);
} else {
console.error("Next Tab button not found.");
}
// Initial render of the dashboard and data input table
updateViews();
});