feat: complete dynamic menu system across all frontends
All checks were successful
CI / ruff (push) Successful in 11s
CI / pytest (push) Successful in 44m40s
CI / validate (push) Successful in 22s
CI / dependency-scanning (push) Successful in 28s
CI / docs (push) Successful in 39s
CI / deploy (push) Successful in 49s

- Add "Merchant Frontend" tab to admin menu-config page
- Merchant render endpoint now respects AdminMenuConfig visibility
  via get_merchant_primary_platform_id() platform resolution
- New store menu render endpoint (GET /store/core/menu/render/store)
  with platform-scoped visibility and store_code interpolation
- Store sidebar migrated from hardcoded Jinja2 macros to dynamic
  Alpine.js x-for rendering with loading skeleton and fallback
- Store init-alpine.js: add loadMenuConfig(), expandSectionForCurrentPage()
- Include store page route fixes, login template updates, and tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-23 02:14:42 +01:00
parent be248222bc
commit 506171503d
14 changed files with 1364 additions and 158 deletions

View File

@@ -4,7 +4,6 @@ Marketplace Store Page Routes (HTML rendering).
Store pages for marketplace management:
- Onboarding wizard
- Dashboard
- Marketplace imports
- Letzshop integration
"""
@@ -16,7 +15,9 @@ from sqlalchemy.orm import Session
from app.api.deps import get_current_store_from_cookie_or_header, get_db
from app.modules.core.utils.page_context import get_store_context
from app.modules.marketplace.services.onboarding_service import OnboardingService
from app.modules.service import module_service
from app.modules.tenancy.models import User
from app.modules.tenancy.models.store_platform import StorePlatform
from app.templates_config import templates
router = APIRouter()
@@ -39,14 +40,27 @@ async def store_onboarding_page(
"""
Render store onboarding wizard.
Mandatory 4-step wizard that must be completed before accessing dashboard:
4-step wizard for marketplace setup:
1. Merchant Profile Setup
2. Letzshop API Configuration
3. Product & Order Import Configuration
4. Order Sync (historical import)
If onboarding is already completed, redirects to dashboard.
If marketplace module is not enabled for this store's platform,
redirects to dashboard. If onboarding is already completed,
redirects to dashboard.
"""
sp = (
db.query(StorePlatform)
.filter(StorePlatform.store_id == current_user.token_store_id)
.first()
)
if not sp or not module_service.is_module_enabled(db, sp.platform_id, "marketplace"):
return RedirectResponse(
url=f"/store/{store_code}/dashboard",
status_code=302,
)
onboarding_service = OnboardingService(db)
if onboarding_service.is_completed(current_user.token_store_id):
return RedirectResponse(
@@ -60,44 +74,6 @@ async def store_onboarding_page(
)
# ============================================================================
# STORE DASHBOARD
# ============================================================================
@router.get(
"/{store_code}/dashboard", response_class=HTMLResponse, include_in_schema=False
)
async def store_dashboard_page(
request: Request,
store_code: str = Path(..., description="Store code"),
current_user: User = Depends(get_current_store_from_cookie_or_header),
db: Session = Depends(get_db),
):
"""
Render store dashboard.
Redirects to onboarding if not completed.
JavaScript will:
- Load store info via API
- Load dashboard stats via API
- Load recent orders via API
- Handle all interactivity
"""
onboarding_service = OnboardingService(db)
if not onboarding_service.is_completed(current_user.token_store_id):
return RedirectResponse(
url=f"/store/{store_code}/onboarding",
status_code=302,
)
return templates.TemplateResponse(
"core/store/dashboard.html",
get_store_context(request, db, current_user, store_code),
)
# ============================================================================
# MARKETPLACE IMPORTS
# ============================================================================
@@ -115,7 +91,15 @@ async def store_marketplace_page(
"""
Render marketplace import page.
JavaScript loads import jobs and products via API.
Redirects to onboarding if not completed.
"""
onboarding_service = OnboardingService(db)
if not onboarding_service.is_completed(current_user.token_store_id):
return RedirectResponse(
url=f"/store/{store_code}/onboarding",
status_code=302,
)
return templates.TemplateResponse(
"marketplace/store/marketplace.html",
get_store_context(request, db, current_user, store_code),
@@ -139,7 +123,15 @@ async def store_letzshop_page(
"""
Render Letzshop integration page.
JavaScript loads orders, credentials status, and handles fulfillment operations.
Redirects to onboarding if not completed.
"""
onboarding_service = OnboardingService(db)
if not onboarding_service.is_completed(current_user.token_store_id):
return RedirectResponse(
url=f"/store/{store_code}/onboarding",
status_code=302,
)
return templates.TemplateResponse(
"marketplace/store/letzshop.html",
get_store_context(request, db, current_user, store_code),