diff --git a/app/modules/cart/templates/cart/storefront/cart.html b/app/modules/cart/templates/cart/storefront/cart.html index aaca6bc7..4c90d6f1 100644 --- a/app/modules/cart/templates/cart/storefront/cart.html +++ b/app/modules/cart/templates/cart/storefront/cart.html @@ -208,7 +208,7 @@ document.addEventListener('alpine:init', () => { // Initialize async init() { - console.log('[SHOP] Cart page initializing...'); + console.log('[STOREFRONT] Cart page initializing...'); // Call parent init to set up sessionId if (baseData.init) { @@ -223,17 +223,17 @@ document.addEventListener('alpine:init', () => { this.loading = true; try { - console.log(`[SHOP] Loading cart for session ${this.sessionId}...`); + console.log(`[STOREFRONT] Loading cart for session ${this.sessionId}...`); const response = await fetch(`/api/v1/storefront/cart/${this.sessionId}`); if (response.ok) { const data = await response.json(); this.items = data.items || []; this.cartCount = this.totalItems; - console.log('[SHOP] Cart loaded:', this.items.length, 'items'); + console.log('[STOREFRONT] Cart loaded:', this.items.length, 'items'); } } catch (error) { - console.error('[SHOP] Failed to load cart:', error); + console.error('[STOREFRONT] Failed to load cart:', error); this.showToast('Failed to load cart', 'error'); } finally { this.loading = false; @@ -249,7 +249,7 @@ document.addEventListener('alpine:init', () => { this.updating = true; try { - console.log('[SHOP] Updating quantity:', productId, newQuantity); + console.log('[STOREFRONT] Updating quantity:', productId, newQuantity); const response = await fetch( `/api/v1/storefront/cart/${this.sessionId}/items/${productId}`, { @@ -268,7 +268,7 @@ document.addEventListener('alpine:init', () => { throw new Error('Failed to update quantity'); } } catch (error) { - console.error('[SHOP] Update quantity error:', error); + console.error('[STOREFRONT] Update quantity error:', error); this.showToast('Failed to update quantity', 'error'); } finally { this.updating = false; @@ -280,7 +280,7 @@ document.addEventListener('alpine:init', () => { this.updating = true; try { - console.log('[SHOP] Removing item:', productId); + console.log('[STOREFRONT] Removing item:', productId); const response = await fetch( `/api/v1/storefront/cart/${this.sessionId}/items/${productId}`, { @@ -295,7 +295,7 @@ document.addEventListener('alpine:init', () => { throw new Error('Failed to remove item'); } } catch (error) { - console.error('[SHOP] Remove item error:', error); + console.error('[STOREFRONT] Remove item error:', error); this.showToast('Failed to remove item', 'error'); } finally { this.updating = false; diff --git a/app/modules/catalog/templates/catalog/storefront/category.html b/app/modules/catalog/templates/catalog/storefront/category.html index 9fcc9076..a873a6d0 100644 --- a/app/modules/catalog/templates/catalog/storefront/category.html +++ b/app/modules/catalog/templates/catalog/storefront/category.html @@ -187,8 +187,8 @@ document.addEventListener('alpine:init', () => { }, async init() { - console.log('[SHOP] Category page initializing...'); - console.log('[SHOP] Category slug:', this.categorySlug); + console.log('[STOREFRONT] Category page initializing...'); + console.log('[STOREFRONT] Category slug:', this.categorySlug); // Convert slug to display name this.categoryName = this.categorySlug @@ -213,7 +213,7 @@ document.addEventListener('alpine:init', () => { params.append('sort', this.sortBy); } - console.log(`[SHOP] Loading category products from /api/v1/storefront/products?${params}`); + console.log(`[STOREFRONT] Loading category products from /api/v1/storefront/products?${params}`); const response = await fetch(`/api/v1/storefront/products?${params}`); @@ -223,12 +223,12 @@ document.addEventListener('alpine:init', () => { const data = await response.json(); - console.log(`[SHOP] Loaded ${data.products.length} products (total: ${data.total})`); + console.log(`[STOREFRONT] Loaded ${data.products.length} products (total: ${data.total})`); this.products = data.products; this.total = data.total; } catch (error) { - console.error('[SHOP] Failed to load category products:', error); + console.error('[STOREFRONT] Failed to load category products:', error); this.showToast('Failed to load products', 'error'); } finally { this.loading = false; @@ -243,7 +243,7 @@ document.addEventListener('alpine:init', () => { }, async addToCart(product) { - console.log('[SHOP] Adding to cart:', product); + console.log('[STOREFRONT] Adding to cart:', product); try { const url = `/api/v1/storefront/cart/${this.sessionId}/items`; @@ -262,16 +262,16 @@ document.addEventListener('alpine:init', () => { if (response.ok) { const result = await response.json(); - console.log('[SHOP] Add to cart success:', result); + console.log('[STOREFRONT] Add to cart success:', result); this.cartCount += 1; this.showToast(`${product.marketplace_product.title} added to cart`, 'success'); } else { const error = await response.json(); - console.error('[SHOP] Add to cart error:', error); + console.error('[STOREFRONT] Add to cart error:', error); this.showToast(error.message || 'Failed to add to cart', 'error'); } } catch (error) { - console.error('[SHOP] Add to cart exception:', error); + console.error('[STOREFRONT] Add to cart exception:', error); this.showToast('Failed to add to cart', 'error'); } } diff --git a/app/modules/catalog/templates/catalog/storefront/product.html b/app/modules/catalog/templates/catalog/storefront/product.html index a86dc21e..b8d18ded 100644 --- a/app/modules/catalog/templates/catalog/storefront/product.html +++ b/app/modules/catalog/templates/catalog/storefront/product.html @@ -256,16 +256,16 @@ document.addEventListener('alpine:init', () => { // Initialize async init() { - console.log('[SHOP] Product detail page initializing...'); + console.log('[STOREFRONT] Product detail page initializing...'); // Call parent init to set up sessionId if (baseData.init) { baseData.init.call(this); } - console.log('[SHOP] Product ID:', this.productId); - console.log('[SHOP] Store ID:', this.storeId); - console.log('[SHOP] Session ID:', this.sessionId); + console.log('[STOREFRONT] Product ID:', this.productId); + console.log('[STOREFRONT] Store ID:', this.storeId); + console.log('[STOREFRONT] Session ID:', this.sessionId); await this.loadProduct(); }, @@ -275,7 +275,7 @@ document.addEventListener('alpine:init', () => { this.loading = true; try { - console.log(`[SHOP] Loading product ${this.productId}...`); + console.log(`[STOREFRONT] Loading product ${this.productId}...`); const response = await fetch(`/api/v1/storefront/products/${this.productId}`); if (!response.ok) { @@ -283,7 +283,7 @@ document.addEventListener('alpine:init', () => { } this.product = await response.json(); - console.log('[SHOP] Product loaded:', this.product); + console.log('[STOREFRONT] Product loaded:', this.product); // Set default image if (this.product?.marketplace_product?.image_link) { @@ -297,7 +297,7 @@ document.addEventListener('alpine:init', () => { await this.loadRelatedProducts(); } catch (error) { - console.error('[SHOP] Failed to load product:', error); + console.error('[STOREFRONT] Failed to load product:', error); this.showToast('Failed to load product', 'error'); // Redirect back to products after error setTimeout(() => { @@ -320,10 +320,10 @@ document.addEventListener('alpine:init', () => { .filter(p => p.id !== parseInt(this.productId)) .slice(0, 4); - console.log('[SHOP] Loaded related products:', this.relatedProducts.length); + console.log('[STOREFRONT] Loaded related products:', this.relatedProducts.length); } } catch (error) { - console.error('[SHOP] Failed to load related products:', error); + console.error('[STOREFRONT] Failed to load related products:', error); } }, @@ -356,7 +356,7 @@ document.addEventListener('alpine:init', () => { // Add to cart async addToCart() { if (!this.canAddToCart) { - console.warn('[SHOP] Cannot add to cart:', { + console.warn('[STOREFRONT] Cannot add to cart:', { canAddToCart: this.canAddToCart, isActive: this.product?.is_active, inventory: this.product?.available_inventory, @@ -374,7 +374,7 @@ document.addEventListener('alpine:init', () => { quantity: this.quantity }; - console.log('[SHOP] Adding to cart:', { + console.log('[STOREFRONT] Adding to cart:', { url, sessionId: this.sessionId, productId: this.productId, @@ -390,14 +390,14 @@ document.addEventListener('alpine:init', () => { body: JSON.stringify(payload) }); - console.log('[SHOP] Add to cart response:', { + console.log('[STOREFRONT] Add to cart response:', { status: response.status, ok: response.ok }); if (response.ok) { const result = await response.json(); - console.log('[SHOP] Add to cart success:', result); + console.log('[STOREFRONT] Add to cart success:', result); this.cartCount += this.quantity; this.showToast( @@ -409,11 +409,11 @@ document.addEventListener('alpine:init', () => { this.quantity = this.product?.min_quantity || 1; } else { const error = await response.json(); - console.error('[SHOP] Add to cart error response:', error); + console.error('[STOREFRONT] Add to cart error response:', error); throw new Error(error.detail || 'Failed to add to cart'); } } catch (error) { - console.error('[SHOP] Add to cart exception:', error); + console.error('[STOREFRONT] Add to cart exception:', error); this.showToast(error.message || 'Failed to add to cart', 'error'); } finally { this.addingToCart = false; diff --git a/app/modules/catalog/templates/catalog/storefront/products.html b/app/modules/catalog/templates/catalog/storefront/products.html index f620e1f6..2fabde3d 100644 --- a/app/modules/catalog/templates/catalog/storefront/products.html +++ b/app/modules/catalog/templates/catalog/storefront/products.html @@ -160,7 +160,7 @@ document.addEventListener('alpine:init', () => { }, async init() { - console.log('[SHOP] Products page initializing...'); + console.log('[STOREFRONT] Products page initializing...'); await this.loadProducts(); }, @@ -178,7 +178,7 @@ document.addEventListener('alpine:init', () => { params.append('search', this.filters.search); } - console.log(`[SHOP] Loading products from /api/v1/storefront/products?${params}`); + console.log(`[STOREFRONT] Loading products from /api/v1/storefront/products?${params}`); const response = await fetch(`/api/v1/storefront/products?${params}`); @@ -188,12 +188,12 @@ document.addEventListener('alpine:init', () => { const data = await response.json(); - console.log(`[SHOP] Loaded ${data.products.length} products (total: ${data.total})`); + console.log(`[STOREFRONT] Loaded ${data.products.length} products (total: ${data.total})`); this.products = data.products; this.pagination.total = data.total; } catch (error) { - console.error('[SHOP] Failed to load products:', error); + console.error('[STOREFRONT] Failed to load products:', error); this.showToast('Failed to load products', 'error'); } finally { this.loading = false; @@ -208,7 +208,7 @@ document.addEventListener('alpine:init', () => { // formatPrice is inherited from storefrontLayoutData() via spread operator async addToCart(product) { - console.log('[SHOP] Adding to cart:', product); + console.log('[STOREFRONT] Adding to cart:', product); try { const url = `/api/v1/storefront/cart/${this.sessionId}/items`; @@ -227,16 +227,16 @@ document.addEventListener('alpine:init', () => { if (response.ok) { const result = await response.json(); - console.log('[SHOP] Add to cart success:', result); + console.log('[STOREFRONT] Add to cart success:', result); this.cartCount += 1; this.showToast(`${product.marketplace_product.title} added to cart`, 'success'); } else { const error = await response.json(); - console.error('[SHOP] Add to cart error:', error); + console.error('[STOREFRONT] Add to cart error:', error); this.showToast(error.message || 'Failed to add to cart', 'error'); } } catch (error) { - console.error('[SHOP] Add to cart exception:', error); + console.error('[STOREFRONT] Add to cart exception:', error); this.showToast('Failed to add to cart', 'error'); } } diff --git a/app/modules/catalog/templates/catalog/storefront/search.html b/app/modules/catalog/templates/catalog/storefront/search.html index 5b9d9b1f..15da115b 100644 --- a/app/modules/catalog/templates/catalog/storefront/search.html +++ b/app/modules/catalog/templates/catalog/storefront/search.html @@ -212,7 +212,7 @@ document.addEventListener('alpine:init', () => { }, async init() { - console.log('[SHOP] Search page initializing...'); + console.log('[STOREFRONT] Search page initializing...'); // Check for query parameter in URL const urlParams = new URLSearchParams(window.location.search); @@ -254,7 +254,7 @@ document.addEventListener('alpine:init', () => { limit: this.perPage }); - console.log(`[SHOP] Searching: /api/v1/storefront/products/search?${params}`); + console.log(`[STOREFRONT] Searching: /api/v1/storefront/products/search?${params}`); const response = await fetch(`/api/v1/storefront/products/search?${params}`); @@ -264,12 +264,12 @@ document.addEventListener('alpine:init', () => { const data = await response.json(); - console.log(`[SHOP] Search found ${data.total} results`); + console.log(`[STOREFRONT] Search found ${data.total} results`); this.products = data.products; this.total = data.total; } catch (error) { - console.error('[SHOP] Search failed:', error); + console.error('[STOREFRONT] Search failed:', error); this.showToast('Search failed. Please try again.', 'error'); this.products = []; this.total = 0; @@ -289,7 +289,7 @@ document.addEventListener('alpine:init', () => { }, async addToCart(product) { - console.log('[SHOP] Adding to cart:', product); + console.log('[STOREFRONT] Adding to cart:', product); try { const url = `/api/v1/storefront/cart/${this.sessionId}/items`; @@ -308,16 +308,16 @@ document.addEventListener('alpine:init', () => { if (response.ok) { const result = await response.json(); - console.log('[SHOP] Add to cart success:', result); + console.log('[STOREFRONT] Add to cart success:', result); this.cartCount += 1; this.showToast(`${product.marketplace_product?.title || 'Product'} added to cart`, 'success'); } else { const error = await response.json(); - console.error('[SHOP] Add to cart error:', error); + console.error('[STOREFRONT] Add to cart error:', error); this.showToast(error.message || 'Failed to add to cart', 'error'); } } catch (error) { - console.error('[SHOP] Add to cart exception:', error); + console.error('[STOREFRONT] Add to cart exception:', error); this.showToast('Failed to add to cart', 'error'); } } diff --git a/app/modules/catalog/templates/catalog/storefront/wishlist.html b/app/modules/catalog/templates/catalog/storefront/wishlist.html index 3faffb79..0fe8f557 100644 --- a/app/modules/catalog/templates/catalog/storefront/wishlist.html +++ b/app/modules/catalog/templates/catalog/storefront/wishlist.html @@ -143,7 +143,7 @@ document.addEventListener('alpine:init', () => { isLoggedIn: false, async init() { - console.log('[SHOP] Wishlist page initializing...'); + console.log('[STOREFRONT] Wishlist page initializing...'); // Check if user is logged in this.isLoggedIn = await this.checkLoginStatus(); @@ -168,7 +168,7 @@ document.addEventListener('alpine:init', () => { this.loading = true; try { - console.log('[SHOP] Loading wishlist...'); + console.log('[STOREFRONT] Loading wishlist...'); const response = await fetch('/api/v1/storefront/wishlist'); @@ -182,11 +182,11 @@ document.addEventListener('alpine:init', () => { const data = await response.json(); - console.log(`[SHOP] Loaded ${data.items?.length || 0} wishlist items`); + console.log(`[STOREFRONT] Loaded ${data.items?.length || 0} wishlist items`); this.items = data.items || []; } catch (error) { - console.error('[SHOP] Failed to load wishlist:', error); + console.error('[STOREFRONT] Failed to load wishlist:', error); this.showToast('Failed to load wishlist', 'error'); } finally { this.loading = false; @@ -195,7 +195,7 @@ document.addEventListener('alpine:init', () => { async removeFromWishlist(item) { try { - console.log('[SHOP] Removing from wishlist:', item); + console.log('[STOREFRONT] Removing from wishlist:', item); const response = await fetch(`/api/v1/storefront/wishlist/${item.id}`, { method: 'DELETE' @@ -208,13 +208,13 @@ document.addEventListener('alpine:init', () => { throw new Error('Failed to remove from wishlist'); } } catch (error) { - console.error('[SHOP] Failed to remove from wishlist:', error); + console.error('[STOREFRONT] Failed to remove from wishlist:', error); this.showToast('Failed to remove from wishlist', 'error'); } }, async addToCart(product) { - console.log('[SHOP] Adding to cart:', product); + console.log('[STOREFRONT] Adding to cart:', product); try { const url = `/api/v1/storefront/cart/${this.sessionId}/items`; @@ -233,16 +233,16 @@ document.addEventListener('alpine:init', () => { if (response.ok) { const result = await response.json(); - console.log('[SHOP] Add to cart success:', result); + console.log('[STOREFRONT] Add to cart success:', result); this.cartCount += 1; this.showToast(`${product.marketplace_product?.title || 'Product'} added to cart`, 'success'); } else { const error = await response.json(); - console.error('[SHOP] Add to cart error:', error); + console.error('[STOREFRONT] Add to cart error:', error); this.showToast(error.message || 'Failed to add to cart', 'error'); } } catch (error) { - console.error('[SHOP] Add to cart exception:', error); + console.error('[STOREFRONT] Add to cart exception:', error); this.showToast('Failed to add to cart', 'error'); } } diff --git a/app/modules/core/routes/pages/admin.py b/app/modules/core/routes/pages/admin.py index 7464aea2..eba957dd 100644 --- a/app/modules/core/routes/pages/admin.py +++ b/app/modules/core/routes/pages/admin.py @@ -62,6 +62,7 @@ async def admin_login_page( context = { "request": request, "current_language": language, + "frontend_type": "admin", **get_jinja2_globals(language), } return templates.TemplateResponse("tenancy/admin/login.html", context) diff --git a/app/modules/core/routes/pages/merchant.py b/app/modules/core/routes/pages/merchant.py index 320de998..04c084f4 100644 --- a/app/modules/core/routes/pages/merchant.py +++ b/app/modules/core/routes/pages/merchant.py @@ -72,6 +72,7 @@ async def merchant_login_page( context = { "request": request, "current_language": language, + "frontend_type": "merchant", **get_jinja2_globals(language), } return templates.TemplateResponse("tenancy/merchant/login.html", context) diff --git a/app/modules/core/static/storefront/js/storefront-layout.js b/app/modules/core/static/storefront/js/storefront-layout.js index 30632b16..ec8f71bb 100644 --- a/app/modules/core/static/storefront/js/storefront-layout.js +++ b/app/modules/core/static/storefront/js/storefront-layout.js @@ -5,11 +5,11 @@ * Works with store-specific themes */ -const shopLog = { - info: (...args) => console.info('🛒 [SHOP]', ...args), - warn: (...args) => console.warn('⚠️ [SHOP]', ...args), - error: (...args) => console.error('❌ [SHOP]', ...args), - debug: (...args) => console.log('🔍 [SHOP]', ...args) +const shopLog = window.LogConfig?.createLogger('STOREFRONT') || { + info: (...args) => console.info('🛒 [STOREFRONT]', ...args), + warn: (...args) => console.warn('⚠️ [STOREFRONT]', ...args), + error: (...args) => console.error('❌ [STOREFRONT]', ...args), + debug: (...args) => console.log('🔍 [STOREFRONT]', ...args) }; /** diff --git a/app/modules/core/utils/page_context.py b/app/modules/core/utils/page_context.py index eb25b9ff..2f4ad986 100644 --- a/app/modules/core/utils/page_context.py +++ b/app/modules/core/utils/page_context.py @@ -149,6 +149,9 @@ def get_context_for_frontend( # Pass enabled module codes to templates for conditional rendering context["enabled_modules"] = enabled_module_codes + # Pass frontend type to templates (used by JS for logging, dev toolbar, etc.) + context["frontend_type"] = frontend_type.value + # For storefront, build nav menu structure from module declarations if frontend_type == FrontendType.STOREFRONT: from app.modules.core.services.menu_discovery_service import ( diff --git a/app/templates/admin/base.html b/app/templates/admin/base.html index 1f739768..4bf3dba9 100644 --- a/app/templates/admin/base.html +++ b/app/templates/admin/base.html @@ -100,6 +100,9 @@ + + + diff --git a/app/templates/merchant/base.html b/app/templates/merchant/base.html index 2559a09b..d0f83593 100644 --- a/app/templates/merchant/base.html +++ b/app/templates/merchant/base.html @@ -50,6 +50,9 @@ + + + diff --git a/app/templates/store/base.html b/app/templates/store/base.html index 39157bbd..cc436ac9 100644 --- a/app/templates/store/base.html +++ b/app/templates/store/base.html @@ -54,6 +54,9 @@ + + + diff --git a/app/templates/storefront/base.html b/app/templates/storefront/base.html index 2e5f38f9..c626d3ef 100644 --- a/app/templates/storefront/base.html +++ b/app/templates/storefront/base.html @@ -349,6 +349,9 @@ {# JavaScript Loading Order (CRITICAL - must be in this order) #} + {# 0. Frontend type (server-injected, used by log-config and dev-toolbar) #} + + {# 1. Log Configuration (must load first) #} diff --git a/static/shared/js/dev-toolbar.js b/static/shared/js/dev-toolbar.js index 9f389c38..7224794e 100644 --- a/static/shared/js/dev-toolbar.js +++ b/static/shared/js/dev-toolbar.js @@ -286,11 +286,11 @@ } function detectFrontend() { + // Prefer server-injected value (set in base templates) + if (window.FRONTEND_TYPE) return window.FRONTEND_TYPE; + + // Fallback for pages without base template (e.g., API docs) var path = window.location.pathname; - if (path.startsWith('/store/') || path === '/store') return 'store'; - if (path.startsWith('/admin/') || path === '/admin') return 'admin'; - if (path.indexOf('/merchants/') !== -1) return 'merchant'; - if (path.indexOf('/storefront/') !== -1) return 'storefront'; if (path.startsWith('/api/')) return 'api'; return 'unknown'; } diff --git a/static/shared/js/log-config.js b/static/shared/js/log-config.js index 0d426337..ba91107c 100644 --- a/static/shared/js/log-config.js +++ b/static/shared/js/log-config.js @@ -43,14 +43,11 @@ const LOG_LEVELS = { /** * Detect which frontend we're in based on URL path - * @returns {string} 'admin' | 'store' | 'shop' | 'unknown' + * @returns {string} 'admin' | 'store' | 'merchant' | 'storefront' | 'unknown' */ function detectFrontend() { - const path = window.location.pathname; - - if (path.startsWith('/admin')) return 'admin'; - if (path.startsWith('/store')) return 'store'; - if (path.startsWith('/shop')) return 'shop'; + // Prefer server-injected value (set in base templates before this script loads) + if (window.FRONTEND_TYPE) return window.FRONTEND_TYPE; return 'unknown'; } @@ -94,9 +91,13 @@ const DEFAULT_LOG_LEVELS = { development: LOG_LEVELS.DEBUG, production: LOG_LEVELS.INFO // Stores might need more logging }, - shop: { + merchant: { development: LOG_LEVELS.DEBUG, - production: LOG_LEVELS.ERROR // Shop frontend: minimal logging in production + production: LOG_LEVELS.INFO // Merchant portal: same as store + }, + storefront: { + development: LOG_LEVELS.DEBUG, + production: LOG_LEVELS.ERROR // Storefront: minimal logging in production }, unknown: { development: LOG_LEVELS.DEBUG, @@ -275,10 +276,10 @@ const storeLoggers = { }; // ============================================================================ -// PRE-CONFIGURED LOGGERS FOR SHOP FRONTEND +// PRE-CONFIGURED LOGGERS FOR STOREFRONT // ============================================================================ -const shopLoggers = { +const storefrontLoggers = { // Product browsing catalog: createLogger('CATALOG', ACTIVE_LOG_LEVEL), product: createLogger('PRODUCT', ACTIVE_LOG_LEVEL), @@ -309,8 +310,10 @@ function getLoggers() { return adminLoggers; case 'store': return storeLoggers; - case 'shop': - return shopLoggers; + case 'merchant': + return storeLoggers; // Merchant portal reuses store logger set + case 'storefront': + return storefrontLoggers; default: return {}; // Empty object, use createLogger instead }