// 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, // Modal state showCreateHomepageConfirm: false, pendingHomepagePlatform: null, showDeletePageConfirm: false, pageToDelete: null, // Tabs and filters activeTab: 'all', // all, platform_marketing, store_defaults, store_overrides searchQuery: '', selectedPlatform: '', // Platform code filter // Initialize async init() { // Load i18n translations await I18n.loadModule('cms'); 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, store_id=null) get platformMarketingPages() { return this.allPages.filter(page => page.is_platform_page && !page.store_id); }, // Computed: Store Default pages (is_platform_page=false, store_id=null) get storeDefaultPages() { return this.allPages.filter(page => !page.is_platform_page && !page.store_id); }, // Computed: Store Override pages (store_id is set) get storeOverridePages() { return this.allPages.filter(page => page.store_id); }, // Legacy computed (for backward compatibility) get platformPages() { return [...this.platformMarketingPages, ...this.storeDefaultPages]; }, get storePages() { return this.storeOverridePages; }, // 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 === 'store_defaults') { pages = this.storeDefaultPages; } else if (this.activeTab === 'store_overrides') { pages = this.storeOverridePages; } 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.store_name && page.store_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 + store, 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 this.pendingHomepagePlatform = platformCode; this.showCreateHomepageConfirm = true; } } }, // Create homepage for a platform (called from confirm modal) createHomepage() { if (this.pendingHomepagePlatform) { window.location.href = `/admin/content-pages/create?platform_code=${this.pendingHomepagePlatform}&slug=home&is_platform_page=true`; } }, // Get page tier label (three-tier system) getPageTierLabel(page) { if (page.store_id) { return 'Store Override'; } else if (page.is_platform_page) { return 'Platform Marketing'; } else { return 'Store Default'; } }, // Get page tier CSS class (three-tier system) getPageTierClass(page) { if (page.store_id) { // Store 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 { // Store Default - teal return 'bg-teal-100 text-teal-800 dark:bg-teal-900 dark:text-teal-200'; } }, // Prompt delete page confirmation promptDeletePage(page) { this.pageToDelete = page; this.showDeletePageConfirm = true; }, // Delete a page async deletePage(page) { 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(I18n.t('cms.messages.failed_to_delete_page', { error: 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' }); } } }; }