// noqa: js-006 - async init pattern is safe, loadData has try/catch // static/admin/js/content-pages.js // Use centralized logger const contentPagesLog = window.LogConfig.loggers.contentPages || window.LogConfig.createLogger('contentPages'); // ============================================ // CONTENT PAGES MANAGER FUNCTION // ============================================ function contentPagesManager() { return { // Inherit base layout functionality from init-alpine.js ...data(), // Page identifier for sidebar active state currentPage: 'content-pages', // Content pages specific state allPages: [], platforms: [], loading: false, error: null, // Tabs and filters activeTab: 'all', // all, platform_marketing, vendor_defaults, vendor_overrides searchQuery: '', selectedPlatform: '', // Platform code filter // Initialize async init() { contentPagesLog.info('=== CONTENT PAGES MANAGER INITIALIZING ==='); // Prevent multiple initializations if (window._contentPagesInitialized) { contentPagesLog.warn('Content pages manager already initialized, skipping...'); return; } window._contentPagesInitialized = true; contentPagesLog.group('Loading data'); await Promise.all([ this.loadPages(), this.loadPlatforms() ]); contentPagesLog.groupEnd(); // Check for platform filter in URL (support both 'platform' and 'platform_code') const urlParams = new URLSearchParams(window.location.search); const platformParam = urlParams.get('platform_code') || urlParams.get('platform'); if (platformParam) { this.selectedPlatform = platformParam; } // Check for slug param - if specified, redirect to edit page const slugParam = urlParams.get('slug'); if (slugParam && platformParam) { await this.redirectToEditIfSlugMatches(platformParam, slugParam); } contentPagesLog.info('=== CONTENT PAGES MANAGER INITIALIZATION COMPLETE ==='); }, // Computed: Platform Marketing pages (is_platform_page=true, vendor_id=null) get platformMarketingPages() { return this.allPages.filter(page => page.is_platform_page && !page.vendor_id); }, // Computed: Vendor Default pages (is_platform_page=false, vendor_id=null) get vendorDefaultPages() { return this.allPages.filter(page => !page.is_platform_page && !page.vendor_id); }, // Computed: Vendor Override pages (vendor_id is set) get vendorOverridePages() { return this.allPages.filter(page => page.vendor_id); }, // Legacy computed (for backward compatibility) get platformPages() { return [...this.platformMarketingPages, ...this.vendorDefaultPages]; }, get vendorPages() { return this.vendorOverridePages; }, // Computed: Filtered pages based on active tab, platform, and search get filteredPages() { let pages = []; // Filter by tab (three-tier system) if (this.activeTab === 'platform_marketing') { pages = this.platformMarketingPages; } else if (this.activeTab === 'vendor_defaults') { pages = this.vendorDefaultPages; } else if (this.activeTab === 'vendor_overrides') { pages = this.vendorOverridePages; } else { pages = this.allPages; } // Filter by selected platform if (this.selectedPlatform) { pages = pages.filter(page => page.platform_code === this.selectedPlatform ); } // Filter by search query if (this.searchQuery) { const query = this.searchQuery.toLowerCase(); pages = pages.filter(page => page.title.toLowerCase().includes(query) || page.slug.toLowerCase().includes(query) || (page.vendor_name && page.vendor_name.toLowerCase().includes(query)) || (page.platform_name && page.platform_name.toLowerCase().includes(query)) ); } // Sort by display_order, then title return pages.sort((a, b) => { if (a.display_order !== b.display_order) { return a.display_order - b.display_order; } return a.title.localeCompare(b.title); }); }, // Load all content pages async loadPages() { this.loading = true; this.error = null; try { contentPagesLog.info('Fetching all content pages...'); // Fetch all pages (platform + vendor, published + unpublished) const response = await apiClient.get('/admin/content-pages/?include_unpublished=true'); contentPagesLog.debug('API Response:', response); if (!response) { throw new Error('Invalid API response'); } // Handle response - API returns array directly this.allPages = Array.isArray(response) ? response : (response.data || response.items || []); contentPagesLog.info(`Loaded ${this.allPages.length} pages`); } catch (err) { contentPagesLog.error('Error loading content pages:', err); this.error = err.message || 'Failed to load content pages'; } finally { this.loading = false; } }, // Load platforms for filter dropdown async loadPlatforms() { try { contentPagesLog.info('Fetching platforms...'); const response = await apiClient.get('/admin/platforms'); this.platforms = response.platforms || []; contentPagesLog.info(`Loaded ${this.platforms.length} platforms`); } catch (err) { contentPagesLog.error('Error loading platforms:', err); // Non-critical - don't set error state } }, // Redirect to edit page if a specific slug is requested async redirectToEditIfSlugMatches(platformCode, slug) { contentPagesLog.info(`Looking for page with platform=${platformCode}, slug=${slug}`); // Find the page matching the platform and slug const matchingPage = this.allPages.find(page => page.platform_code === platformCode && page.slug === slug ); if (matchingPage) { contentPagesLog.info(`Found matching page: ${matchingPage.id}, redirecting to edit...`); window.location.href = `/admin/content-pages/${matchingPage.id}/edit`; } else { contentPagesLog.warn(`No page found for platform=${platformCode}, slug=${slug}`); // Show a toast and offer to create if (slug === 'home') { // Offer to create homepage if (confirm(`No homepage found for ${platformCode}. Would you like to create one?`)) { window.location.href = `/admin/content-pages/create?platform_code=${platformCode}&slug=home&is_platform_page=true`; } } } }, // Get page tier label (three-tier system) getPageTierLabel(page) { if (page.vendor_id) { return 'Vendor Override'; } else if (page.is_platform_page) { return 'Platform Marketing'; } else { return 'Vendor Default'; } }, // Get page tier CSS class (three-tier system) getPageTierClass(page) { if (page.vendor_id) { // Vendor Override - purple return 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200'; } else if (page.is_platform_page) { // Platform Marketing - blue return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200'; } else { // Vendor Default - teal return 'bg-teal-100 text-teal-800 dark:bg-teal-900 dark:text-teal-200'; } }, // Delete a page async deletePage(page) { if (!confirm(`Are you sure you want to delete "${page.title}"?`)) { return; } try { contentPagesLog.info(`Deleting page: ${page.id}`); await apiClient.delete(`/admin/content-pages/${page.id}`); // Remove from local array this.allPages = this.allPages.filter(p => p.id !== page.id); contentPagesLog.info('Page deleted successfully'); } catch (err) { contentPagesLog.error('Error deleting page:', err); Utils.showToast(`Failed to delete page: ${err.message}`, 'error'); } }, // Format date helper formatDate(dateString) { if (!dateString) return '—'; const date = new Date(dateString); const now = new Date(); const diffMs = now - date; const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); if (diffDays === 0) { return 'Today'; } else if (diffDays === 1) { return 'Yesterday'; } else if (diffDays < 7) { return `${diffDays} days ago`; } else { return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }); } } }; }