fix(ui): inject window.FRONTEND_TYPE from server + rename SHOP→STOREFRONT
Server now injects window.FRONTEND_TYPE in all base templates via get_context_for_frontend(). Both log-config.js and dev-toolbar.js read this instead of guessing from URL paths, fixing: - UNKNOWN prefix on merchant pages - Incorrect detection on custom domains/subdomains in prod Also adds frontend_type to login page contexts (admin, merchant, store). Renames all [SHOP] logger prefixes to [STOREFRONT] across 7 files (storefront-layout.js + 6 storefront templates). Adds 'merchant' and 'storefront' to log-config.js frontend detection, log levels, and logger selection. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -208,7 +208,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
async init() {
|
async init() {
|
||||||
console.log('[SHOP] Cart page initializing...');
|
console.log('[STOREFRONT] Cart page initializing...');
|
||||||
|
|
||||||
// Call parent init to set up sessionId
|
// Call parent init to set up sessionId
|
||||||
if (baseData.init) {
|
if (baseData.init) {
|
||||||
@@ -223,17 +223,17 @@ document.addEventListener('alpine:init', () => {
|
|||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
try {
|
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}`);
|
const response = await fetch(`/api/v1/storefront/cart/${this.sessionId}`);
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
this.items = data.items || [];
|
this.items = data.items || [];
|
||||||
this.cartCount = this.totalItems;
|
this.cartCount = this.totalItems;
|
||||||
console.log('[SHOP] Cart loaded:', this.items.length, 'items');
|
console.log('[STOREFRONT] Cart loaded:', this.items.length, 'items');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} 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');
|
this.showToast('Failed to load cart', 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
@@ -249,7 +249,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
this.updating = true;
|
this.updating = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('[SHOP] Updating quantity:', productId, newQuantity);
|
console.log('[STOREFRONT] Updating quantity:', productId, newQuantity);
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`/api/v1/storefront/cart/${this.sessionId}/items/${productId}`,
|
`/api/v1/storefront/cart/${this.sessionId}/items/${productId}`,
|
||||||
{
|
{
|
||||||
@@ -268,7 +268,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
throw new Error('Failed to update quantity');
|
throw new Error('Failed to update quantity');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[SHOP] Update quantity error:', error);
|
console.error('[STOREFRONT] Update quantity error:', error);
|
||||||
this.showToast('Failed to update quantity', 'error');
|
this.showToast('Failed to update quantity', 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.updating = false;
|
this.updating = false;
|
||||||
@@ -280,7 +280,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
this.updating = true;
|
this.updating = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('[SHOP] Removing item:', productId);
|
console.log('[STOREFRONT] Removing item:', productId);
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`/api/v1/storefront/cart/${this.sessionId}/items/${productId}`,
|
`/api/v1/storefront/cart/${this.sessionId}/items/${productId}`,
|
||||||
{
|
{
|
||||||
@@ -295,7 +295,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
throw new Error('Failed to remove item');
|
throw new Error('Failed to remove item');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[SHOP] Remove item error:', error);
|
console.error('[STOREFRONT] Remove item error:', error);
|
||||||
this.showToast('Failed to remove item', 'error');
|
this.showToast('Failed to remove item', 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.updating = false;
|
this.updating = false;
|
||||||
|
|||||||
@@ -187,8 +187,8 @@ document.addEventListener('alpine:init', () => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
console.log('[SHOP] Category page initializing...');
|
console.log('[STOREFRONT] Category page initializing...');
|
||||||
console.log('[SHOP] Category slug:', this.categorySlug);
|
console.log('[STOREFRONT] Category slug:', this.categorySlug);
|
||||||
|
|
||||||
// Convert slug to display name
|
// Convert slug to display name
|
||||||
this.categoryName = this.categorySlug
|
this.categoryName = this.categorySlug
|
||||||
@@ -213,7 +213,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
params.append('sort', this.sortBy);
|
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}`);
|
const response = await fetch(`/api/v1/storefront/products?${params}`);
|
||||||
|
|
||||||
@@ -223,12 +223,12 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
const data = await response.json();
|
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.products = data.products;
|
||||||
this.total = data.total;
|
this.total = data.total;
|
||||||
} catch (error) {
|
} 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');
|
this.showToast('Failed to load products', 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
@@ -243,7 +243,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async addToCart(product) {
|
async addToCart(product) {
|
||||||
console.log('[SHOP] Adding to cart:', product);
|
console.log('[STOREFRONT] Adding to cart:', product);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = `/api/v1/storefront/cart/${this.sessionId}/items`;
|
const url = `/api/v1/storefront/cart/${this.sessionId}/items`;
|
||||||
@@ -262,16 +262,16 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const result = await response.json();
|
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.cartCount += 1;
|
||||||
this.showToast(`${product.marketplace_product.title} added to cart`, 'success');
|
this.showToast(`${product.marketplace_product.title} added to cart`, 'success');
|
||||||
} else {
|
} else {
|
||||||
const error = await response.json();
|
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');
|
this.showToast(error.message || 'Failed to add to cart', 'error');
|
||||||
}
|
}
|
||||||
} catch (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');
|
this.showToast('Failed to add to cart', 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,16 +256,16 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
async init() {
|
async init() {
|
||||||
console.log('[SHOP] Product detail page initializing...');
|
console.log('[STOREFRONT] Product detail page initializing...');
|
||||||
|
|
||||||
// Call parent init to set up sessionId
|
// Call parent init to set up sessionId
|
||||||
if (baseData.init) {
|
if (baseData.init) {
|
||||||
baseData.init.call(this);
|
baseData.init.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[SHOP] Product ID:', this.productId);
|
console.log('[STOREFRONT] Product ID:', this.productId);
|
||||||
console.log('[SHOP] Store ID:', this.storeId);
|
console.log('[STOREFRONT] Store ID:', this.storeId);
|
||||||
console.log('[SHOP] Session ID:', this.sessionId);
|
console.log('[STOREFRONT] Session ID:', this.sessionId);
|
||||||
|
|
||||||
await this.loadProduct();
|
await this.loadProduct();
|
||||||
},
|
},
|
||||||
@@ -275,7 +275,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
try {
|
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}`);
|
const response = await fetch(`/api/v1/storefront/products/${this.productId}`);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -283,7 +283,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.product = await response.json();
|
this.product = await response.json();
|
||||||
console.log('[SHOP] Product loaded:', this.product);
|
console.log('[STOREFRONT] Product loaded:', this.product);
|
||||||
|
|
||||||
// Set default image
|
// Set default image
|
||||||
if (this.product?.marketplace_product?.image_link) {
|
if (this.product?.marketplace_product?.image_link) {
|
||||||
@@ -297,7 +297,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
await this.loadRelatedProducts();
|
await this.loadRelatedProducts();
|
||||||
|
|
||||||
} catch (error) {
|
} 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');
|
this.showToast('Failed to load product', 'error');
|
||||||
// Redirect back to products after error
|
// Redirect back to products after error
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -320,10 +320,10 @@ document.addEventListener('alpine:init', () => {
|
|||||||
.filter(p => p.id !== parseInt(this.productId))
|
.filter(p => p.id !== parseInt(this.productId))
|
||||||
.slice(0, 4);
|
.slice(0, 4);
|
||||||
|
|
||||||
console.log('[SHOP] Loaded related products:', this.relatedProducts.length);
|
console.log('[STOREFRONT] Loaded related products:', this.relatedProducts.length);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} 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
|
// Add to cart
|
||||||
async addToCart() {
|
async addToCart() {
|
||||||
if (!this.canAddToCart) {
|
if (!this.canAddToCart) {
|
||||||
console.warn('[SHOP] Cannot add to cart:', {
|
console.warn('[STOREFRONT] Cannot add to cart:', {
|
||||||
canAddToCart: this.canAddToCart,
|
canAddToCart: this.canAddToCart,
|
||||||
isActive: this.product?.is_active,
|
isActive: this.product?.is_active,
|
||||||
inventory: this.product?.available_inventory,
|
inventory: this.product?.available_inventory,
|
||||||
@@ -374,7 +374,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
quantity: this.quantity
|
quantity: this.quantity
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('[SHOP] Adding to cart:', {
|
console.log('[STOREFRONT] Adding to cart:', {
|
||||||
url,
|
url,
|
||||||
sessionId: this.sessionId,
|
sessionId: this.sessionId,
|
||||||
productId: this.productId,
|
productId: this.productId,
|
||||||
@@ -390,14 +390,14 @@ document.addEventListener('alpine:init', () => {
|
|||||||
body: JSON.stringify(payload)
|
body: JSON.stringify(payload)
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('[SHOP] Add to cart response:', {
|
console.log('[STOREFRONT] Add to cart response:', {
|
||||||
status: response.status,
|
status: response.status,
|
||||||
ok: response.ok
|
ok: response.ok
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const result = await response.json();
|
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.cartCount += this.quantity;
|
||||||
this.showToast(
|
this.showToast(
|
||||||
@@ -409,11 +409,11 @@ document.addEventListener('alpine:init', () => {
|
|||||||
this.quantity = this.product?.min_quantity || 1;
|
this.quantity = this.product?.min_quantity || 1;
|
||||||
} else {
|
} else {
|
||||||
const error = await response.json();
|
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');
|
throw new Error(error.detail || 'Failed to add to cart');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} 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');
|
this.showToast(error.message || 'Failed to add to cart', 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.addingToCart = false;
|
this.addingToCart = false;
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
console.log('[SHOP] Products page initializing...');
|
console.log('[STOREFRONT] Products page initializing...');
|
||||||
await this.loadProducts();
|
await this.loadProducts();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
params.append('search', this.filters.search);
|
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}`);
|
const response = await fetch(`/api/v1/storefront/products?${params}`);
|
||||||
|
|
||||||
@@ -188,12 +188,12 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
const data = await response.json();
|
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.products = data.products;
|
||||||
this.pagination.total = data.total;
|
this.pagination.total = data.total;
|
||||||
} catch (error) {
|
} 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');
|
this.showToast('Failed to load products', 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
@@ -208,7 +208,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
// formatPrice is inherited from storefrontLayoutData() via spread operator
|
// formatPrice is inherited from storefrontLayoutData() via spread operator
|
||||||
|
|
||||||
async addToCart(product) {
|
async addToCart(product) {
|
||||||
console.log('[SHOP] Adding to cart:', product);
|
console.log('[STOREFRONT] Adding to cart:', product);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = `/api/v1/storefront/cart/${this.sessionId}/items`;
|
const url = `/api/v1/storefront/cart/${this.sessionId}/items`;
|
||||||
@@ -227,16 +227,16 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const result = await response.json();
|
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.cartCount += 1;
|
||||||
this.showToast(`${product.marketplace_product.title} added to cart`, 'success');
|
this.showToast(`${product.marketplace_product.title} added to cart`, 'success');
|
||||||
} else {
|
} else {
|
||||||
const error = await response.json();
|
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');
|
this.showToast(error.message || 'Failed to add to cart', 'error');
|
||||||
}
|
}
|
||||||
} catch (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');
|
this.showToast('Failed to add to cart', 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
console.log('[SHOP] Search page initializing...');
|
console.log('[STOREFRONT] Search page initializing...');
|
||||||
|
|
||||||
// Check for query parameter in URL
|
// Check for query parameter in URL
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
@@ -254,7 +254,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
limit: this.perPage
|
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}`);
|
const response = await fetch(`/api/v1/storefront/products/search?${params}`);
|
||||||
|
|
||||||
@@ -264,12 +264,12 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
const data = await response.json();
|
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.products = data.products;
|
||||||
this.total = data.total;
|
this.total = data.total;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[SHOP] Search failed:', error);
|
console.error('[STOREFRONT] Search failed:', error);
|
||||||
this.showToast('Search failed. Please try again.', 'error');
|
this.showToast('Search failed. Please try again.', 'error');
|
||||||
this.products = [];
|
this.products = [];
|
||||||
this.total = 0;
|
this.total = 0;
|
||||||
@@ -289,7 +289,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async addToCart(product) {
|
async addToCart(product) {
|
||||||
console.log('[SHOP] Adding to cart:', product);
|
console.log('[STOREFRONT] Adding to cart:', product);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = `/api/v1/storefront/cart/${this.sessionId}/items`;
|
const url = `/api/v1/storefront/cart/${this.sessionId}/items`;
|
||||||
@@ -308,16 +308,16 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const result = await response.json();
|
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.cartCount += 1;
|
||||||
this.showToast(`${product.marketplace_product?.title || 'Product'} added to cart`, 'success');
|
this.showToast(`${product.marketplace_product?.title || 'Product'} added to cart`, 'success');
|
||||||
} else {
|
} else {
|
||||||
const error = await response.json();
|
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');
|
this.showToast(error.message || 'Failed to add to cart', 'error');
|
||||||
}
|
}
|
||||||
} catch (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');
|
this.showToast('Failed to add to cart', 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
isLoggedIn: false,
|
isLoggedIn: false,
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
console.log('[SHOP] Wishlist page initializing...');
|
console.log('[STOREFRONT] Wishlist page initializing...');
|
||||||
|
|
||||||
// Check if user is logged in
|
// Check if user is logged in
|
||||||
this.isLoggedIn = await this.checkLoginStatus();
|
this.isLoggedIn = await this.checkLoginStatus();
|
||||||
@@ -168,7 +168,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('[SHOP] Loading wishlist...');
|
console.log('[STOREFRONT] Loading wishlist...');
|
||||||
|
|
||||||
const response = await fetch('/api/v1/storefront/wishlist');
|
const response = await fetch('/api/v1/storefront/wishlist');
|
||||||
|
|
||||||
@@ -182,11 +182,11 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
const data = await response.json();
|
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 || [];
|
this.items = data.items || [];
|
||||||
} catch (error) {
|
} 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');
|
this.showToast('Failed to load wishlist', 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
@@ -195,7 +195,7 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
async removeFromWishlist(item) {
|
async removeFromWishlist(item) {
|
||||||
try {
|
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}`, {
|
const response = await fetch(`/api/v1/storefront/wishlist/${item.id}`, {
|
||||||
method: 'DELETE'
|
method: 'DELETE'
|
||||||
@@ -208,13 +208,13 @@ document.addEventListener('alpine:init', () => {
|
|||||||
throw new Error('Failed to remove from wishlist');
|
throw new Error('Failed to remove from wishlist');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} 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');
|
this.showToast('Failed to remove from wishlist', 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async addToCart(product) {
|
async addToCart(product) {
|
||||||
console.log('[SHOP] Adding to cart:', product);
|
console.log('[STOREFRONT] Adding to cart:', product);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = `/api/v1/storefront/cart/${this.sessionId}/items`;
|
const url = `/api/v1/storefront/cart/${this.sessionId}/items`;
|
||||||
@@ -233,16 +233,16 @@ document.addEventListener('alpine:init', () => {
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const result = await response.json();
|
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.cartCount += 1;
|
||||||
this.showToast(`${product.marketplace_product?.title || 'Product'} added to cart`, 'success');
|
this.showToast(`${product.marketplace_product?.title || 'Product'} added to cart`, 'success');
|
||||||
} else {
|
} else {
|
||||||
const error = await response.json();
|
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');
|
this.showToast(error.message || 'Failed to add to cart', 'error');
|
||||||
}
|
}
|
||||||
} catch (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');
|
this.showToast('Failed to add to cart', 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ async def admin_login_page(
|
|||||||
context = {
|
context = {
|
||||||
"request": request,
|
"request": request,
|
||||||
"current_language": language,
|
"current_language": language,
|
||||||
|
"frontend_type": "admin",
|
||||||
**get_jinja2_globals(language),
|
**get_jinja2_globals(language),
|
||||||
}
|
}
|
||||||
return templates.TemplateResponse("tenancy/admin/login.html", context)
|
return templates.TemplateResponse("tenancy/admin/login.html", context)
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ async def merchant_login_page(
|
|||||||
context = {
|
context = {
|
||||||
"request": request,
|
"request": request,
|
||||||
"current_language": language,
|
"current_language": language,
|
||||||
|
"frontend_type": "merchant",
|
||||||
**get_jinja2_globals(language),
|
**get_jinja2_globals(language),
|
||||||
}
|
}
|
||||||
return templates.TemplateResponse("tenancy/merchant/login.html", context)
|
return templates.TemplateResponse("tenancy/merchant/login.html", context)
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
* Works with store-specific themes
|
* Works with store-specific themes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const shopLog = {
|
const shopLog = window.LogConfig?.createLogger('STOREFRONT') || {
|
||||||
info: (...args) => console.info('🛒 [SHOP]', ...args),
|
info: (...args) => console.info('🛒 [STOREFRONT]', ...args),
|
||||||
warn: (...args) => console.warn('⚠️ [SHOP]', ...args),
|
warn: (...args) => console.warn('⚠️ [STOREFRONT]', ...args),
|
||||||
error: (...args) => console.error('❌ [SHOP]', ...args),
|
error: (...args) => console.error('❌ [STOREFRONT]', ...args),
|
||||||
debug: (...args) => console.log('🔍 [SHOP]', ...args)
|
debug: (...args) => console.log('🔍 [STOREFRONT]', ...args)
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -149,6 +149,9 @@ def get_context_for_frontend(
|
|||||||
# Pass enabled module codes to templates for conditional rendering
|
# Pass enabled module codes to templates for conditional rendering
|
||||||
context["enabled_modules"] = enabled_module_codes
|
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
|
# For storefront, build nav menu structure from module declarations
|
||||||
if frontend_type == FrontendType.STOREFRONT:
|
if frontend_type == FrontendType.STOREFRONT:
|
||||||
from app.modules.core.services.menu_discovery_service import (
|
from app.modules.core.services.menu_discovery_service import (
|
||||||
|
|||||||
@@ -100,6 +100,9 @@
|
|||||||
|
|
||||||
<!-- Core Scripts - ORDER MATTERS! -->
|
<!-- Core Scripts - ORDER MATTERS! -->
|
||||||
|
|
||||||
|
<!-- 0. Frontend type (server-injected, used by log-config and dev-toolbar) -->
|
||||||
|
<script>window.FRONTEND_TYPE = '{{ frontend_type | default("admin") }}';</script>
|
||||||
|
|
||||||
<!-- 1. FIRST: Log Configuration -->
|
<!-- 1. FIRST: Log Configuration -->
|
||||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,9 @@
|
|||||||
|
|
||||||
<!-- Core Scripts - ORDER MATTERS! -->
|
<!-- Core Scripts - ORDER MATTERS! -->
|
||||||
|
|
||||||
|
<!-- 0. Frontend type (server-injected, used by log-config and dev-toolbar) -->
|
||||||
|
<script>window.FRONTEND_TYPE = '{{ frontend_type | default("merchant") }}';</script>
|
||||||
|
|
||||||
<!-- 1. FIRST: Log Configuration -->
|
<!-- 1. FIRST: Log Configuration -->
|
||||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,9 @@
|
|||||||
|
|
||||||
<!-- Core Scripts - ORDER MATTERS! -->
|
<!-- Core Scripts - ORDER MATTERS! -->
|
||||||
|
|
||||||
|
<!-- 0. Frontend type (server-injected, used by log-config and dev-toolbar) -->
|
||||||
|
<script>window.FRONTEND_TYPE = '{{ frontend_type | default("store") }}';</script>
|
||||||
|
|
||||||
<!-- 1. FIRST: Log Configuration -->
|
<!-- 1. FIRST: Log Configuration -->
|
||||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||||
|
|
||||||
|
|||||||
@@ -349,6 +349,9 @@
|
|||||||
|
|
||||||
{# JavaScript Loading Order (CRITICAL - must be in this order) #}
|
{# JavaScript Loading Order (CRITICAL - must be in this order) #}
|
||||||
|
|
||||||
|
{# 0. Frontend type (server-injected, used by log-config and dev-toolbar) #}
|
||||||
|
<script>window.FRONTEND_TYPE = '{{ frontend_type | default("storefront") }}';</script>
|
||||||
|
|
||||||
{# 1. Log Configuration (must load first) #}
|
{# 1. Log Configuration (must load first) #}
|
||||||
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
<script defer src="{{ url_for('static', path='shared/js/log-config.js') }}"></script>
|
||||||
|
|
||||||
|
|||||||
@@ -286,11 +286,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function detectFrontend() {
|
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;
|
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';
|
if (path.startsWith('/api/')) return 'api';
|
||||||
return 'unknown';
|
return 'unknown';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,14 +43,11 @@ const LOG_LEVELS = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect which frontend we're in based on URL path
|
* 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() {
|
function detectFrontend() {
|
||||||
const path = window.location.pathname;
|
// Prefer server-injected value (set in base templates before this script loads)
|
||||||
|
if (window.FRONTEND_TYPE) return window.FRONTEND_TYPE;
|
||||||
if (path.startsWith('/admin')) return 'admin';
|
|
||||||
if (path.startsWith('/store')) return 'store';
|
|
||||||
if (path.startsWith('/shop')) return 'shop';
|
|
||||||
|
|
||||||
return 'unknown';
|
return 'unknown';
|
||||||
}
|
}
|
||||||
@@ -94,9 +91,13 @@ const DEFAULT_LOG_LEVELS = {
|
|||||||
development: LOG_LEVELS.DEBUG,
|
development: LOG_LEVELS.DEBUG,
|
||||||
production: LOG_LEVELS.INFO // Stores might need more logging
|
production: LOG_LEVELS.INFO // Stores might need more logging
|
||||||
},
|
},
|
||||||
shop: {
|
merchant: {
|
||||||
development: LOG_LEVELS.DEBUG,
|
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: {
|
unknown: {
|
||||||
development: LOG_LEVELS.DEBUG,
|
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
|
// Product browsing
|
||||||
catalog: createLogger('CATALOG', ACTIVE_LOG_LEVEL),
|
catalog: createLogger('CATALOG', ACTIVE_LOG_LEVEL),
|
||||||
product: createLogger('PRODUCT', ACTIVE_LOG_LEVEL),
|
product: createLogger('PRODUCT', ACTIVE_LOG_LEVEL),
|
||||||
@@ -309,8 +310,10 @@ function getLoggers() {
|
|||||||
return adminLoggers;
|
return adminLoggers;
|
||||||
case 'store':
|
case 'store':
|
||||||
return storeLoggers;
|
return storeLoggers;
|
||||||
case 'shop':
|
case 'merchant':
|
||||||
return shopLoggers;
|
return storeLoggers; // Merchant portal reuses store logger set
|
||||||
|
case 'storefront':
|
||||||
|
return storefrontLoggers;
|
||||||
default:
|
default:
|
||||||
return {}; // Empty object, use createLogger instead
|
return {}; // Empty object, use createLogger instead
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user