Some checks failed
Migrated ~68 native browser confirm() calls across 74 files to use the project's confirm_modal/confirm_modal_dynamic Jinja2 macros, providing consistent styled confirmation dialogs instead of plain browser popups. Modules updated: core, tenancy, cms, marketplace, messaging, billing, customers, orders, cart. Uses danger/warning/info variants and double-confirm pattern for destructive delete operations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
225 lines
8.0 KiB
JavaScript
225 lines
8.0 KiB
JavaScript
// static/store/js/content-pages.js
|
|
|
|
// Use centralized logger
|
|
const contentPagesLog = window.LogConfig.loggers.contentPages || window.LogConfig.createLogger('contentPages');
|
|
|
|
// ============================================
|
|
// STORE CONTENT PAGES MANAGER
|
|
// ============================================
|
|
function storeContentPagesManager() {
|
|
return {
|
|
// Inherit base layout functionality from init-alpine.js
|
|
...data(),
|
|
|
|
// Page identifier for sidebar active state
|
|
currentPage: 'content-pages',
|
|
|
|
// State
|
|
loading: false,
|
|
error: null,
|
|
activeTab: 'platform',
|
|
searchQuery: '',
|
|
|
|
// Modal state
|
|
showDeletePageConfirm: false,
|
|
pageToDelete: null,
|
|
|
|
// Data
|
|
platformPages: [], // Platform default pages
|
|
customPages: [], // Store's own pages (overrides + custom)
|
|
overrideMap: {}, // Map of slug -> page id for quick lookup
|
|
cmsUsage: null, // CMS usage statistics
|
|
|
|
// Initialize
|
|
async init() {
|
|
contentPagesLog.info('=== STORE CONTENT PAGES MANAGER INITIALIZING ===');
|
|
|
|
// Prevent multiple initializations
|
|
if (window._storeContentPagesInitialized) {
|
|
contentPagesLog.warn('Content pages manager already initialized, skipping...');
|
|
return;
|
|
}
|
|
window._storeContentPagesInitialized = true;
|
|
|
|
try {
|
|
// IMPORTANT: Call parent init first to set storeCode from URL
|
|
const parentInit = data().init;
|
|
if (parentInit) {
|
|
await parentInit.call(this);
|
|
}
|
|
|
|
await Promise.all([
|
|
this.loadPages(),
|
|
this.loadCmsUsage()
|
|
]);
|
|
|
|
contentPagesLog.info('=== STORE CONTENT PAGES MANAGER INITIALIZATION COMPLETE ===');
|
|
} catch (error) {
|
|
contentPagesLog.error('Failed to initialize content pages:', error);
|
|
this.error = 'Failed to initialize. Please refresh the page.';
|
|
this.loading = false;
|
|
}
|
|
},
|
|
|
|
// Load all pages
|
|
async loadPages() {
|
|
this.loading = true;
|
|
this.error = null;
|
|
|
|
try {
|
|
contentPagesLog.info('Loading content pages...');
|
|
|
|
// Load platform defaults and store pages in parallel
|
|
const [platformResponse, storeResponse] = await Promise.all([
|
|
apiClient.get('/store/content-pages/'),
|
|
apiClient.get('/store/content-pages/overrides')
|
|
]);
|
|
|
|
// Platform pages - filter to only show actual platform defaults
|
|
const allPages = platformResponse.data || platformResponse || [];
|
|
this.platformPages = allPages.filter(p => p.is_platform_page);
|
|
|
|
// Store's custom pages (includes overrides)
|
|
this.customPages = storeResponse.data || storeResponse || [];
|
|
|
|
// Build override map for quick lookups
|
|
this.overrideMap = {};
|
|
this.customPages.forEach(page => {
|
|
if (page.is_store_override) {
|
|
this.overrideMap[page.slug] = page.id;
|
|
}
|
|
});
|
|
|
|
contentPagesLog.info(`Loaded ${this.platformPages.length} platform pages, ${this.customPages.length} store pages`);
|
|
|
|
} catch (err) {
|
|
contentPagesLog.error('Error loading pages:', err);
|
|
this.error = err.message || 'Failed to load pages';
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
|
|
// Load CMS usage statistics
|
|
async loadCmsUsage() {
|
|
try {
|
|
contentPagesLog.info('Loading CMS usage...');
|
|
const response = await apiClient.get('/store/content-pages/usage');
|
|
this.cmsUsage = response.data || response;
|
|
contentPagesLog.info('CMS usage loaded:', this.cmsUsage);
|
|
} catch (err) {
|
|
contentPagesLog.error('Error loading CMS usage:', err);
|
|
// Non-critical - don't set error state
|
|
}
|
|
},
|
|
|
|
// Check if store has overridden a platform page
|
|
hasOverride(slug) {
|
|
return slug in this.overrideMap;
|
|
},
|
|
|
|
// Get override page ID
|
|
getOverrideId(slug) {
|
|
return this.overrideMap[slug];
|
|
},
|
|
|
|
// Create an override for a platform page
|
|
async createOverride(platformPage) {
|
|
contentPagesLog.info('Creating override for:', platformPage.slug);
|
|
|
|
try {
|
|
// Create a new store page with the same slug as the platform page
|
|
const payload = {
|
|
slug: platformPage.slug,
|
|
title: platformPage.title,
|
|
content: platformPage.content,
|
|
content_format: platformPage.content_format || 'html',
|
|
meta_description: platformPage.meta_description,
|
|
meta_keywords: platformPage.meta_keywords,
|
|
is_published: true,
|
|
show_in_header: platformPage.show_in_header,
|
|
show_in_footer: platformPage.show_in_footer,
|
|
display_order: platformPage.display_order
|
|
};
|
|
|
|
const response = await apiClient.post('/store/content-pages/', payload);
|
|
const newPage = response.data || response;
|
|
|
|
contentPagesLog.info('Override created:', newPage.id);
|
|
|
|
// Redirect to edit the new page
|
|
window.location.href = `/store/${this.storeCode}/content-pages/${newPage.id}/edit`;
|
|
|
|
} catch (err) {
|
|
contentPagesLog.error('Error creating override:', err);
|
|
this.error = err.message || 'Failed to create override';
|
|
}
|
|
},
|
|
|
|
// 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(`/store/content-pages/${page.id}`);
|
|
|
|
// Remove from local state
|
|
this.customPages = this.customPages.filter(p => p.id !== page.id);
|
|
|
|
// Update override map
|
|
if (page.is_store_override) {
|
|
delete this.overrideMap[page.slug];
|
|
}
|
|
|
|
contentPagesLog.info('Page deleted successfully');
|
|
|
|
} catch (err) {
|
|
contentPagesLog.error('Error deleting page:', err);
|
|
this.error = err.message || 'Failed to delete page';
|
|
}
|
|
},
|
|
|
|
// Filtered platform pages based on search
|
|
get filteredPlatformPages() {
|
|
if (!this.searchQuery) {
|
|
return this.platformPages;
|
|
}
|
|
const query = this.searchQuery.toLowerCase();
|
|
return this.platformPages.filter(page =>
|
|
page.title.toLowerCase().includes(query) ||
|
|
page.slug.toLowerCase().includes(query)
|
|
);
|
|
},
|
|
|
|
// Filtered custom pages based on search
|
|
get filteredCustomPages() {
|
|
if (!this.searchQuery) {
|
|
return this.customPages;
|
|
}
|
|
const query = this.searchQuery.toLowerCase();
|
|
return this.customPages.filter(page =>
|
|
page.title.toLowerCase().includes(query) ||
|
|
page.slug.toLowerCase().includes(query)
|
|
);
|
|
},
|
|
|
|
// Format date for display
|
|
formatDate(dateStr) {
|
|
if (!dateStr) return '—';
|
|
const date = new Date(dateStr);
|
|
const locale = window.STORE_CONFIG?.locale || 'en-GB';
|
|
return date.toLocaleDateString(locale, {
|
|
day: '2-digit',
|
|
month: 'short',
|
|
year: 'numeric'
|
|
});
|
|
}
|
|
};
|
|
}
|