from __future__ import annotations from quart import ( g, Blueprint, abort, render_template, render_template_string, make_response, current_app, ) from shared.config import config from .services.nav import category_context, get_nav from .services.blacklist.category import is_category_blocked from .services import ( _hx_fragment_request, _productInfo, _vary, _current_url_without_page, ) from shared.browser.app.redis_cacher import cache_page from shared.browser.app.utils.htmx import is_htmx_request from shared.sx.helpers import sx_response def register(): browse_bp = Blueprint("browse", __name__) from .. import register_product browse_bp.register_blueprint( register_product(), ) @browse_bp.get("/") @cache_page(tag="browse") async def home(): """ Market landing page. Uses the post data hydrated by the app-level before_request (g.post_data). """ p_data = getattr(g, "post_data", None) or {} # Determine which template to use based on request type from shared.sx.page import get_template_context from sx.sx_components import render_market_home_page, render_market_home_oob ctx = await get_template_context() ctx.update(p_data) if not is_htmx_request(): html = await render_market_home_page(ctx) return await make_response(html) else: sx_src = await render_market_home_oob(ctx) return sx_response(sx_src) @browse_bp.get("/all/") @cache_page(tag="browse") async def browse_all(): """ Browse all products across all categories. Renders full page or just product cards (HTMX pagination fragment). """ market = getattr(g, "market", None) market_id = market.id if market else None nav = await get_nav(g.s, market_id=market_id) ctx = { "category_label": "All Products", "top_slug": "all", "sub_slug": None, } product_info = await _productInfo() full_context = {**product_info, **ctx} from shared.sx.page import get_template_context from sx.sx_components import render_browse_page, render_browse_oob, render_browse_cards tctx = await get_template_context() tctx.update(full_context) if not is_htmx_request(): html = await render_browse_page(tctx) resp = await make_response(html) elif product_info["page"] > 1: tctx.update(product_info) sx_src = await render_browse_cards(tctx) resp = sx_response(sx_src) else: sx_src = await render_browse_oob(tctx) resp = sx_response(sx_src) resp.headers["Hx-Push-Url"] = _current_url_without_page() return _vary(resp) @browse_bp.get("//") @cache_page(tag="browse") async def browse_top(top_slug: str): """ Browse by top-level category (e.g. /fruit). 404 if category not in allowed list or is blocked. """ REVERSE_CATEGORY = {v: k for k, v in config()["categories"]["allow"].items()} if top_slug not in REVERSE_CATEGORY: abort(404) if is_category_blocked(top_slug): abort(404) market = getattr(g, "market", None) market_id = market.id if market else None nav = await get_nav(g.s, market_id=market_id) ctx = category_context(top_slug, None, nav) product_info = await _productInfo(top_slug) full_context = {**product_info, **ctx} from shared.sx.page import get_template_context from sx.sx_components import render_browse_page, render_browse_oob, render_browse_cards tctx = await get_template_context() tctx.update(full_context) if not is_htmx_request(): html = await render_browse_page(tctx) resp = await make_response(html) elif product_info["page"] > 1: tctx.update(product_info) sx_src = await render_browse_cards(tctx) resp = sx_response(sx_src) else: sx_src = await render_browse_oob(tctx) resp = sx_response(sx_src) resp.headers["Hx-Push-Url"] = _current_url_without_page() return _vary(resp) @browse_bp.get("///") @cache_page(tag="browse") async def browse_sub(top_slug: str, sub_slug: str): """ Browse by subcategory (e.g. /fruit/citrus). 404 if blocked or unknown. """ REVERSE_CATEGORY = {v: k for k, v in config()["categories"]["allow"].items()} if top_slug not in REVERSE_CATEGORY: abort(404) if is_category_blocked(top_slug, sub_slug): abort(404) market = getattr(g, "market", None) market_id = market.id if market else None nav = await get_nav(g.s, market_id=market_id) ctx = category_context(top_slug, sub_slug, nav) product_info = await _productInfo(top_slug, sub_slug) full_context = {**product_info, **ctx} from shared.sx.page import get_template_context from sx.sx_components import render_browse_page, render_browse_oob, render_browse_cards tctx = await get_template_context() tctx.update(full_context) if not is_htmx_request(): html = await render_browse_page(tctx) resp = await make_response(html) elif product_info["page"] > 1: tctx.update(product_info) sx_src = await render_browse_cards(tctx) resp = sx_response(sx_src) else: sx_src = await render_browse_oob(tctx) resp = sx_response(sx_src) resp.headers["Hx-Push-Url"] = _current_url_without_page() return _vary(resp) return browse_bp