Updated documentation to cover all work completed today: ## Database Setup (docs/getting-started/database-setup.md) - Added data seeding section with all three scripts - Documented inventory creation requirement - Added complete setup workflow - Included common issues and solutions - Added database reset instructions ## New Troubleshooting Guide (docs/troubleshooting/shop-frontend.md) Comprehensive troubleshooting for: ### Cart and Product Issues - Products cannot be added to cart (inventory = 0) - Cart is empty after adding products (session ID issue) - Root causes and solutions with code examples ### Styling and Layout Issues - Pages with no styling (not extending base template) - Images not loading (placeholder SVG implementation) - Detailed before/after examples ### Navigation and Routing Issues - Product detail 404 (duplicate /shop prefix) - Missing /shop/ in links - Breadcrumb navigation patterns ### Landing Page Issues - Vendor root 404 (no landing page) - Breadcrumb home link configuration - Auto-redirect behavior ### Alpine.js Issues - Component data not available (parent init not called) - Product ID undefined (window globals solution) - Debugging tips and console commands All issues encountered today are now documented with: - Clear symptoms - Root cause explanation - How the system works - Step-by-step solutions - Code examples - Verification steps 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
394 lines
9.7 KiB
Markdown
394 lines
9.7 KiB
Markdown
# Shop Frontend Troubleshooting
|
|
|
|
Common issues and solutions for the vendor shop frontend.
|
|
|
|
## Cart and Product Issues
|
|
|
|
### Products Cannot Be Added to Cart
|
|
|
|
**Symptoms:**
|
|
- "Add to Cart" button is disabled
|
|
- No response when clicking "Add to Cart"
|
|
- Console shows `canAddToCart: false`
|
|
|
|
**Root Cause:**
|
|
Products have `available_inventory: 0` because the `inventory` table is empty.
|
|
|
|
**How it Works:**
|
|
- Product's `available_inventory` is a calculated property
|
|
- It sums `quantity - reserved_quantity` from all `inventory_entries`
|
|
- If there are no inventory entries, `available_inventory` = 0
|
|
- The `canAddToCart` check fails when `available_inventory <= 0`
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Create inventory entries for all products
|
|
python scripts/create_inventory.py
|
|
```
|
|
|
|
This script:
|
|
- Finds all products without inventory entries
|
|
- Creates inventory with 100 units in "Main Warehouse"
|
|
- Can be run multiple times (only creates missing entries)
|
|
|
|
**Verify Fix:**
|
|
```python
|
|
# Check a product's inventory
|
|
from app.core.database import SessionLocal
|
|
from models.database.product import Product
|
|
|
|
db = SessionLocal()
|
|
product = db.query(Product).first()
|
|
print(f"Available inventory: {product.available_inventory}")
|
|
# Should show: Available inventory: 100
|
|
```
|
|
|
|
### Cart is Empty After Adding Products
|
|
|
|
**Symptoms:**
|
|
- Success toast appears: "1 item(s) added to cart!"
|
|
- Cart count in header doesn't update
|
|
- Cart page shows 0 items
|
|
- Console shows `session_1234_abc` but API returns empty cart
|
|
|
|
**Root Cause:**
|
|
Session ID not properly initialized in Alpine.js components.
|
|
|
|
**How it Works:**
|
|
- Cart uses session ID stored in localStorage as `cart_session_id`
|
|
- `shopLayoutData()` base component initializes `sessionId` in its `init()` method
|
|
- Child components (product, cart) must call parent `init()` to get `sessionId`
|
|
- If parent init isn't called, `sessionId` is `undefined`
|
|
|
|
**Solution Already Implemented:**
|
|
The product and cart pages now properly call parent init:
|
|
|
|
```javascript
|
|
// In product.html and cart.html
|
|
async init() {
|
|
// Call parent init to set up sessionId
|
|
if (baseData.init) {
|
|
baseData.init.call(this);
|
|
}
|
|
// Now sessionId is available
|
|
await this.loadCart();
|
|
}
|
|
```
|
|
|
|
**Verify Fix:**
|
|
Open browser console and check for:
|
|
```
|
|
🔍 [SHOP] Session ID: session_1763765104510_zc866tt5d
|
|
```
|
|
|
|
If you see `undefined`, the parent init isn't being called properly.
|
|
|
|
## Styling and Layout Issues
|
|
|
|
### Page Has No Styling / CSS 404 Errors
|
|
|
|
**Symptoms:**
|
|
- Page displays with no styling
|
|
- Console shows 404 errors:
|
|
- `/static/css/shared/base.css` not found
|
|
- `/static/css/vendor/vendor.css` not found
|
|
- Page is just plain HTML
|
|
|
|
**Root Cause:**
|
|
Template doesn't extend `shop/base.html` and has hardcoded non-existent CSS references.
|
|
|
|
**How it Works:**
|
|
- All shop pages should extend `shop/base.html`
|
|
- Base template includes Tailwind CSS and shop styles
|
|
- Standalone HTML pages with `<link>` tags won't work
|
|
|
|
**Solution:**
|
|
Refactor template to extend base:
|
|
|
|
```jinja2
|
|
{# BEFORE: Standalone HTML #}
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<link rel="stylesheet" href="/static/css/shared/base.css"> ❌
|
|
</head>
|
|
<body>
|
|
<!-- content -->
|
|
</body>
|
|
</html>
|
|
|
|
{# AFTER: Extends base #}
|
|
{% extends "shop/base.html" %}
|
|
|
|
{% block title %}My Page{% endblock %}
|
|
|
|
{% block alpine_data %}myComponent(){% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- content -->
|
|
{% endblock %}
|
|
```
|
|
|
|
**Templates Already Fixed:**
|
|
- ✅ `shop/product.html` - Refactored to extend base
|
|
- ✅ `shop/cart.html` - Refactored to extend base
|
|
- ✅ `shop/products.html` - Already extends base
|
|
- ✅ `shop/home.html` - Already extends base
|
|
|
|
### Images Not Loading / Placeholder Not Showing
|
|
|
|
**Symptoms:**
|
|
- Product images show broken image icon
|
|
- Console shows 404: `/static/shop/img/placeholder.jpg`
|
|
- OR images point to fake URLs like `https://wizamart.example.com/images/product-1.jpg`
|
|
|
|
**Root Cause:**
|
|
1. Test data has fake image URLs
|
|
2. Placeholder file was `.jpg` but contained SVG content
|
|
|
|
**How it Works:**
|
|
- Products have `marketplace_product.image_link` URLs
|
|
- Template uses fallback: `:src="image || '/static/shop/img/placeholder.svg'"`
|
|
- `@error` handler switches to placeholder when image fails to load
|
|
- Browsers won't render SVG content from `.jpg` files
|
|
|
|
**Solution Already Implemented:**
|
|
- Created proper `/static/shop/img/placeholder.svg`
|
|
- Added `@error` handlers to all image tags:
|
|
|
|
```html
|
|
<img
|
|
:src="product.image_link || '/static/shop/img/placeholder.svg'"
|
|
@error="$el.src = '/static/shop/img/placeholder.svg'"
|
|
alt="Product image"
|
|
>
|
|
```
|
|
|
|
**Update Test Data (Optional):**
|
|
```python
|
|
# Replace fake URLs with real placeholder images
|
|
import sqlite3
|
|
conn = sqlite3.connect('wizamart.db')
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute("""
|
|
UPDATE marketplace_products
|
|
SET image_link = NULL
|
|
WHERE image_link LIKE '%example.com%'
|
|
""")
|
|
conn.commit()
|
|
```
|
|
|
|
## Navigation and Routing Issues
|
|
|
|
### Product Detail Page Returns 404
|
|
|
|
**Symptoms:**
|
|
- Clicking product shows 404 error
|
|
- URL is: `/vendors/wizamart/shop/shop/products/4` (double `/shop/`)
|
|
- Server log shows route not found
|
|
|
|
**Root Cause:**
|
|
Duplicate `/shop` prefix in route definitions when router already has prefix.
|
|
|
|
**How it Works:**
|
|
```python
|
|
# Router is mounted with prefix
|
|
app.include_router(shop_pages.router, prefix="/shop")
|
|
|
|
# Route decorator should NOT repeat the prefix
|
|
@router.get("/products/{id}") # ✅ Correct
|
|
@router.get("/shop/products/{id}") # ❌ Wrong - creates /shop/shop/products/{id}
|
|
```
|
|
|
|
**Solution Already Implemented:**
|
|
All routes in `shop_pages.py` have been fixed to remove duplicate `/shop/` prefix.
|
|
|
|
### Missing `/shop/` in Links
|
|
|
|
**Symptoms:**
|
|
- Links go to `/vendors/wizamart/products` instead of `/vendors/wizamart/shop/products`
|
|
- 404 errors on navigation
|
|
- Footer/header links broken
|
|
|
|
**Root Cause:**
|
|
Template links missing `/shop/` prefix after `{{ base_url }}`.
|
|
|
|
**Solution:**
|
|
```jinja2
|
|
{# WRONG #}
|
|
<a href="{{ base_url }}products">Products</a>
|
|
|
|
{# CORRECT #}
|
|
<a href="{{ base_url }}shop/products">Products</a>
|
|
```
|
|
|
|
**All Templates Fixed:**
|
|
- ✅ `shop/base.html` - Header, footer, navigation
|
|
- ✅ `shop/products.html` - Product links
|
|
- ✅ `shop/product.html` - Breadcrumbs, related products
|
|
- ✅ `shop/cart.html` - Continue shopping, checkout
|
|
- ✅ `shop/errors/404.html` - All fallback links
|
|
|
|
## Landing Page Issues
|
|
|
|
### Vendor Root Shows 404
|
|
|
|
**Symptoms:**
|
|
- `http://localhost:8000/vendors/wizamart/` returns 404
|
|
- `/` path not found
|
|
|
|
**Root Cause:**
|
|
No landing page created for vendor.
|
|
|
|
**How it Works:**
|
|
```python
|
|
# Root handler checks for landing page
|
|
if has_landing_page():
|
|
return render_landing_page()
|
|
else:
|
|
return redirect("/shop/") # Fallback
|
|
```
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Create landing page
|
|
python scripts/create_landing_page.py
|
|
# Choose vendor and template
|
|
```
|
|
|
|
**Or Accept Redirect:**
|
|
The system auto-redirects to `/shop/` if no landing page exists. This is normal behavior.
|
|
|
|
### Breadcrumb "Home" Points to Wrong Place
|
|
|
|
**Symptoms:**
|
|
- Clicking "Home" in breadcrumb goes to shop instead of landing page
|
|
- Want "Home" to point to vendor root (/)
|
|
|
|
**Solution Already Implemented:**
|
|
```jinja2
|
|
{# Breadcrumb Home link points to vendor root #}
|
|
<a href="{{ base_url }}">Home</a>
|
|
|
|
{# Shop homepage link #}
|
|
<a href="{{ base_url }}shop/">Shop</a>
|
|
```
|
|
|
|
Navigation pattern:
|
|
- **Logo click** → `/shop/` (stays in shop for convenience)
|
|
- **Breadcrumb "Home"** → `/` (returns to landing page/root)
|
|
- **Header "Home" link** → `/` (returns to landing page/root)
|
|
|
|
## Alpine.js / JavaScript Issues
|
|
|
|
### Component Data Not Available
|
|
|
|
**Symptoms:**
|
|
- `this.sessionId` is `undefined`
|
|
- `this.cartCount` doesn't work
|
|
- Console: "Cannot read property of undefined"
|
|
|
|
**Root Cause:**
|
|
Child component doesn't call parent `init()` method.
|
|
|
|
**Solution:**
|
|
```javascript
|
|
// Store reference to parent
|
|
const baseData = shopLayoutData();
|
|
|
|
return {
|
|
...baseData,
|
|
|
|
// Child properties
|
|
items: [],
|
|
|
|
// Call parent init
|
|
async init() {
|
|
if (baseData.init) {
|
|
baseData.init.call(this);
|
|
}
|
|
// Now parent properties are initialized
|
|
await this.loadData();
|
|
}
|
|
};
|
|
```
|
|
|
|
### Product ID is Undefined
|
|
|
|
**Symptoms:**
|
|
- API call: `/api/v1/shop/products/undefined`
|
|
- Console: `productId: undefined`
|
|
|
|
**Root Cause:**
|
|
Product ID not accessible from `this.$el.dataset` when `x-data` is on `<html>` tag.
|
|
|
|
**Solution Already Implemented:**
|
|
Pass via window globals:
|
|
|
|
```html
|
|
{% block extra_scripts %}
|
|
<script>
|
|
window.PRODUCT_ID = {{ product_id }};
|
|
window.VENDOR_ID = {{ vendor.id }};
|
|
|
|
Alpine.data('productDetail', () => ({
|
|
productId: window.PRODUCT_ID,
|
|
vendorId: window.VENDOR_ID,
|
|
// ...
|
|
}));
|
|
</script>
|
|
{% endblock %}
|
|
```
|
|
|
|
## Debugging Tips
|
|
|
|
### Enable Verbose Logging
|
|
|
|
```javascript
|
|
// In shop-layout.js, the shopLog is already configured
|
|
// Check browser console for:
|
|
🛒 [SHOP] Shop layout initializing...
|
|
🔍 [SHOP] Session ID: session_xxx
|
|
[SHOP] Adding to cart: {...}
|
|
[SHOP] Cart loaded: 3 items
|
|
```
|
|
|
|
### Check Session ID
|
|
|
|
```javascript
|
|
// In browser console
|
|
localStorage.getItem('cart_session_id')
|
|
// Should show: "session_1763765104510_zc866tt5d"
|
|
```
|
|
|
|
### Inspect Product Data
|
|
|
|
```javascript
|
|
// In browser console on product page
|
|
Alpine.$data(document.querySelector('[x-data]')).product
|
|
// Shows full product object with inventory
|
|
```
|
|
|
|
### Check API Responses
|
|
|
|
In browser Network tab, filter by "shop" and check:
|
|
- GET `/api/v1/shop/products` - Should return products array
|
|
- GET `/api/v1/shop/cart/{session_id}` - Should return cart items
|
|
- POST `/api/v1/shop/cart/{session_id}/items` - Should return success
|
|
|
|
## Getting Help
|
|
|
|
1. Check this guide first
|
|
2. Check browser console for errors
|
|
3. Check server logs for API errors
|
|
4. Verify database has inventory entries
|
|
5. Ensure all templates extend `shop/base.html`
|
|
6. Check that session ID is initialized
|
|
|
|
If still stuck, provide:
|
|
- Browser console output
|
|
- Server log excerpt
|
|
- Network tab showing failed requests
|
|
- Steps to reproduce
|