Fix cart template cross-app url_for crash and favicon 404
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m30s

- Cart _cart.html: replace url_for('market.browse.product...') with
  market_product_url() for links and cart_global.update_quantity for
  quantity forms (market endpoints don't exist in cart app)
- Factory favicon route: use STATIC_DIR instead of relative "static"
  (resolves to shared/static/ where favicon.ico actually lives)
- Cart context processor: fetch all 3 fragments (cart-mini, auth-menu,
  nav-tree) concurrently, matching pattern in all other apps

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-24 20:48:23 +00:00
parent 8b52a11b67
commit 567888c9e0
3 changed files with 30 additions and 16 deletions

View File

@@ -52,17 +52,32 @@ async def cart_context() -> dict:
"""
from shared.infrastructure.context import base_context
from shared.services.navigation import get_navigation_tree
from shared.infrastructure.fragments import fetch_fragment
from shared.infrastructure.cart_identity import current_cart_identity
from shared.infrastructure.fragments import fetch_fragments
ctx = await base_context()
ctx["nav_tree_html"] = await fetch_fragment(
"blog", "nav-tree",
params={"app_name": "cart", "path": request.path},
)
# Fallback for _nav.html when nav-tree fragment fetch fails
ctx["menu_items"] = await get_navigation_tree(g.s)
# Pre-fetch cross-app HTML fragments concurrently
user = getattr(g, "user", None)
ident = current_cart_identity()
cart_params = {}
if ident["user_id"] is not None:
cart_params["user_id"] = ident["user_id"]
if ident["session_id"] is not None:
cart_params["session_id"] = ident["session_id"]
cart_mini_html, auth_menu_html, nav_tree_html = await fetch_fragments([
("cart", "cart-mini", cart_params or None),
("account", "auth-menu", {"email": user.email} if user else None),
("blog", "nav-tree", {"app_name": "cart", "path": request.path}),
])
ctx["cart_mini_html"] = cart_mini_html
ctx["auth_menu_html"] = auth_menu_html
ctx["nav_tree_html"] = nav_tree_html
# Cart app owns cart data — use g.cart from _load_cart
all_cart = getattr(g, "cart", None) or []
all_cal = await get_calendar_cart_entries(g.s)

View File

@@ -130,7 +130,7 @@
class="w-24 h-24 sm:w-32 sm:h-28 rounded-xl border border-dashed border-stone-300 flex items-center justify-center text-xs text-stone-400"
>
No image
</div>'market', 'product', p.slug
</div>
{% endif %}
</div>
@@ -139,7 +139,7 @@
<div class="flex flex-col sm:flex-row sm:items-start justify-between gap-2 sm:gap-3">
<div class="min-w-0">
<h2 class="text-sm sm:text-base md:text-lg font-semibold text-stone-900">
{% set href=url_for('market.browse.product.product_detail', product_slug=p.slug) %}
{% set href=market_product_url(p.slug) %}
<a
href="{{ href }}"
hx_get="{{href}}"
@@ -188,12 +188,12 @@
<div class="mt-3 flex flex-col sm:flex-row sm:items-center justify-between gap-2 sm:gap-4">
<div class="flex items-center gap-2 text-xs sm:text-sm text-stone-700">
<span class="text-[0.65rem] sm:text-xs uppercase tracking-wide text-stone-500">Quantity</span>
{% set qty_url = url_for('cart_global.update_quantity', product_id=p.id) %}
<form
action="{{ url_for('market.browse.product.cart', product_slug=p.slug) }}"
action="{{ qty_url }}"
method="post"
hx-post="{{ url_for('market.browse.product.cart', product_slug=p.slug) }}"
hx-target="#cart-mini"
hx-swap="outerHTML"
hx-post="{{ qty_url }}"
hx-swap="none"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input
@@ -212,11 +212,10 @@
{{ item.quantity }}
</span>
<form
action="{{ url_for('market.browse.product.cart', product_slug=p.slug) }}"
action="{{ qty_url }}"
method="post"
hx-post="{{ url_for('market.browse.product.cart', product_slug=p.slug) }}"
hx-target="#cart-mini"
hx-swap="outerHTML"
hx-post="{{ qty_url }}"
hx-swap="none"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input

View File

@@ -284,6 +284,6 @@ def create_base_app(
# --- favicon ---
@app.get("/favicon.ico")
async def favicon():
return await send_from_directory("static", "favicon.ico")
return await send_from_directory(STATIC_DIR, "favicon.ico")
return app