""" Page summary blueprint — shows upcoming events for a single page's calendars. Routes: GET // — full page scoped to this page GET //entries — HTMX fragment for infinite scroll POST //tickets/adjust — adjust ticket quantity inline """ from __future__ import annotations from quart import Blueprint, g, request, render_template, render_template_string, make_response from shared.browser.app.utils.htmx import is_htmx_request from shared.infrastructure.cart_identity import current_cart_identity from shared.services.registry import services def register() -> Blueprint: bp = Blueprint("page_summary", __name__) async def _load_entries(post_id, page, per_page=20): """Load upcoming entries for this page + pending ticket counts.""" entries, has_more = await services.calendar.upcoming_entries_for_container( g.s, "page", post_id, page=page, per_page=per_page, ) # Pending ticket counts keyed by entry_id ident = current_cart_identity() pending_tickets = {} if entries: tickets = await services.calendar.pending_tickets( g.s, user_id=ident["user_id"], session_id=ident["session_id"], ) for t in tickets: if t.entry_id is not None: pending_tickets[t.entry_id] = pending_tickets.get(t.entry_id, 0) + 1 return entries, has_more, pending_tickets @bp.get("/") async def index(): post = g.post_data["post"] view = request.args.get("view", "list") page = int(request.args.get("page", 1)) entries, has_more, pending_tickets = await _load_entries(post["id"], page) ctx = dict( entries=entries, has_more=has_more, pending_tickets=pending_tickets, page_info={}, page=page, view=view, ) if is_htmx_request(): html = await render_template("_types/page_summary/_main_panel.html", **ctx) else: html = await render_template("_types/page_summary/index.html", **ctx) return await make_response(html, 200) @bp.get("/entries") async def entries_fragment(): post = g.post_data["post"] view = request.args.get("view", "list") page = int(request.args.get("page", 1)) entries, has_more, pending_tickets = await _load_entries(post["id"], page) html = await render_template( "_types/page_summary/_cards.html", entries=entries, has_more=has_more, pending_tickets=pending_tickets, page_info={}, page=page, view=view, ) return await make_response(html, 200) @bp.post("/tickets/adjust") async def adjust_ticket(): """Adjust ticket quantity, return updated widget + OOB cart-mini.""" ident = current_cart_identity() form = await request.form entry_id = int(form.get("entry_id", 0)) count = max(int(form.get("count", 0)), 0) tt_raw = (form.get("ticket_type_id") or "").strip() ticket_type_id = int(tt_raw) if tt_raw else None await services.calendar.adjust_ticket_quantity( g.s, entry_id, count, user_id=ident["user_id"], session_id=ident["session_id"], ticket_type_id=ticket_type_id, ) # Get updated ticket count for this entry tickets = await services.calendar.pending_tickets( g.s, user_id=ident["user_id"], session_id=ident["session_id"], ) qty = sum(1 for t in tickets if t.entry_id == entry_id) # Load entry DTO for the widget template entry = await services.calendar.entry_by_id(g.s, entry_id) # Updated cart count for OOB mini-cart summary = await services.cart.cart_summary( g.s, user_id=ident["user_id"], session_id=ident["session_id"], ) cart_count = summary.count + summary.calendar_count + summary.ticket_count # Render widget + OOB cart-mini widget_html = await render_template( "_types/page_summary/_ticket_widget.html", entry=entry, qty=qty, ticket_url=f"/{g.post_slug}/tickets/adjust", ) mini_html = await render_template_string( '{% from "_types/cart/_mini.html" import mini with context %}' '{{ mini(oob="true") }}', cart_count=cart_count, ) return await make_response(widget_html + mini_html, 200) return bp