From b7bf505a619f38d0221d1c7ab2ae6dc95d086820 Mon Sep 17 00:00:00 2001
From: Samir Boulahtit Add some products to get started!
Home
-
+
Products
-
+
About
-
+
Contact
@@ -106,7 +106,7 @@
{# Cart #}
-
+
๐ Shopping Cart
@@ -35,7 +35,7 @@
Your cart is empty
+ {{ vendor.tagline }} +
+ {% endif %} + + {# CTA Button #} ++ Browse our complete catalog +
+ + + {% if header_pages %} + {% for page in header_pages[:2] %} + ++ {{ page.meta_description or 'Learn more' }} +
+ + {% endfor %} + {% else %} + ++ Learn about our story +
+ + + ++ Get in touch with us +
+ + {% endif %} ++ {{ vendor.tagline }} +
+ {% endif %} + + {% if vendor.description %} ++ {{ vendor.description }} +
+ {% endif %} + + + + {# Stats/Badges #} ++ Your Shopping Destination +
++ Everything you need for an exceptional shopping experience +
++ Top-tier products carefully selected for you +
++ Quick delivery right to your door +
++ Competitive prices and great deals +
++ Always here to help you +
++ Browse our complete collection +
++ {{ page.meta_description or 'Learn more about us' }} +
++ Learn about our story and mission +
++ Get in touch with our team +
++ Join thousands of satisfied customers today +
+ + View All Products ++ {{ vendor.description }} +
+ {% endif %} + + {# Single CTA #} + + + {# Optional Links Below #} + {% if header_pages or footer_pages %} ++ {% if vendor.description %}{{ vendor.description }}{% else %}Experience excellence in every purchase{% endif %} +
++ Carefully curated selection of premium items +
++ Quick and reliable shipping to your doorstep +
++ Competitive pricing with great value +
++ Explore our collection and find what you're looking for +
+ + Browse Products +Your custom HTML content here...
", + template="modern", # Choose: default, minimal, modern, full + is_published=True, + show_in_footer=False, + show_in_header=False +) +db.add(landing_page) +db.commit() +``` + +### Step 2: Choose Template + +Set the `template` field to one of: +- `"default"` - Clean professional layout +- `"minimal"` - Ultra-simple centered design +- `"modern"` - Full-screen with animations +- `"full"` - Maximum features and sections + +### Step 3: Add Content (Optional) + +The `content` field supports HTML. This appears in a dedicated section on all templates: + +```html +We've been serving customers since 2020...
+...
", + "template": "modern", + "is_published": true +} +``` + +## Testing + +### Test Landing Page +1. Create a landing page via database or admin panel +2. Access vendor root URL: + - Path-based: `http://localhost:8000/vendors/wizamart/` + - Subdomain: `https://wizamart.platform.com/` +3. Should see your custom landing page + +### Test Fallback +1. Delete or unpublish landing page +2. Access vendor root URL +3. Should redirect to `/shop/` + +## Customization Guide + +### Adding a New Template + +1. Create new template file: + ``` + app/templates/vendor/landing-{name}.html + ``` + +2. Extend shop base: + ```jinja2 + {% extends "shop/base.html" %} + ``` + +3. Use template variables as needed + +4. Update `page.template` to `{name}` in database + +### Modifying Existing Templates + +Templates are in: +``` +app/templates/vendor/ +โโโ landing-default.html (Clean professional) +โโโ landing-minimal.html (Ultra-simple) +โโโ landing-modern.html (Full-screen hero) +โโโ landing-full.html (Maximum features) +``` + +Edit directly and changes apply immediately (no rebuild needed). + +## Best Practices + +1. **Choose Template Based on Content**: + - Minimal: Little content, single CTA + - Default: Moderate content, professional + - Modern: Tech/modern brands, animated + - Full: Lots of content, established brand + +2. **Keep Content Concise**: Landing pages should be scannable + +3. **Strong CTAs**: Always link to `/shop/` for e-commerce + +4. **Use Theme Colors**: Templates automatically use vendor theme + +5. **Test Responsiveness**: All templates are mobile-friendly + +6. **SEO**: Fill in `meta_description` for better search results + +## Examples + +### Example 1: Simple Store +```python +ContentPage( + vendor_id=1, + slug="landing", + title="Welcome to TechStore", + content="Your one-stop shop for electronics
", + template="default", + is_published=True +) +``` + +### Example 2: Portfolio Site +```python +ContentPage( + vendor_id=2, + slug="landing", + title="John's Artwork", + content="Handcrafted pieces since 2015
", + template="minimal", + is_published=True +) +``` + +### Example 3: Modern Brand +```python +ContentPage( + vendor_id=3, + slug="landing", + title="FutureWear - Style Redefined", + content="Innovation meets fashion...
", + template="modern", + is_published=True +) +``` + +## Troubleshooting + +### Landing Page Not Showing +- Check `is_published=True` +- Verify `slug="landing"` or `slug="home"` +- Check vendor ID matches +- Verify template field is valid + +### Wrong Template Rendering +- Check `template` field value +- Ensure template file exists at `app/templates/vendor/landing-{template}.html` +- Check for typos in template name + +### Theme Colors Not Applied +- Verify vendor has theme configured +- Check CSS variables in template: `var(--color-primary)` +- Inspect theme object in template context + +## Future Enhancements + +**Phase 2: Section Builder** (Future) +- Drag-and-drop section components +- Hero, Features, Testimonials, Gallery sections +- Per-section customization +- Visual page builder interface + +This will allow vendors to build completely custom layouts without template limitations. diff --git a/docs/frontend/shop/architecture.md b/docs/frontend/shop/architecture.md index ac204c8f..dc4ce5ab 100644 --- a/docs/frontend/shop/architecture.md +++ b/docs/frontend/shop/architecture.md @@ -108,7 +108,21 @@ Layer 1: ROUTES (FastAPI) Purpose: Vendor Detection + Template Rendering Location: app/routes/shop_pages.py -Example: +โ ๏ธ ROUTE REGISTRATION (main.py): +The shop router is mounted at TWO prefixes to support both access methods: + + # main.py + app.include_router(shop_pages.router, prefix="/shop", ...) # Domain/subdomain + app.include_router(shop_pages.router, prefix="/vendors/{vendor_code}/shop", ...) # Path-based + +This means routes defined WITHOUT /shop prefix in shop_pages.py: + @router.get("/products") โ /shop/products OR /vendors/{code}/shop/products + +โ COMMON MISTAKE: Don't add /shop prefix in route definitions! + @router.get("/shop/products") โ WRONG - creates /shop/shop/products + @router.get("/products") โ CORRECT - creates /shop/products + +Example Route Handler: @router.get("/", response_class=HTMLResponse, include_in_schema=False) @router.get("/products", response_class=HTMLResponse, include_in_schema=False) async def shop_products_page(request: Request): @@ -164,31 +178,31 @@ Responsibilities: The shop frontend supports THREE access methods: 1. **Custom Domain** (Production) - URL: https://customdomain.com/products + URL: https://customdomain.com/shop/products - Vendor has their own domain - base_url = "/" - - Links: /products, /about, /contact + - Links: /shop/products, /shop/about, /shop/contact 2. **Subdomain** (Production) - URL: https://wizamart.letzshop.com/products + URL: https://wizamart.letzshop.com/shop/products - Vendor uses platform subdomain - base_url = "/" - - Links: /products, /about, /contact + - Links: /shop/products, /shop/about, /shop/contact 3. **Path-Based** (Development/Testing) - URL: http://localhost:8000/vendor/wizamart/products + URL: http://localhost:8000/vendors/wizamart/shop/products - Vendor accessed via path prefix - - base_url = "/vendor/wizamart/" - - Links: /vendor/wizamart/products, /vendor/wizamart/about + - base_url = "/vendors/wizamart/" + - Links: /vendors/wizamart/shop/products, /vendors/wizamart/shop/about -โ ๏ธ CRITICAL: All template links MUST use {{ base_url }} prefix +โ ๏ธ CRITICAL: All template links MUST use {{ base_url }}shop/ prefix Example: โ BAD: Products - โ GOOD: Products + โ BAD: Products + โ GOOD: Products - โ BAD: Contact - โ GOOD: Contact +Note: The router is mounted at /shop prefix in main.py, so all links need shop/ after base_url How It Works: 1. VendorContextMiddleware detects access method diff --git a/docs/frontend/shop/navigation-flow.md b/docs/frontend/shop/navigation-flow.md new file mode 100644 index 00000000..81d49d2f --- /dev/null +++ b/docs/frontend/shop/navigation-flow.md @@ -0,0 +1,318 @@ +# Shop Navigation Flow + +Complete guide to navigation structure and URL hierarchy with landing pages. + +## URL Hierarchy + +``` +/ (Vendor Root) โ Landing Page (if exists) OR redirect to /shop/ +โโโ /shop/ โ E-commerce Homepage (Product Catalog) +โ โโโ /shop/products โ Product Catalog (same as /shop/) +โ โโโ /shop/products/{id} โ Product Detail Page +โ โโโ /shop/cart โ Shopping Cart +โ โโโ /shop/checkout โ Checkout Process +โ โโโ /shop/account/login โ Customer Login +โ โโโ /shop/account/register โ Customer Registration +โ โโโ /shop/account/dashboard โ Customer Dashboard (auth required) +โ โโโ /shop/about โ CMS Content Page +โ โโโ /shop/contact โ CMS Content Page +โ โโโ /shop/{slug} โ Other CMS Pages +``` + +## Navigation Patterns + +### Pattern 1: With Landing Page (Recommended) + +**URL Structure:** +``` +customdomain.com/ โ Landing Page (marketing/brand) +customdomain.com/shop/ โ E-commerce Shop +customdomain.com/shop/products โ Product Catalog +``` + +**Navigation Flow:** +1. User visits vendor domain โ **Landing Page** +2. Clicks "Shop Now" โ **/shop/** (product catalog) +3. Clicks "Home" in breadcrumb โ **/** (back to landing page) +4. Clicks logo โ **/** (back to landing page) + +**Breadcrumb Example (on Products page):** +``` +Home > Products + โ + / (Landing Page) +``` + +### Pattern 2: Without Landing Page (Auto-Redirect) + +**URL Structure:** +``` +customdomain.com/ โ Redirects to /shop/ +customdomain.com/shop/ โ E-commerce Shop +customdomain.com/shop/products โ Product Catalog +``` + +**Navigation Flow:** +1. User visits vendor domain โ **Redirects to /shop/** +2. User browses shop +3. Clicks "Home" in breadcrumb โ **/** (redirects to /shop/) +4. Clicks logo โ **/** (redirects to /shop/) + +**Breadcrumb Example (on Products page):** +``` +Home > Products + โ + / โ /shop/ (redirects) +``` + +## Link References + +### Base URL Calculation + +The `base_url` variable is calculated in `shop_pages.py:get_shop_context()`: + +```python +# For domain/subdomain access +base_url = "/" +# Result: /shop/products, /shop/cart, etc. + +# For path-based access +base_url = "/vendors/wizamart/" +# Result: /vendors/wizamart/shop/products, /vendors/wizamart/shop/cart, etc. +``` + +### Template Links + +**Logo / Home Link (Header):** +```jinja2 +{# Points to vendor root (landing page or shop) #} +{{ vendor.name }} +``` + +**Breadcrumb Home Link:** +```jinja2 +{# Points to vendor root (landing page) #} +Home +``` + +**Shop Links:** +```jinja2 +{# All shop pages include /shop/ prefix #} +Products +Cart +Checkout +``` + +**CMS Page Links:** +```jinja2 +{# CMS pages are under /shop/ #} +About +Contact +{{ page.title }} +``` + +## Complete URL Examples + +### Path-Based Access (Development) + +``` +http://localhost:8000/vendors/wizamart/ +โโโ / (root) โ Landing Page OR redirect to shop +โโโ /shop/ โ Shop Homepage +โโโ /shop/products โ Product Catalog +โโโ /shop/products/4 โ Product Detail +โโโ /shop/cart โ Shopping Cart +โโโ /shop/checkout โ Checkout +โโโ /shop/account/login โ Customer Login +โโโ /shop/about โ About Page (CMS) +โโโ /shop/contact โ Contact Page (CMS) +``` + +### Subdomain Access (Production) + +``` +https://wizamart.platform.com/ +โโโ / (root) โ Landing Page OR redirect to shop +โโโ /shop/ โ Shop Homepage +โโโ /shop/products โ Product Catalog +โโโ /shop/products/4 โ Product Detail +โโโ /shop/cart โ Shopping Cart +โโโ /shop/checkout โ Checkout +โโโ /shop/account/login โ Customer Login +โโโ /shop/about โ About Page (CMS) +โโโ /shop/contact โ Contact Page (CMS) +``` + +### Custom Domain Access (Production) + +``` +https://customdomain.com/ +โโโ / (root) โ Landing Page OR redirect to shop +โโโ /shop/ โ Shop Homepage +โโโ /shop/products โ Product Catalog +โโโ /shop/products/4 โ Product Detail +โโโ /shop/cart โ Shopping Cart +โโโ /shop/checkout โ Checkout +โโโ /shop/account/login โ Customer Login +โโโ /shop/about โ About Page (CMS) +โโโ /shop/contact โ Contact Page (CMS) +``` + +## User Journeys + +### Journey 1: First-Time Visitor (With Landing Page) + +1. Visit `customdomain.com/` โ **Landing Page** + - Sees brand story, features, CTA +2. Clicks "Shop Now" โ `/shop/` โ **Product Catalog** + - Browses products +3. Clicks product โ `/shop/products/4` โ **Product Detail** + - Views product +4. Clicks "Home" in breadcrumb โ `/` โ **Back to Landing Page** +5. Clicks logo โ `/` โ **Back to Landing Page** + +### Journey 2: Returning Customer (Direct to Shop) + +1. Visit `customdomain.com/shop/` โ **Product Catalog** + - Already knows the brand, goes straight to shop +2. Adds to cart โ `/shop/cart` โ **Shopping Cart** +3. Checkout โ `/shop/checkout` โ **Checkout** +4. Clicks "Home" โ `/` โ **Landing Page** (brand homepage) + +### Journey 3: Customer Account Management + +1. Visit `customdomain.com/shop/account/login` โ **Login** +2. After login โ `/shop/account/dashboard` โ **Dashboard** +3. View orders โ `/shop/account/orders` โ **Order History** +4. Clicks logo โ `/` โ **Back to Landing Page** + +## Navigation Components + +### Header Navigation (base.html) + +```jinja2 +{# Logo - always points to vendor root #} + +{vendor.description or 'Your trusted shopping destination for quality products.'}
+ +We've been serving customers since 2020, providing exceptional products and service. + Our mission is to make online shopping easy, enjoyable, and reliable.
+ """, + content_format="html", + template=template, + meta_description=f"Shop at {vendor.name} for quality products and great service", + is_published=True, + published_at=datetime.now(timezone.utc), + show_in_footer=False, + show_in_header=False, + display_order=0 + ) + + db.add(landing_page) + db.commit() + db.refresh(landing_page) + + print(f"โ Created landing page (ID: {landing_page.id})") + print(f" Template: {template}") + print(f" Title: {landing_page.title}") + + # Print access URLs + print("\n๐ Access your landing page at:") + print(f" Path-based: http://localhost:8000/vendors/{vendor.subdomain}/") + print(f" Shop page: http://localhost:8000/vendors/{vendor.subdomain}/shop/") + + return True + + except Exception as e: + print(f"โ Error: {e}") + db.rollback() + return False + finally: + db.close() + + +def list_vendors(): + """List all vendors in the system.""" + db: Session = SessionLocal() + + try: + vendors = db.query(Vendor).filter(Vendor.is_active == True).all() + + if not vendors: + print("โ No active vendors found!") + return + + print("\n๐ Active Vendors:") + print("=" * 60) + for vendor in vendors: + print(f" โข {vendor.name}") + print(f" Subdomain: {vendor.subdomain}") + print(f" Code: {vendor.vendor_code}") + + # Check if has landing page + landing = db.query(ContentPage).filter( + ContentPage.vendor_id == vendor.id, + ContentPage.slug == "landing" + ).first() + + if landing: + print(f" Landing Page: โ ({landing.template})") + else: + print(f" Landing Page: โ None") + print() + + finally: + db.close() + + +def show_templates(): + """Show available templates.""" + print("\n๐จ Available Templates:") + print("=" * 60) + + templates = [ + ("default", "Clean professional layout with 3-column quick links"), + ("minimal", "Ultra-simple centered design with single CTA"), + ("modern", "Full-screen hero with animations and features"), + ("full", "Maximum features with split-screen hero and stats") + ] + + for name, desc in templates: + print(f" โข {name:<10} - {desc}") + print() + + +if __name__ == "__main__": + print("\n" + "=" * 60) + print(" VENDOR LANDING PAGE CREATOR") + print("=" * 60) + + # List vendors + list_vendors() + + # Show templates + show_templates() + + # Interactive creation + print("๐ Create Landing Page") + print("-" * 60) + + vendor_subdomain = input("Enter vendor subdomain (e.g., wizamart): ").strip() + + if not vendor_subdomain: + print("โ Vendor subdomain is required!") + sys.exit(1) + + print("\nAvailable templates: default, minimal, modern, full") + template = input("Enter template (default): ").strip() or "default" + + if template not in ["default", "minimal", "modern", "full"]: + print(f"โ ๏ธ Invalid template '{template}', using 'default'") + template = "default" + + title = input("Enter page title (optional, press Enter to use default): ").strip() + + print("\n๐ Creating landing page...") + print("-" * 60) + + success = create_landing_page( + vendor_subdomain=vendor_subdomain, + template=template, + title=title if title else None + ) + + if success: + print("\nโ SUCCESS! Landing page is ready.") + print("\n๐ก Try different templates:") + print(f" python scripts/create_landing_page.py") + print(f" # Then choose: minimal, modern, or full") + else: + print("\nโ Failed to create landing page") + sys.exit(1)