// ============================================================ // ADMIN: DEVELOPMENTAL MILESTONES MANAGEMENT // ============================================================ (function() { var _inited = false; document.addEventListener('tabChanged', function(e) { if (e.detail.tab !== 'admin' || _inited) return; _inited = true; initMilestonesAdmin(); }); var milestones = []; var ageGroups = []; var domains = []; var editingId = null; function initMilestonesAdmin() { console.log('[AdminMilestones] Initializing...'); // Buttons document.getElementById('btn-refresh-milestones')?.addEventListener('click', loadMilestones); document.getElementById('btn-add-milestone')?.addEventListener('click', function() { editingId = null; openMilestoneModal(); }); document.getElementById('btn-close-milestone-modal')?.addEventListener('click', closeMilestoneModal); document.getElementById('btn-cancel-milestone-modal')?.addEventListener('click', closeMilestoneModal); document.getElementById('btn-save-milestone')?.addEventListener('click', saveMilestone); // Filter document.getElementById('ms-filter-age')?.addEventListener('change', renderMilestones); // Load data loadMetadata(); loadMilestones(); } function loadMetadata() { fetch('/api/admin/milestones/meta', { headers: getAuthHeaders() }) .then(r => r.json()) .then(data => { if (!data.success) return; ageGroups = data.age_groups || []; domains = data.domains || []; // Populate filter dropdown var filterSelect = document.getElementById('ms-filter-age'); if (filterSelect) { filterSelect.innerHTML = ''; ageGroups.forEach(function(age) { var opt = document.createElement('option'); opt.value = age; opt.textContent = age; filterSelect.appendChild(opt); }); } // Populate datalists for modal var ageDatalist = document.getElementById('ms-age-list'); if (ageDatalist) { ageDatalist.innerHTML = ''; ageGroups.forEach(function(age) { var opt = document.createElement('option'); opt.value = age; ageDatalist.appendChild(opt); }); } var domainDatalist = document.getElementById('ms-domain-list'); if (domainDatalist) { domainDatalist.innerHTML = ''; domains.forEach(function(domain) { var opt = document.createElement('option'); opt.value = domain; domainDatalist.appendChild(opt); }); } }) .catch(err => console.error('[AdminMilestones] Failed to load metadata:', err)); } function loadMilestones() { var filterAge = document.getElementById('ms-filter-age')?.value; var url = '/api/admin/milestones' + (filterAge ? '?age_group=' + encodeURIComponent(filterAge) : ''); fetch(url, { headers: getAuthHeaders() }) .then(r => r.json()) .then(data => { if (!data.success) { showToast(data.error || 'Failed to load milestones', 'error'); return; } milestones = data.milestones || []; renderMilestones(); }) .catch(err => { console.error('[AdminMilestones] Failed to load:', err); showToast('Failed to load milestones: ' + err.message, 'error'); }); } function renderMilestones() { var list = document.getElementById('milestones-list'); if (!list) return; var filterAge = document.getElementById('ms-filter-age')?.value; var filtered = filterAge ? milestones.filter(m => m.age_group === filterAge) : milestones; if (filtered.length === 0) { list.innerHTML = '
No milestones found. Click "Add Milestone" to create one.
'; return; } // Group by age_group and domain var grouped = {}; filtered.forEach(function(m) { if (!grouped[m.age_group]) grouped[m.age_group] = {}; if (!grouped[m.age_group][m.domain]) grouped[m.age_group][m.domain] = []; grouped[m.age_group][m.domain].push(m); }); var html = ''; Object.keys(grouped).forEach(function(age) { html += '