Charity Donation Planner
Donation Summary
Total Goal
$0.00
Total Donated
$0.00
Remaining
$0.00
Editable Donation Plan
Charity Name
Goal
Donated
Go to the "Data Configuration" tab to add charities and generate your plan.
1. Add Charity to Plan
Current Charities
2. Log a Donation
No charities added. Go to the Configuration tab to add some.
$
$
`;
dashboardList.appendChild(itemEl);
}
/**
* Handles clicks on dashboard list (for remove)
*/
function handleDashboardClick(e) {
if (e.target.dataset.action === "remove") {
const itemEl = e.target.closest(".cdp-dash-item");
if (itemEl) {
// Remove from dashboard
itemEl.remove();
// Remove from master array
charities = charities.filter(c => c.id !== itemEl.dataset.id);
// Update config tab lists
updateConfigLists();
// Update dashboard totals
recalculateTotals();
}
}
}
/**
* Calculates and displays totals from the *dashboard's editable fields*
*/
function recalculateTotals() {
let totalGoal = 0;
let totalDonated = 0;
const goalInputs = dashboardList.querySelectorAll(".cdp-dash-goal");
goalInputs.forEach((input) => {
totalGoal += parseFloat(input.value) || 0;
});
const donatedInputs = dashboardList.querySelectorAll(".cdp-dash-donated");
donatedInputs.forEach((input) => {
totalDonated += parseFloat(input.value) || 0;
});
const totalRemaining = totalGoal - totalDonated;
totalGoalEl.textContent = `$${totalGoal.toFixed(2)}`;
totalDonatedEl.textContent = `$${totalDonated.toFixed(2)}`;
totalRemainingEl.textContent = `$${totalRemaining.toFixed(2)}`;
return { totalGoal, totalDonated, totalRemaining };
}
/**
* Generates a PDF report from the dashboard data
*/
function downloadPDF() {
if (
typeof window.jspdf === "undefined" ||
typeof window.jspdf.jsPDF.autoTable === "undefined"
) {
alert("Error: PDF library could not be loaded. Please try again.");
return;
}
const { jsPDF } = window.jspdf;
const doc = new jsPDF("p", "pt", "a4");
const margin = 40;
const tableHead = [["Charity", "Goal", "Donated", "Remaining"]];
const tableBody = [];
// Get data *from the dashboard*
const dashItems = dashboardList.querySelectorAll(".cdp-dash-item");
dashItems.forEach((item) => {
const name = item.querySelector(".cdp-dash-name").value;
const goal = parseFloat(item.querySelector(".cdp-dash-goal").value) || 0;
const donated = parseFloat(item.querySelector(".cdp-dash-donated").value) || 0;
const remaining = goal - donated;
tableBody.push([
name,
`$${goal.toFixed(2)}`,
`$${donated.toFixed(2)}`,
`$${remaining.toFixed(2)}`
]);
});
const totals = recalculateTotals(); // Get fresh totals
doc.setFontSize(18);
doc.text("Charity Donation Plan", margin, margin);
doc.autoTable({
startY: margin + 20,
head: tableHead,
body: tableBody,
theme: "striped",
headStyles: {
fillColor: [0, 115, 230],
textColor: [255, 255, 255],
},
columnStyles: {
1: { halign: 'right' },
2: { halign: 'right' },
3: { halign: 'right' },
},
// Add footer row for totals
didDrawPage: function (data) {
let finalY = data.table.finalY + 20;
doc.setFontSize(12);
doc.setFont(undefined, "bold");
doc.text("Total Goal:", margin, finalY);
doc.text(`$${totals.totalGoal.toFixed(2)}`, data.settings.margin.left + 150, finalY);
doc.text("Total Donated:", margin, finalY + 20);
doc.text(`$${totals.totalDonated.toFixed(2)}`, data.settings.margin.left + 150, finalY + 20);
doc.text("Total Remaining:", margin, finalY + 40);
doc.text(`$${totals.totalRemaining.toFixed(2)}`, data.settings.margin.left + 150, finalY + 40);
},
});
doc.save("Charity_Donation_Plan.pdf");
}
/**
* Helper to escape HTML
*/
function escapeHTML(str) {
if (!str) return "";
return str
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
// --- 3. INITIALIZATION & EVENT LISTENERS ---
// Tab Listeners
tabButtons.forEach((btn) => {
btn.addEventListener("click", () => showTab(btn.dataset.target));
});
navButtons.forEach((btn) => {
btn.addEventListener("click", () => showTab(btn.dataset.target));
});
// Config Tab Listeners
if (addCharityForm) {
addCharityForm.addEventListener("submit", handleAddCharity);
}
if (logDonationForm) {
logDonationForm.addEventListener("submit", handleLogDonation);
}
if (configCharityList) {
configCharityList.addEventListener("click", handleConfigListClick);
}
if (generateBtn) {
generateBtn.addEventListener("click", handleGenerateDashboard);
}
// Dashboard Tab Listeners
if (recalculateBtn) {
recalculateBtn.addEventListener("click", recalculateTotals);
}
if (pdfBtn) {
pdfBtn.addEventListener("click", downloadPDF);
}
if (dashboardList) {
dashboardList.addEventListener("click", handleDashboardClick);
}
// Initial State
logDate.valueAsDate = new Date(); // Set date to today
// Load sample data
charities = [
{ id: 'charity-1', name: 'St. Jude Children\'s Research Hospital', category: 'Health', goal: 500, donated: 50 },
{ id: 'charity-2', name: 'ASPCA', category: 'Animals', goal: 250, donated: 0 }
];
updateConfigLists();
handleGenerateDashboard();
showTab("cdp-tab-dashboard");
});
