Adoption Application Tracker
Use this tool to manage and track adoption applications.
All data is saved in your browser's local storage.
Add New Application
All Applications
| ID | Applicant | Pet/Child | App Date | Status | Actions |
|---|
No applications added yet.
Status Summary
${statusCounts[status]}
`; statusSummaryDiv.appendChild(card); }); } function attachTableEventListeners() { applicationTableBody.querySelectorAll('.status-update-btn').forEach(button => { button.onclick = (e) => showStatusUpdatePrompt(e.target.dataset.id); }); applicationTableBody.querySelectorAll('.delete-btn').forEach(button => { button.onclick = (e) => deleteApplication(e.target.dataset.id); }); } // --- Application Management Logic --- function addApplication() { clearError(); const applicantName = applicantNameInput.value.trim(); const petOrChild = petOrChildInput.value.trim(); const applicationDate = applicationDateInput.value; const initialStatus = initialStatusSelect.value; if (!applicantName || !applicationDate) { showError("Applicant Name and Application Date are required."); return; } const applications = getApplications(); const newId = applications.length > 0 ? Math.max(...applications.map(app => app.id)) + 1 : 1; const newApplication = { id: newId, applicantName, petOrChild: petOrChild || '', applicationDate, status: initialStatus, history: [{ date: new Date().toISOString().split('T')[0], status: initialStatus }] // Track initial status }; applications.push(newApplication); saveApplications(applications); renderApplicationsTable(); renderStatusSummary(); // Clear form applicantNameInput.value = ''; petOrChildInput.value = ''; applicationDateInput.value = ''; // Or set to today's date new Date().toISOString().split('T')[0]; initialStatusSelect.value = 'Submitted'; } function showStatusUpdatePrompt(id) { const applications = getApplications(); const appIndex = applications.findIndex(app => app.id == id); if (appIndex === -1) return; const currentApp = applications[appIndex]; const newStatus = prompt(`Update status for ${currentApp.applicantName} (ID: ${currentApp.id})\nCurrent Status: ${currentApp.status}\n\nEnter new status from: ${STATUSES.join(', ')}`); if (newStatus === null) return; // User cancelled const trimmedStatus = newStatus.trim(); if (!STATUSES.includes(trimmedStatus)) { alert("Invalid status. Please choose from: " + STATUSES.join(', ')); return; } if (currentApp.status !== trimmedStatus) { currentApp.status = trimmedStatus; currentApp.history.push({ date: new Date().toISOString().split('T')[0], status: trimmedStatus }); saveApplications(applications); renderApplicationsTable(); renderStatusSummary(); } } function deleteApplication(id) { if (!confirm(`Are you sure you want to delete application ID ${id}? This action cannot be undone.`)) { return; } let applications = getApplications(); applications = applications.filter(app => app.id != id); saveApplications(applications); renderApplicationsTable(); renderStatusSummary(); } function clearAllData() { if (!confirm("Are you sure you want to delete ALL application data? This action cannot be undone.")) { return; } localStorage.removeItem('adoptionApplications'); renderApplicationsTable(); renderStatusSummary(); clearError(); } // --- PDF Generation --- async function downloadPdf() { const doc = new jsPDF(); const primaryColorRgb = getRgbFromCssVar('--primary-color'); const primaryDarkColorRgb = getRgbFromCssVar('--primary-dark-color'); const textColorRgb = getRgbFromCssVar('--text-color'); const cardBgRgb = getRgbFromCssVar('--card-background'); const borderColorRgb = getRgbFromCssVar('--border-color'); let y = 20; const margin = 15; const lineHeight = 7; doc.setFontSize(22); doc.setTextColor(primaryDarkColorRgb[0], primaryDarkColorRgb[1], primaryDarkColorRgb[2]); doc.text("Adoption Application Report", margin, y); y += lineHeight * 2; // Status Summary doc.setFontSize(14); doc.setTextColor(primaryDarkColorRgb[0], primaryDarkColorRgb[1], primaryDarkColorRgb[2]); doc.text("Status Summary:", margin, y); y += lineHeight * 1.5; const applications = getApplications(); const statusCounts = STATUSES.reduce((acc, status) => { acc[status] = 0; return acc; }, {}); applications.forEach(app => { if (statusCounts.hasOwnProperty(app.status)) { statusCounts[app.status]++; } }); const summaryData = Object.entries(statusCounts).map(([status, count]) => [status, count]); doc.autoTable({ startY: y, head: [['Status', 'Count']], body: summaryData, theme: 'grid', headStyles: { fillColor: primaryColorRgb, textColor: 255, fontStyle: 'bold', fontSize: 10 }, styles: { fontSize: 9, textColor: textColorRgb, lineColor: borderColorRgb, lineWidth: 0.1 }, alternateRowStyles: { fillColor: cardBgRgb }, didDrawPage: function (data) { y = data.cursor.y; } }); y = doc.autoTable.previous.finalY + lineHeight * 2; // All Applications Table doc.setFontSize(14); doc.setTextColor(primaryDarkColorRgb[0], primaryDarkColorRgb[1], primaryDarkColorRgb[2]); if (y + lineHeight * 2 > doc.internal.pageSize.height - margin) { doc.addPage(); y = margin; } doc.text("All Applications:", margin, y); y += lineHeight * 1.5; const tableData = applications.map(app => [ app.id, app.applicantName, app.petOrChild || 'N/A', formatDate(app.applicationDate), app.status ]); doc.autoTable({ startY: y, head: [['ID', 'Applicant', 'Pet/Child', 'App Date', 'Status']], body: tableData, theme: 'grid', headStyles: { fillColor: primaryColorRgb, textColor: 255, fontStyle: 'bold', fontSize: 10 }, styles: { fontSize: 9, textColor: textColorRgb, lineColor: borderColorRgb, lineWidth: 0.1, valign: 'middle' }, alternateRowStyles: { fillColor: cardBgRgb }, didDrawPage: function (data) { y = data.cursor.y; } }); y = doc.autoTable.previous.finalY + lineHeight * 2; const disclaimerText = "This report provides a summary of adoption applications. Data is sourced from the Adoption Application Tracker tool. For detailed application histories, please refer to the live tracker."; doc.setFontSize(8); doc.setTextColor(primaryDarkColorRgb[0], primaryDarkColorRgb[1], primaryDarkColorRgb[2]); const disclaimerLines = doc.splitTextToSize(disclaimerText, doc.internal.pageSize.width - 2 * margin); if (y + lineHeight * disclaimerLines.length > doc.internal.pageSize.height - margin) { doc.addPage(); y = margin; } doc.text(disclaimerLines, margin, y); doc.save('Adoption_Application_Report.pdf'); } // --- Event Listeners --- addApplicationBtn.addEventListener('click', addApplication); clearAllBtn.addEventListener('click', clearAllData); downloadPdfBtn.addEventListener('click', downloadPdf); // Initial render renderApplicationsTable(); renderStatusSummary(); applicationDateInput.value = new Date().toISOString().split('T')[0]; // Set today's date as default });