import { deleteJson, getJson, sendJson } from './api.js'; import { renderCmsCategoryList, renderCmsContentEmpty, renderCmsContentRow } from './cmsRenderer.js'; import { esc } from './sanitize.js'; export function createCmsController(deps) { var contentData = []; function loadStats() { getJson('/api/admin/learning/stats') .then(function(data) { if (!data.success) return; var s = data.stats; setText('cms-stat-published', s.publishedContent); setText('cms-stat-drafts', s.totalContent - s.publishedContent); setText('cms-stat-categories', s.totalCategories); setText('cms-stat-quizzes', s.totalQuizzes); setText('cms-stat-attempts', s.totalAttempts); }); } function loadCategories(editorCategoryId, filterCategoryId) { getJson('/api/admin/learning/categories') .then(function(data) { if (!data.success) return; var container = document.getElementById('lh-cms-categories'); if (!container) return; container.innerHTML = renderCmsCategoryList(data.categories); updateCategorySelects(data.categories, editorCategoryId, filterCategoryId); setActiveCategory((document.getElementById('cms-filter-category') || {}).value || 'all'); }); } function addCategory() { var input = document.getElementById('lh-cms-cat-name'); if (!input || !input.value.trim()) { deps.showToast('Enter category name', 'error'); return; } sendJson('/api/admin/learning/categories', 'POST', { name: input.value.trim() }) .then(function(data) { if (data.success) { input.value = ''; loadCategories(); deps.refreshUserCategories(); deps.showToast('Category created', 'success'); } else deps.showToast(data.error || 'Failed', 'error'); }) .catch(function() { deps.showToast('Request failed', 'error'); }); } function deleteCategory(id) { if (!window.__confirmDeleteCat) { window.__confirmDeleteCat = id; deps.showToast('Click delete again to confirm removing this category', 'info'); setTimeout(function() { window.__confirmDeleteCat = null; }, 4000); return; } window.__confirmDeleteCat = null; deleteJson('/api/admin/learning/categories/' + id) .then(function(data) { if (data.success) { loadCategories(); deps.refreshUserCategories(); deps.showToast('Category deleted', 'info'); } else deps.showToast(data.error || 'Failed', 'error'); }); } function loadContent() { var container = document.getElementById('lh-cms-content-list'); if (!container) return; container.innerHTML = '

Loading...

'; getJson('/api/admin/learning/content') .then(function(data) { if (!data.success) return; contentData = data.content || []; if (contentData.length === 0) { container.innerHTML = '

No content yet. Click "New Content" to create.

'; return; } renderContentList(contentData); }); } function handleFilterInput(e) { if (e.target.id === 'cms-search') filterContent(); } function handleFilterChange(e) { if (e.target.id !== 'cms-filter-status' && e.target.id !== 'cms-filter-category') return; if (e.target.id === 'cms-filter-category') setActiveCategory(e.target.value || 'all'); filterContent(); } function filterByCategory(categoryId) { var filterSel = document.getElementById('cms-filter-category'); if (filterSel) filterSel.value = String(categoryId); setActiveCategory(categoryId); filterContent(); } function refreshAll() { loadContent(); loadCategories(); loadStats(); } function renderContentList(items) { var container = document.getElementById('lh-cms-content-list'); if (!container) return; if (!items || items.length === 0) { container.innerHTML = renderCmsContentEmpty(); return; } container.innerHTML = items.map(renderCmsContentRow).join(''); } function filterContent() { var search = (document.getElementById('cms-search') || {}).value || ''; var statusFilter = (document.getElementById('cms-filter-status') || {}).value || 'all'; var catFilter = (document.getElementById('cms-filter-category') || {}).value || 'all'; search = search.toLowerCase().trim(); var filtered = contentData.filter(function(item) { var title = (item.title || '').toLowerCase(); var subject = (item.subject || '').toLowerCase(); if (search && title.indexOf(search) === -1 && subject.indexOf(search) === -1) return false; if (statusFilter === 'published' && !item.published) return false; if (statusFilter === 'draft' && item.published) return false; if (catFilter !== 'all' && String(item.category_id) !== catFilter) return false; return true; }); renderContentList(filtered); } return { addCategory: addCategory, deleteCategory: deleteCategory, filterByCategory: filterByCategory, handleFilterChange: handleFilterChange, handleFilterInput: handleFilterInput, loadCategories: loadCategories, loadContent: loadContent, loadStats: loadStats, refreshAll: refreshAll }; } function updateCategorySelects(categories, editorCategoryId, filterCategoryId) { var sel = document.getElementById('lh-cms-edit-category'); if (sel) { var selectedEditorId = editorCategoryId !== undefined ? editorCategoryId : sel.value; sel.innerHTML = ''; categories.forEach(function(c) { sel.innerHTML += ''; }); if (selectedEditorId && hasSelectValue(sel, selectedEditorId)) sel.value = selectedEditorId; } var filterSel = document.getElementById('cms-filter-category'); if (filterSel) { var selectedFilterId = filterCategoryId !== undefined ? filterCategoryId : filterSel.value; filterSel.innerHTML = ''; categories.forEach(function(c) { filterSel.innerHTML += ''; }); if (selectedFilterId && hasSelectValue(filterSel, selectedFilterId)) filterSel.value = selectedFilterId; } } function setText(id, val) { var el = document.getElementById(id); if (el) el.textContent = val; } function setActiveCategory(categoryId) { categoryId = String(categoryId || 'all'); document.querySelectorAll('.lh-cms-cat-filter').forEach(function(item) { item.classList.toggle('active', categoryId !== 'all' && item.dataset.id === categoryId); }); } function hasSelectValue(sel, value) { value = String(value); for (var i = 0; i < sel.options.length; i++) { if (sel.options[i].value === value) return true; } return false; }