Migrate all apps to defpage declarative page routes
Replace Python GET page handlers with declarative defpage definitions in .sx files across all 8 apps (sx docs, orders, account, market, cart, federation, events, blog). Each app now has sxc/pages/ with setup functions, layout registrations, page helpers, and .sx defpage declarations. Core infrastructure: add g I/O primitive, PageDef support for auth/layout/ data/content/filter/aside/menu slots, post_author auth level, and custom layout registration. Remove ~1400 lines of render_*_page/render_*_oob boilerplate. Update all endpoint references in routes, sx_components, and templates to defpage_* naming. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -78,6 +78,10 @@ def create_app() -> "Quart":
|
||||
app.jinja_loader,
|
||||
])
|
||||
|
||||
# --- defpage setup ---
|
||||
from sxc.pages import setup_events_pages
|
||||
setup_events_pages()
|
||||
|
||||
# All events: / — global view across all pages
|
||||
app.register_blueprint(
|
||||
register_all_events(),
|
||||
@@ -169,11 +173,16 @@ def create_app() -> "Quart":
|
||||
|
||||
# Tickets blueprint — user-facing ticket views and QR codes
|
||||
from bp.tickets.routes import register as register_tickets
|
||||
app.register_blueprint(register_tickets())
|
||||
tickets_bp = register_tickets()
|
||||
from shared.sx.pages import mount_pages
|
||||
mount_pages(tickets_bp, "events", names=["my-tickets", "ticket-detail"])
|
||||
app.register_blueprint(tickets_bp)
|
||||
|
||||
# Ticket admin — check-in interface (admin only)
|
||||
from bp.ticket_admin.routes import register as register_ticket_admin
|
||||
app.register_blueprint(register_ticket_admin())
|
||||
ticket_admin_bp = register_ticket_admin()
|
||||
mount_pages(ticket_admin_bp, "events", names=["ticket-admin"])
|
||||
app.register_blueprint(ticket_admin_bp)
|
||||
|
||||
# --- oEmbed endpoint ---
|
||||
@app.get("/oembed")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from quart import (
|
||||
request, render_template, make_response, Blueprint, g
|
||||
request, Blueprint, g
|
||||
)
|
||||
|
||||
|
||||
@@ -14,23 +14,18 @@ from shared.sx.helpers import sx_response
|
||||
|
||||
def register():
|
||||
bp = Blueprint("admin", __name__, url_prefix='/admin')
|
||||
# ---------- Pages ----------
|
||||
@bp.get("/")
|
||||
@require_admin
|
||||
async def admin(calendar_slug: str, **kwargs):
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
|
||||
@bp.before_request
|
||||
async def _prepare_page_data():
|
||||
if "defpage_" not in (request.endpoint or ""):
|
||||
return
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_calendar_admin_page, render_calendar_admin_oob
|
||||
from sx.sx_components import _calendar_admin_main_panel_html
|
||||
ctx = await get_template_context()
|
||||
g.calendar_admin_content = _calendar_admin_main_panel_html(ctx)
|
||||
|
||||
tctx = await get_template_context()
|
||||
if not is_htmx_request():
|
||||
html = await render_calendar_admin_page(tctx)
|
||||
return await make_response(html)
|
||||
else:
|
||||
sx_src = await render_calendar_admin_oob(tctx)
|
||||
return sx_response(sx_src)
|
||||
|
||||
from shared.sx.pages import mount_pages
|
||||
mount_pages(bp, "events", names=["calendar-admin"])
|
||||
|
||||
@bp.get("/description/")
|
||||
@require_admin
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from quart import (
|
||||
make_response, Blueprint
|
||||
request, Blueprint, g
|
||||
)
|
||||
|
||||
from shared.browser.app.authz import require_admin
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
from shared.sx.helpers import sx_response
|
||||
|
||||
|
||||
def register():
|
||||
bp = Blueprint("admin", __name__, url_prefix='/admin')
|
||||
|
||||
# ---------- Pages ----------
|
||||
@bp.get("/")
|
||||
@require_admin
|
||||
async def admin(entry_id: int, **kwargs):
|
||||
@bp.before_request
|
||||
async def _prepare_page_data():
|
||||
if "defpage_" not in (request.endpoint or ""):
|
||||
return
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_entry_admin_page, render_entry_admin_oob
|
||||
from sx.sx_components import _entry_admin_main_panel_html
|
||||
ctx = await get_template_context()
|
||||
g.entry_admin_content = _entry_admin_main_panel_html(ctx)
|
||||
|
||||
from shared.sx.pages import mount_pages
|
||||
mount_pages(bp, "events", names=["entry-admin"])
|
||||
|
||||
tctx = await get_template_context()
|
||||
if not is_htmx_request():
|
||||
html = await render_entry_admin_page(tctx)
|
||||
return await make_response(html)
|
||||
else:
|
||||
sx_src = await render_entry_admin_oob(tctx)
|
||||
return sx_response(sx_src)
|
||||
return bp
|
||||
|
||||
@@ -238,20 +238,18 @@ def register():
|
||||
"user_ticket_counts_by_type": user_ticket_counts_by_type,
|
||||
"container_nav": container_nav,
|
||||
}
|
||||
@bp.get("/")
|
||||
@require_admin
|
||||
async def get(entry_id: int, **rest):
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
@bp.before_request
|
||||
async def _prepare_page_data():
|
||||
if "defpage_" not in (request.endpoint or ""):
|
||||
return
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_entry_page, render_entry_oob
|
||||
from sx.sx_components import _entry_main_panel_html, _entry_nav_html
|
||||
ctx = await get_template_context()
|
||||
g.entry_content = _entry_main_panel_html(ctx)
|
||||
g.entry_menu = _entry_nav_html(ctx)
|
||||
|
||||
tctx = await get_template_context()
|
||||
if not is_htmx_request():
|
||||
html = await render_entry_page(tctx)
|
||||
return await make_response(html, 200)
|
||||
else:
|
||||
sx_src = await render_entry_oob(tctx)
|
||||
return sx_response(sx_src)
|
||||
from shared.sx.pages import mount_pages
|
||||
mount_pages(bp, "events", names=["entry-detail"])
|
||||
|
||||
@bp.get("/edit/")
|
||||
@require_admin
|
||||
@@ -435,10 +433,10 @@ def register():
|
||||
nav_oob = await get_day_nav_oob(year, month, day)
|
||||
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_entry_page
|
||||
from sx.sx_components import _entry_main_panel_html
|
||||
|
||||
tctx = await get_template_context()
|
||||
html = await render_entry_page(tctx)
|
||||
html = _entry_main_panel_html(tctx)
|
||||
return sx_response(html + nav_oob)
|
||||
|
||||
|
||||
|
||||
@@ -1,31 +1,21 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from quart import (
|
||||
render_template, make_response, Blueprint
|
||||
request, Blueprint, g
|
||||
)
|
||||
|
||||
|
||||
from shared.browser.app.authz import require_admin
|
||||
from shared.sx.helpers import sx_response
|
||||
|
||||
|
||||
def register():
|
||||
bp = Blueprint("admin", __name__, url_prefix='/admin')
|
||||
|
||||
# ---------- Pages ----------
|
||||
@bp.get("/")
|
||||
@require_admin
|
||||
async def admin(year: int, month: int, day: int, **kwargs):
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_day_admin_page, render_day_admin_oob
|
||||
@bp.before_request
|
||||
async def _prepare_page_data():
|
||||
if "defpage_" not in (request.endpoint or ""):
|
||||
return
|
||||
from sx.sx_components import _day_admin_main_panel_html
|
||||
g.day_admin_content = _day_admin_main_panel_html({})
|
||||
|
||||
from shared.sx.pages import mount_pages
|
||||
mount_pages(bp, "events", names=["day-admin"])
|
||||
|
||||
tctx = await get_template_context()
|
||||
if not is_htmx_request():
|
||||
html = await render_day_admin_page(tctx)
|
||||
return await make_response(html)
|
||||
else:
|
||||
sx_src = await render_day_admin_oob(tctx)
|
||||
return sx_response(sx_src)
|
||||
return bp
|
||||
|
||||
@@ -9,9 +9,8 @@ from .services.markets import (
|
||||
soft_delete as svc_soft_delete,
|
||||
)
|
||||
|
||||
from shared.browser.app.redis_cacher import cache_page, clear_cache
|
||||
from shared.browser.app.redis_cacher import clear_cache
|
||||
from shared.browser.app.authz import require_admin
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
from shared.sx.helpers import sx_response
|
||||
|
||||
|
||||
@@ -22,18 +21,17 @@ def register():
|
||||
async def inject_root():
|
||||
return {}
|
||||
|
||||
@bp.get("/")
|
||||
async def home(**kwargs):
|
||||
@bp.before_request
|
||||
async def _prepare_page_data():
|
||||
if "defpage_" not in (request.endpoint or ""):
|
||||
return
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_markets_page, render_markets_oob
|
||||
|
||||
from sx.sx_components import _markets_main_panel_html
|
||||
ctx = await get_template_context()
|
||||
if not is_htmx_request():
|
||||
html = await render_markets_page(ctx)
|
||||
return await make_response(html)
|
||||
else:
|
||||
sx_src = await render_markets_oob(ctx)
|
||||
return sx_response(sx_src)
|
||||
g.markets_content = _markets_main_panel_html(ctx)
|
||||
|
||||
from shared.sx.pages import mount_pages
|
||||
mount_pages(bp, "events", names=["events-markets"])
|
||||
|
||||
@bp.post("/new/")
|
||||
@require_admin
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from quart import (
|
||||
request, render_template, make_response, Blueprint, g, jsonify
|
||||
request, make_response, Blueprint, g, jsonify
|
||||
)
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
|
||||
@@ -23,33 +23,32 @@ from shared.browser.app.utils import (
|
||||
parse_time,
|
||||
parse_cost
|
||||
)
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
from shared.sx.helpers import sx_response
|
||||
|
||||
|
||||
def register():
|
||||
bp = Blueprint("slot", __name__, url_prefix='/<int:slot_id>')
|
||||
|
||||
# ---------- Pages ----------
|
||||
|
||||
@bp.get("/")
|
||||
@require_admin
|
||||
async def get(slot_id: int, **kwargs):
|
||||
slot = await svc_get_slot(g.s, slot_id)
|
||||
@bp.before_request
|
||||
async def _prepare_page_data():
|
||||
if "defpage_" not in (request.endpoint or ""):
|
||||
return
|
||||
slot_id = (request.view_args or {}).get("slot_id")
|
||||
slot = await svc_get_slot(g.s, slot_id) if slot_id else None
|
||||
if not slot:
|
||||
return await make_response("Not found", 404)
|
||||
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_slot_page, render_slot_oob
|
||||
from quart import abort
|
||||
abort(404)
|
||||
g.slot = slot
|
||||
calendar = getattr(g, "calendar", None)
|
||||
from sx.sx_components import render_slot_main_panel
|
||||
g.slot_content = render_slot_main_panel(slot, calendar)
|
||||
|
||||
tctx = await get_template_context()
|
||||
if not is_htmx_request():
|
||||
html = await render_slot_page(tctx)
|
||||
return await make_response(html)
|
||||
else:
|
||||
sx_src = await render_slot_oob(tctx)
|
||||
return sx_response(sx_src)
|
||||
@bp.context_processor
|
||||
async def _inject_slot():
|
||||
return {"slot": getattr(g, "slot", None)}
|
||||
|
||||
from shared.sx.pages import mount_pages
|
||||
mount_pages(bp, "events", names=["slot-detail"])
|
||||
|
||||
@bp.get("/edit/")
|
||||
@require_admin
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from quart import (
|
||||
request, render_template, make_response, Blueprint, g, jsonify
|
||||
request, Blueprint, g, jsonify
|
||||
)
|
||||
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
@@ -19,21 +19,16 @@ from shared.browser.app.utils import (
|
||||
parse_time,
|
||||
parse_cost
|
||||
)
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
from shared.sx.helpers import sx_response
|
||||
|
||||
|
||||
def register():
|
||||
bp = Blueprint("slots", __name__, url_prefix='/slots')
|
||||
|
||||
# ---------- Pages ----------
|
||||
|
||||
|
||||
bp.register_blueprint(
|
||||
register_slot()
|
||||
)
|
||||
|
||||
|
||||
|
||||
@bp.context_processor
|
||||
async def get_slots():
|
||||
calendar = getattr(g, "calendar", None)
|
||||
@@ -43,19 +38,17 @@ def register():
|
||||
}
|
||||
return {"slots": []}
|
||||
|
||||
@bp.get("/")
|
||||
async def get(**kwargs):
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_slots_page, render_slots_oob
|
||||
|
||||
tctx = await get_template_context()
|
||||
if not is_htmx_request():
|
||||
html = await render_slots_page(tctx)
|
||||
return await make_response(html)
|
||||
else:
|
||||
sx_src = await render_slots_oob(tctx)
|
||||
return sx_response(sx_src)
|
||||
@bp.before_request
|
||||
async def _prepare_page_data():
|
||||
if "defpage_" not in (request.endpoint or ""):
|
||||
return
|
||||
calendar = getattr(g, "calendar", None)
|
||||
slots = await svc_list_slots(g.s, calendar.id) if calendar else []
|
||||
from sx.sx_components import render_slots_table
|
||||
g.slots_content = render_slots_table(slots, calendar)
|
||||
|
||||
from shared.sx.pages import mount_pages
|
||||
mount_pages(bp, "events", names=["slots-listing"])
|
||||
|
||||
@bp.post("/")
|
||||
@require_admin
|
||||
|
||||
@@ -12,7 +12,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
|
||||
from quart import (
|
||||
Blueprint, g, request, render_template, make_response, jsonify,
|
||||
Blueprint, g, request, make_response,
|
||||
)
|
||||
from sqlalchemy import select, func
|
||||
from sqlalchemy.orm import selectinload
|
||||
@@ -34,12 +34,10 @@ logger = logging.getLogger(__name__)
|
||||
def register() -> Blueprint:
|
||||
bp = Blueprint("ticket_admin", __name__, url_prefix="/admin/tickets")
|
||||
|
||||
@bp.get("/")
|
||||
@require_admin
|
||||
async def dashboard():
|
||||
"""Ticket admin dashboard with QR scanner and recent tickets."""
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
|
||||
@bp.before_request
|
||||
async def _prepare_page_data():
|
||||
if "defpage_" not in (request.endpoint or ""):
|
||||
return
|
||||
# Get recent tickets
|
||||
result = await g.s.execute(
|
||||
select(Ticket)
|
||||
@@ -72,15 +70,9 @@ def register() -> Blueprint:
|
||||
}
|
||||
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_ticket_admin_page, render_ticket_admin_oob
|
||||
|
||||
from sx.sx_components import _ticket_admin_main_panel_html
|
||||
ctx = await get_template_context()
|
||||
if not is_htmx_request():
|
||||
html = await render_ticket_admin_page(ctx, tickets, stats)
|
||||
return await make_response(html, 200)
|
||||
else:
|
||||
sx_src = await render_ticket_admin_oob(ctx, tickets, stats)
|
||||
return sx_response(sx_src)
|
||||
g.ticket_admin_content = _ticket_admin_main_panel_html(ctx, tickets, stats)
|
||||
|
||||
@bp.get("/entry/<int:entry_id>/")
|
||||
@require_admin
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from quart import (
|
||||
request, render_template, make_response, Blueprint, g, jsonify
|
||||
request, make_response, Blueprint, g, jsonify
|
||||
)
|
||||
|
||||
from shared.browser.app.authz import require_admin
|
||||
@@ -16,30 +16,37 @@ from .services.ticket import (
|
||||
from ..ticket_types.services.tickets import (
|
||||
list_ticket_types as svc_list_ticket_types,
|
||||
)
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
from shared.sx.helpers import sx_response
|
||||
|
||||
|
||||
def register():
|
||||
bp = Blueprint("ticket_type", __name__, url_prefix='/<int:ticket_type_id>')
|
||||
|
||||
@bp.get("/")
|
||||
@require_admin
|
||||
async def get(ticket_type_id: int, **kwargs):
|
||||
"""View a single ticket type."""
|
||||
ticket_type = await svc_get_ticket_type(g.s, ticket_type_id)
|
||||
@bp.before_request
|
||||
async def _prepare_page_data():
|
||||
if "defpage_" not in (request.endpoint or ""):
|
||||
return
|
||||
ticket_type_id = (request.view_args or {}).get("ticket_type_id")
|
||||
ticket_type = await svc_get_ticket_type(g.s, ticket_type_id) if ticket_type_id else None
|
||||
if not ticket_type:
|
||||
return await make_response("Not found", 404)
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_ticket_type_page, render_ticket_type_oob
|
||||
from quart import abort
|
||||
abort(404)
|
||||
g.ticket_type = ticket_type
|
||||
entry = getattr(g, "entry", None)
|
||||
calendar = getattr(g, "calendar", None)
|
||||
va = request.view_args or {}
|
||||
from sx.sx_components import render_ticket_type_main_panel
|
||||
g.ticket_type_content = render_ticket_type_main_panel(
|
||||
ticket_type, entry, calendar,
|
||||
va.get("day"), va.get("month"), va.get("year"),
|
||||
)
|
||||
|
||||
tctx = await get_template_context()
|
||||
if not is_htmx_request():
|
||||
html = await render_ticket_type_page(tctx)
|
||||
return await make_response(html)
|
||||
else:
|
||||
sx_src = await render_ticket_type_oob(tctx)
|
||||
return sx_response(sx_src)
|
||||
@bp.context_processor
|
||||
async def _inject_ticket_type():
|
||||
return {"ticket_type": getattr(g, "ticket_type", None)}
|
||||
|
||||
from shared.sx.pages import mount_pages
|
||||
mount_pages(bp, "events", names=["ticket-type-detail"])
|
||||
|
||||
@bp.get("/edit/")
|
||||
@require_admin
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from quart import (
|
||||
request, render_template, make_response, Blueprint, g, jsonify
|
||||
request, Blueprint, g, jsonify
|
||||
)
|
||||
|
||||
from shared.browser.app.authz import require_admin
|
||||
@@ -14,7 +14,6 @@ from .services.tickets import (
|
||||
|
||||
from ..ticket_type.routes import register as register_ticket_type
|
||||
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
from shared.sx.helpers import sx_response
|
||||
|
||||
|
||||
@@ -36,19 +35,22 @@ def register():
|
||||
}
|
||||
return {"ticket_types": []}
|
||||
|
||||
@bp.get("/")
|
||||
async def get(**kwargs):
|
||||
"""List all ticket types for the current entry."""
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_ticket_types_page, render_ticket_types_oob
|
||||
@bp.before_request
|
||||
async def _prepare_page_data():
|
||||
if "defpage_" not in (request.endpoint or ""):
|
||||
return
|
||||
entry = getattr(g, "entry", None)
|
||||
calendar = getattr(g, "calendar", None)
|
||||
ticket_types = await svc_list_ticket_types(g.s, entry.id) if entry else []
|
||||
va = request.view_args or {}
|
||||
from sx.sx_components import render_ticket_types_table
|
||||
g.ticket_types_content = render_ticket_types_table(
|
||||
ticket_types, entry, calendar,
|
||||
va.get("day"), va.get("month"), va.get("year"),
|
||||
)
|
||||
|
||||
tctx = await get_template_context()
|
||||
if not is_htmx_request():
|
||||
html = await render_ticket_types_page(tctx)
|
||||
return await make_response(html)
|
||||
else:
|
||||
sx_src = await render_ticket_types_oob(tctx)
|
||||
return sx_response(sx_src)
|
||||
from shared.sx.pages import mount_pages
|
||||
mount_pages(bp, "events", names=["ticket-types-listing"])
|
||||
|
||||
@bp.post("/")
|
||||
@require_admin
|
||||
|
||||
@@ -12,7 +12,7 @@ from __future__ import annotations
|
||||
import logging
|
||||
|
||||
from quart import (
|
||||
Blueprint, g, request, render_template, make_response,
|
||||
Blueprint, g, request, make_response,
|
||||
)
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import selectinload
|
||||
@@ -39,59 +39,43 @@ logger = logging.getLogger(__name__)
|
||||
def register() -> Blueprint:
|
||||
bp = Blueprint("tickets", __name__, url_prefix="/tickets")
|
||||
|
||||
@bp.get("/")
|
||||
async def my_tickets():
|
||||
"""List all tickets for the current user/session."""
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
|
||||
ident = current_cart_identity()
|
||||
tickets = await get_user_tickets(
|
||||
g.s,
|
||||
user_id=ident["user_id"],
|
||||
session_id=ident["session_id"],
|
||||
)
|
||||
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_tickets_page, render_tickets_oob
|
||||
|
||||
ctx = await get_template_context()
|
||||
if not is_htmx_request():
|
||||
html = await render_tickets_page(ctx, tickets)
|
||||
return await make_response(html, 200)
|
||||
else:
|
||||
sx_src = await render_tickets_oob(ctx, tickets)
|
||||
return sx_response(sx_src)
|
||||
|
||||
@bp.get("/<code>/")
|
||||
async def ticket_detail(code: str):
|
||||
"""View a single ticket with QR code."""
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
|
||||
ticket = await get_ticket_by_code(g.s, code)
|
||||
if not ticket:
|
||||
return await make_response("Ticket not found", 404)
|
||||
|
||||
# Verify ownership
|
||||
ident = current_cart_identity()
|
||||
if ident["user_id"] is not None:
|
||||
if ticket.user_id != ident["user_id"]:
|
||||
return await make_response("Ticket not found", 404)
|
||||
elif ident["session_id"] is not None:
|
||||
if ticket.session_id != ident["session_id"]:
|
||||
return await make_response("Ticket not found", 404)
|
||||
else:
|
||||
return await make_response("Ticket not found", 404)
|
||||
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import render_ticket_detail_page, render_ticket_detail_oob
|
||||
|
||||
ctx = await get_template_context()
|
||||
if not is_htmx_request():
|
||||
html = await render_ticket_detail_page(ctx, ticket)
|
||||
return await make_response(html, 200)
|
||||
else:
|
||||
sx_src = await render_ticket_detail_oob(ctx, ticket)
|
||||
return sx_response(sx_src)
|
||||
@bp.before_request
|
||||
async def _prepare_page_data():
|
||||
ep = request.endpoint or ""
|
||||
if "defpage_my_tickets" in ep:
|
||||
ident = current_cart_identity()
|
||||
tickets = await get_user_tickets(
|
||||
g.s,
|
||||
user_id=ident["user_id"],
|
||||
session_id=ident["session_id"],
|
||||
)
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import _tickets_main_panel_html
|
||||
ctx = await get_template_context()
|
||||
g.tickets_content = _tickets_main_panel_html(ctx, tickets)
|
||||
elif "defpage_ticket_detail" in ep:
|
||||
code = (request.view_args or {}).get("code")
|
||||
ticket = await get_ticket_by_code(g.s, code) if code else None
|
||||
if not ticket:
|
||||
from quart import abort
|
||||
abort(404)
|
||||
# Verify ownership
|
||||
ident = current_cart_identity()
|
||||
if ident["user_id"] is not None:
|
||||
if ticket.user_id != ident["user_id"]:
|
||||
from quart import abort
|
||||
abort(404)
|
||||
elif ident["session_id"] is not None:
|
||||
if ticket.session_id != ident["session_id"]:
|
||||
from quart import abort
|
||||
abort(404)
|
||||
else:
|
||||
from quart import abort
|
||||
abort(404)
|
||||
from shared.sx.page import get_template_context
|
||||
from sx.sx_components import _ticket_detail_panel_html
|
||||
ctx = await get_template_context()
|
||||
g.ticket_detail_content = _ticket_detail_panel_html(ctx, ticket)
|
||||
|
||||
@bp.post("/buy/")
|
||||
@clear_cache(tag="calendars", tag_scope="all")
|
||||
|
||||
@@ -191,11 +191,11 @@ def _calendar_nav_sx(ctx: dict) -> str:
|
||||
select_colours = ctx.get("select_colours", "")
|
||||
|
||||
parts = []
|
||||
slots_href = url_for("calendar.slots.get", calendar_slug=cal_slug)
|
||||
slots_href = url_for("calendar.slots.defpage_slots_listing", calendar_slug=cal_slug)
|
||||
parts.append(sx_call("nav-link", href=slots_href, icon="fa fa-clock",
|
||||
label="Slots", select_colours=select_colours))
|
||||
if is_admin:
|
||||
admin_href = url_for("calendar.admin.admin", calendar_slug=cal_slug)
|
||||
admin_href = url_for("calendar.admin.defpage_calendar_admin", calendar_slug=cal_slug)
|
||||
parts.append(sx_call("nav-link", href=admin_href, icon="fa fa-cog",
|
||||
select_colours=select_colours))
|
||||
return "".join(parts)
|
||||
@@ -319,7 +319,7 @@ def _calendar_admin_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
||||
nav_parts = []
|
||||
if cal_slug:
|
||||
for endpoint, label in [
|
||||
("calendar.slots.get", "slots"),
|
||||
("calendar.slots.defpage_slots_listing", "slots"),
|
||||
("calendar.admin.calendar_description_edit", "description"),
|
||||
]:
|
||||
href = url_for(endpoint, calendar_slug=cal_slug)
|
||||
@@ -339,7 +339,7 @@ def _calendar_admin_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
||||
def _markets_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
||||
"""Build the markets section header row."""
|
||||
from quart import url_for
|
||||
link_href = url_for("markets.home")
|
||||
link_href = url_for("markets.defpage_events_markets")
|
||||
return sx_call("menu-row-sx", id="markets-row", level=3,
|
||||
link_href=link_href,
|
||||
link_label_content=SxExpr(sx_call("events-markets-label")),
|
||||
@@ -594,7 +594,7 @@ def _day_row_html(ctx: dict, entry) -> str:
|
||||
# Slot/Time
|
||||
slot = getattr(entry, "slot", None)
|
||||
if slot:
|
||||
slot_href = url_for("calendar.slots.slot.get", calendar_slug=cal_slug, slot_id=slot.id)
|
||||
slot_href = url_for("calendar.slots.slot.defpage_slot_detail", calendar_slug=cal_slug, slot_id=slot.id)
|
||||
time_start = slot.time_start.strftime("%H:%M") if slot.time_start else ""
|
||||
time_end = f" \u2192 {slot.time_end.strftime('%H:%M')}" if slot.time_end else ""
|
||||
slot_html = sx_call("events-day-row-slot",
|
||||
@@ -774,7 +774,7 @@ def _tickets_main_panel_html(ctx: dict, tickets: list) -> str:
|
||||
ticket_cards = []
|
||||
if tickets:
|
||||
for ticket in tickets:
|
||||
href = url_for("tickets.ticket_detail", code=ticket.code)
|
||||
href = url_for("tickets.defpage_ticket_detail", code=ticket.code)
|
||||
entry = getattr(ticket, "entry", None)
|
||||
entry_name = entry.name if entry else "Unknown event"
|
||||
tt = getattr(ticket, "ticket_type", None)
|
||||
@@ -819,7 +819,7 @@ def _ticket_detail_panel_html(ctx: dict, ticket) -> str:
|
||||
bg_map = {"confirmed": "bg-emerald-50", "checked_in": "bg-blue-50", "reserved": "bg-amber-50"}
|
||||
header_bg = bg_map.get(state, "bg-stone-50")
|
||||
entry_name = entry.name if entry else "Ticket"
|
||||
back_href = url_for("tickets.my_tickets")
|
||||
back_href = url_for("tickets.defpage_my_tickets")
|
||||
|
||||
# Badge with larger sizing
|
||||
badge = _ticket_state_badge_html(state).replace('px-2 py-0.5 text-xs', 'px-3 py-1 text-sm')
|
||||
@@ -1400,42 +1400,7 @@ async def render_day_oob(ctx: dict) -> str:
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Day admin
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
async def render_day_admin_page(ctx: dict) -> str:
|
||||
"""Full page: day admin."""
|
||||
content = _day_admin_main_panel_html(ctx)
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
root_hdr = root_header_sx(ctx)
|
||||
post_hdr = _post_header_sx(ctx)
|
||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
||||
child = (admin_hdr + _calendar_header_sx(ctx) + _day_header_sx(ctx)
|
||||
+ _day_admin_header_sx(ctx))
|
||||
hdr = root_hdr + post_hdr + header_child_sx(child)
|
||||
return full_page_sx(ctx, header_rows=hdr, content=content)
|
||||
|
||||
|
||||
async def render_day_admin_oob(ctx: dict) -> str:
|
||||
"""OOB response: day admin."""
|
||||
content = _day_admin_main_panel_html(ctx)
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||
+ _calendar_header_sx(ctx, oob=True))
|
||||
oobs += oob_header_sx("day-header-child", "day-admin-header-child",
|
||||
_day_admin_header_sx(ctx))
|
||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"day-row", "day-header-child",
|
||||
"day-admin-row", "day-admin-header-child")
|
||||
return oob_page_sx(oobs=oobs, content=content)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Calendar admin
|
||||
# Calendar admin helper
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _events_post_admin_header_sx(ctx: dict, *, oob: bool = False,
|
||||
@@ -1445,140 +1410,6 @@ def _events_post_admin_header_sx(ctx: dict, *, oob: bool = False,
|
||||
return post_admin_header_sx(ctx, slug, oob=oob, selected=selected)
|
||||
|
||||
|
||||
async def render_calendar_admin_page(ctx: dict) -> str:
|
||||
"""Full page: calendar admin."""
|
||||
content = _calendar_admin_main_panel_html(ctx)
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
root_hdr = root_header_sx(ctx)
|
||||
post_hdr = _post_header_sx(ctx)
|
||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
||||
child = admin_hdr + _calendar_header_sx(ctx) + _calendar_admin_header_sx(ctx)
|
||||
hdr = root_hdr + post_hdr + header_child_sx(child)
|
||||
return full_page_sx(ctx, header_rows=hdr, content=content)
|
||||
|
||||
|
||||
async def render_calendar_admin_oob(ctx: dict) -> str:
|
||||
"""OOB response: calendar admin."""
|
||||
content = _calendar_admin_main_panel_html(ctx)
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||
+ _calendar_header_sx(ctx, oob=True))
|
||||
oobs += oob_header_sx("calendar-header-child", "calendar-admin-header-child",
|
||||
_calendar_admin_header_sx(ctx))
|
||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"calendar-admin-row", "calendar-admin-header-child")
|
||||
return oob_page_sx(oobs=oobs, content=content)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Slots
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
async def render_slots_page(ctx: dict) -> str:
|
||||
"""Full page: slots listing."""
|
||||
from quart import g
|
||||
slots = ctx.get("slots") or []
|
||||
calendar = ctx.get("calendar")
|
||||
content = render_slots_table(slots, calendar)
|
||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
root_hdr = root_header_sx(ctx)
|
||||
post_hdr = _post_header_sx(ctx)
|
||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
||||
child = admin_hdr + _calendar_header_sx(ctx) + _calendar_admin_header_sx(ctx)
|
||||
hdr = root_hdr + post_hdr + header_child_sx(child)
|
||||
return full_page_sx(ctx, header_rows=hdr, content=content)
|
||||
|
||||
|
||||
async def render_slots_oob(ctx: dict) -> str:
|
||||
"""OOB response: slots listing."""
|
||||
slots = ctx.get("slots") or []
|
||||
calendar = ctx.get("calendar")
|
||||
content = render_slots_table(slots, calendar)
|
||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||
+ _calendar_admin_header_sx(ctx, oob=True))
|
||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"calendar-admin-row", "calendar-admin-header-child")
|
||||
return oob_page_sx(oobs=oobs, content=content)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tickets
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
async def render_tickets_page(ctx: dict, tickets: list) -> str:
|
||||
"""Full page: my tickets."""
|
||||
content = _tickets_main_panel_html(ctx, tickets)
|
||||
hdr = root_header_sx(ctx)
|
||||
return full_page_sx(ctx, header_rows=hdr, content=content)
|
||||
|
||||
|
||||
async def render_tickets_oob(ctx: dict, tickets: list) -> str:
|
||||
"""OOB response: my tickets."""
|
||||
content = _tickets_main_panel_html(ctx, tickets)
|
||||
return oob_page_sx(content=content)
|
||||
|
||||
|
||||
async def render_ticket_detail_page(ctx: dict, ticket) -> str:
|
||||
"""Full page: ticket detail with QR."""
|
||||
content = _ticket_detail_panel_html(ctx, ticket)
|
||||
hdr = root_header_sx(ctx)
|
||||
return full_page_sx(ctx, header_rows=hdr, content=content)
|
||||
|
||||
|
||||
async def render_ticket_detail_oob(ctx: dict, ticket) -> str:
|
||||
"""OOB response: ticket detail."""
|
||||
content = _ticket_detail_panel_html(ctx, ticket)
|
||||
return oob_page_sx(content=content)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Ticket admin
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
async def render_ticket_admin_page(ctx: dict, tickets: list, stats: dict) -> str:
|
||||
"""Full page: ticket admin dashboard."""
|
||||
content = _ticket_admin_main_panel_html(ctx, tickets, stats)
|
||||
hdr = root_header_sx(ctx)
|
||||
return full_page_sx(ctx, header_rows=hdr, content=content)
|
||||
|
||||
|
||||
async def render_ticket_admin_oob(ctx: dict, tickets: list, stats: dict) -> str:
|
||||
"""OOB response: ticket admin dashboard."""
|
||||
content = _ticket_admin_main_panel_html(ctx, tickets, stats)
|
||||
return oob_page_sx(content=content)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Markets
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
async def render_markets_page(ctx: dict) -> str:
|
||||
"""Full page: markets listing."""
|
||||
content = _markets_main_panel_html(ctx)
|
||||
hdr = root_header_sx(ctx)
|
||||
child = _post_header_sx(ctx) + _markets_header_sx(ctx)
|
||||
hdr += header_child_sx(child)
|
||||
return full_page_sx(ctx, header_rows=hdr, content=content)
|
||||
|
||||
|
||||
async def render_markets_oob(ctx: dict) -> str:
|
||||
"""OOB response: markets listing."""
|
||||
content = _markets_main_panel_html(ctx)
|
||||
oobs = _post_header_sx(ctx, oob=True)
|
||||
oobs += oob_header_sx("post-header-child", "markets-header-child",
|
||||
_markets_header_sx(ctx))
|
||||
return oob_page_sx(oobs=oobs, content=content)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# POST / PUT / DELETE response components
|
||||
# ===========================================================================
|
||||
@@ -1939,36 +1770,6 @@ def _entry_nav_html(ctx: dict) -> str:
|
||||
return "".join(parts)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Entry page / OOB rendering
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
async def render_entry_page(ctx: dict) -> str:
|
||||
"""Full page: entry detail."""
|
||||
content = _entry_main_panel_html(ctx)
|
||||
hdr = root_header_sx(ctx)
|
||||
child = (_post_header_sx(ctx)
|
||||
+ _calendar_header_sx(ctx) + _day_header_sx(ctx)
|
||||
+ _entry_header_html(ctx))
|
||||
hdr += header_child_sx(child)
|
||||
nav_html = _entry_nav_html(ctx)
|
||||
return full_page_sx(ctx, header_rows=hdr, content=content, menu=nav_html)
|
||||
|
||||
|
||||
async def render_entry_oob(ctx: dict) -> str:
|
||||
"""OOB response: entry detail."""
|
||||
content = _entry_main_panel_html(ctx)
|
||||
oobs = _day_header_sx(ctx, oob=True)
|
||||
oobs += oob_header_sx("day-header-child", "entry-header-child",
|
||||
_entry_header_html(ctx))
|
||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"day-row", "day-header-child",
|
||||
"entry-row", "entry-header-child")
|
||||
nav_html = _entry_nav_html(ctx)
|
||||
return oob_page_sx(oobs=oobs, content=content, menu=nav_html)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Entry optioned (confirm/decline/provisional response)
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -2364,7 +2165,7 @@ def render_slots_table(slots, calendar) -> str:
|
||||
rows_html = ""
|
||||
if slots:
|
||||
for s in slots:
|
||||
slot_href = url_for("calendar.slots.slot.get", calendar_slug=cal_slug, slot_id=s.id)
|
||||
slot_href = url_for("calendar.slots.slot.defpage_slot_detail", calendar_slug=cal_slug, slot_id=s.id)
|
||||
del_url = url_for("calendar.slots.slot.slot_delete", calendar_slug=cal_slug, slot_id=s.id)
|
||||
desc = getattr(s, "description", "") or ""
|
||||
|
||||
@@ -2508,7 +2309,7 @@ def render_buy_result(entry, created_tickets, remaining, cart_count) -> str:
|
||||
|
||||
tickets_html = ""
|
||||
for ticket in created_tickets:
|
||||
href = url_for("tickets.ticket_detail", code=ticket.code)
|
||||
href = url_for("tickets.defpage_ticket_detail", code=ticket.code)
|
||||
tickets_html += sx_call("events-buy-result-ticket",
|
||||
href=href, code_short=ticket.code[:12] + "...")
|
||||
|
||||
@@ -2518,7 +2319,7 @@ def render_buy_result(entry, created_tickets, remaining, cart_count) -> str:
|
||||
remaining_html = sx_call("events-buy-result-remaining",
|
||||
text=f"{remaining} ticket{r_suffix} remaining")
|
||||
|
||||
my_href = url_for("tickets.my_tickets")
|
||||
my_href = url_for("tickets.defpage_my_tickets")
|
||||
|
||||
return cart_html + sx_call("events-buy-result",
|
||||
entry_id=str(entry.id),
|
||||
@@ -2610,7 +2411,7 @@ def _ticket_adjust_controls(csrf, adjust_url, target, entry_id, count, *, ticket
|
||||
return _adj_form(1, sx_call("events-adjust-cart-plus"),
|
||||
extra_cls="flex items-center")
|
||||
|
||||
my_tickets_href = url_for("tickets.my_tickets")
|
||||
my_tickets_href = url_for("tickets.defpage_my_tickets")
|
||||
minus = _adj_form(count - 1, sx_call("events-adjust-minus"))
|
||||
cart_icon = sx_call("events-adjust-cart-icon",
|
||||
href=my_tickets_href, count=str(count))
|
||||
@@ -2960,40 +2761,6 @@ def _entry_admin_main_panel_html(ctx: dict) -> str:
|
||||
is_selected=False)
|
||||
|
||||
|
||||
async def render_entry_admin_page(ctx: dict) -> str:
|
||||
"""Full page: entry admin."""
|
||||
content = _entry_admin_main_panel_html(ctx)
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
root_hdr = root_header_sx(ctx)
|
||||
post_hdr = _post_header_sx(ctx)
|
||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
||||
child = (admin_hdr + _calendar_header_sx(ctx) + _day_header_sx(ctx)
|
||||
+ _entry_header_html(ctx) + _entry_admin_header_html(ctx))
|
||||
hdr = root_hdr + post_hdr + header_child_sx(child)
|
||||
nav_html = sx_call("events-admin-placeholder-nav")
|
||||
return full_page_sx(ctx, header_rows=hdr, content=content, menu=nav_html)
|
||||
|
||||
|
||||
async def render_entry_admin_oob(ctx: dict) -> str:
|
||||
"""OOB response: entry admin."""
|
||||
content = _entry_admin_main_panel_html(ctx)
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||
+ _entry_header_html(ctx, oob=True))
|
||||
oobs += oob_header_sx("entry-header-child", "entry-admin-header-child",
|
||||
_entry_admin_header_html(ctx))
|
||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"day-row", "day-header-child",
|
||||
"entry-row", "entry-header-child",
|
||||
"entry-admin-row", "entry-admin-header-child")
|
||||
nav_html = sx_call("events-admin-placeholder-nav")
|
||||
return oob_page_sx(oobs=oobs, content=content, menu=nav_html)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Slot page / OOB (extends slots)
|
||||
# ===========================================================================
|
||||
@@ -3027,45 +2794,6 @@ def _slot_header_html(ctx: dict, *, oob: bool = False) -> str:
|
||||
child_id="slot-header-child", oob=oob)
|
||||
|
||||
|
||||
async def render_slot_page(ctx: dict) -> str:
|
||||
"""Full page: slot detail (extends slots page)."""
|
||||
slot = ctx.get("slot")
|
||||
calendar = ctx.get("calendar")
|
||||
if not slot or not calendar:
|
||||
return ""
|
||||
content = render_slot_main_panel(slot, calendar)
|
||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
root_hdr = root_header_sx(ctx)
|
||||
post_hdr = _post_header_sx(ctx)
|
||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
||||
child = (admin_hdr + _calendar_header_sx(ctx) + _calendar_admin_header_sx(ctx)
|
||||
+ _slot_header_html(ctx))
|
||||
hdr = root_hdr + post_hdr + header_child_sx(child)
|
||||
return full_page_sx(ctx, header_rows=hdr, content=content)
|
||||
|
||||
|
||||
async def render_slot_oob(ctx: dict) -> str:
|
||||
"""OOB response: slot detail."""
|
||||
slot = ctx.get("slot")
|
||||
calendar = ctx.get("calendar")
|
||||
if not slot or not calendar:
|
||||
return ""
|
||||
content = render_slot_main_panel(slot, calendar)
|
||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||
+ _calendar_admin_header_sx(ctx, oob=True))
|
||||
oobs += oob_header_sx("calendar-admin-header-child", "slot-header-child",
|
||||
_slot_header_html(ctx))
|
||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"calendar-admin-row", "calendar-admin-header-child",
|
||||
"slot-row", "slot-header-child")
|
||||
return oob_page_sx(oobs=oobs, content=content)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Slot edit form
|
||||
# ===========================================================================
|
||||
@@ -3243,40 +2971,6 @@ def _ticket_types_header_html(ctx: dict, *, oob: bool = False) -> str:
|
||||
nav=SxExpr(nav_html) if nav_html else None, child_id="ticket_type-header-child", oob=oob)
|
||||
|
||||
|
||||
async def render_ticket_types_page(ctx: dict) -> str:
|
||||
"""Full page: ticket types listing (extends entry admin)."""
|
||||
ticket_types = ctx.get("ticket_types") or []
|
||||
entry = ctx.get("entry")
|
||||
calendar = ctx.get("calendar")
|
||||
day = ctx.get("day")
|
||||
month = ctx.get("month")
|
||||
year = ctx.get("year")
|
||||
content = render_ticket_types_table(ticket_types, entry, calendar, day, month, year)
|
||||
hdr = root_header_sx(ctx)
|
||||
child = (_post_header_sx(ctx)
|
||||
+ _calendar_header_sx(ctx) + _day_header_sx(ctx)
|
||||
+ _entry_header_html(ctx) + _entry_admin_header_html(ctx)
|
||||
+ _ticket_types_header_html(ctx))
|
||||
hdr += header_child_sx(child)
|
||||
nav_html = sx_call("events-admin-placeholder-nav")
|
||||
return full_page_sx(ctx, header_rows=hdr, content=content, menu=nav_html)
|
||||
|
||||
|
||||
async def render_ticket_types_oob(ctx: dict) -> str:
|
||||
"""OOB response: ticket types listing."""
|
||||
ticket_types = ctx.get("ticket_types") or []
|
||||
entry = ctx.get("entry")
|
||||
calendar = ctx.get("calendar")
|
||||
day = ctx.get("day")
|
||||
month = ctx.get("month")
|
||||
year = ctx.get("year")
|
||||
content = render_ticket_types_table(ticket_types, entry, calendar, day, month, year)
|
||||
oobs = _entry_admin_header_html(ctx, oob=True)
|
||||
oobs += oob_header_sx("entry-admin-header-child", "ticket_types-header-child",
|
||||
_ticket_types_header_html(ctx))
|
||||
nav_html = sx_call("events-admin-placeholder-nav")
|
||||
return oob_page_sx(oobs=oobs, content=content, menu=nav_html)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Ticket type page / OOB
|
||||
@@ -3317,41 +3011,6 @@ def _ticket_type_header_html(ctx: dict, *, oob: bool = False) -> str:
|
||||
nav=SxExpr(nav_html) if nav_html else None, child_id="ticket_type-header-child-inner", oob=oob)
|
||||
|
||||
|
||||
async def render_ticket_type_page(ctx: dict) -> str:
|
||||
"""Full page: single ticket type detail (extends ticket types)."""
|
||||
ticket_type = ctx.get("ticket_type")
|
||||
entry = ctx.get("entry")
|
||||
calendar = ctx.get("calendar")
|
||||
day = ctx.get("day")
|
||||
month = ctx.get("month")
|
||||
year = ctx.get("year")
|
||||
content = render_ticket_type_main_panel(ticket_type, entry, calendar, day, month, year)
|
||||
hdr = root_header_sx(ctx)
|
||||
child = (_post_header_sx(ctx)
|
||||
+ _calendar_header_sx(ctx) + _day_header_sx(ctx)
|
||||
+ _entry_header_html(ctx) + _entry_admin_header_html(ctx)
|
||||
+ _ticket_types_header_html(ctx) + _ticket_type_header_html(ctx))
|
||||
hdr += header_child_sx(child)
|
||||
nav_html = sx_call("events-admin-placeholder-nav")
|
||||
return full_page_sx(ctx, header_rows=hdr, content=content, menu=nav_html)
|
||||
|
||||
|
||||
async def render_ticket_type_oob(ctx: dict) -> str:
|
||||
"""OOB response: single ticket type detail."""
|
||||
ticket_type = ctx.get("ticket_type")
|
||||
entry = ctx.get("entry")
|
||||
calendar = ctx.get("calendar")
|
||||
day = ctx.get("day")
|
||||
month = ctx.get("month")
|
||||
year = ctx.get("year")
|
||||
content = render_ticket_type_main_panel(ticket_type, entry, calendar, day, month, year)
|
||||
oobs = _ticket_types_header_html(ctx, oob=True)
|
||||
oobs += oob_header_sx("ticket_types-header-child", "ticket_type-header-child",
|
||||
_ticket_type_header_html(ctx))
|
||||
nav_html = sx_call("events-admin-placeholder-nav")
|
||||
return oob_page_sx(oobs=oobs, content=content, menu=nav_html)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# Ticket type edit form
|
||||
# ===========================================================================
|
||||
|
||||
406
events/sxc/pages/__init__.py
Normal file
406
events/sxc/pages/__init__.py
Normal file
@@ -0,0 +1,406 @@
|
||||
"""Events defpage setup — registers layouts, page helpers, and loads .sx pages."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
def setup_events_pages() -> None:
|
||||
"""Register events-specific layouts, page helpers, and load page definitions."""
|
||||
_register_events_layouts()
|
||||
_register_events_helpers()
|
||||
_load_events_page_files()
|
||||
|
||||
|
||||
def _load_events_page_files() -> None:
|
||||
import os
|
||||
from shared.sx.pages import load_page_dir
|
||||
load_page_dir(os.path.dirname(__file__), "events")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Layouts
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _register_events_layouts() -> None:
|
||||
from shared.sx.layouts import register_custom_layout
|
||||
register_custom_layout("events-calendar-admin", _cal_admin_full, _cal_admin_oob)
|
||||
register_custom_layout("events-slots", _slots_full, _slots_oob)
|
||||
register_custom_layout("events-slot", _slot_full, _slot_oob)
|
||||
register_custom_layout("events-day-admin", _day_admin_full, _day_admin_oob)
|
||||
register_custom_layout("events-entry", _entry_full, _entry_oob)
|
||||
register_custom_layout("events-entry-admin", _entry_admin_full, _entry_admin_oob)
|
||||
register_custom_layout("events-ticket-types", _ticket_types_full, _ticket_types_oob)
|
||||
register_custom_layout("events-ticket-type", _ticket_type_full, _ticket_type_oob)
|
||||
register_custom_layout("events-markets", _markets_full, _markets_oob)
|
||||
|
||||
|
||||
# --- Calendar admin layout (root + post + child(post-admin + calendar + cal-admin)) ---
|
||||
|
||||
async def _cal_admin_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import root_header_sx, post_admin_header_sx, header_child_sx
|
||||
from sx.sx_components import (
|
||||
_ensure_container_nav, _post_header_sx,
|
||||
_calendar_header_sx, _calendar_admin_header_sx,
|
||||
)
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
root_hdr = root_header_sx(ctx)
|
||||
post_hdr = _post_header_sx(ctx)
|
||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
||||
child = admin_hdr + _calendar_header_sx(ctx) + _calendar_admin_header_sx(ctx)
|
||||
return root_hdr + post_hdr + header_child_sx(child)
|
||||
|
||||
|
||||
async def _cal_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import post_admin_header_sx, oob_header_sx
|
||||
from sx.sx_components import (
|
||||
_ensure_container_nav, _calendar_header_sx,
|
||||
_calendar_admin_header_sx, _clear_deeper_oob,
|
||||
)
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||
+ _calendar_header_sx(ctx, oob=True))
|
||||
oobs += oob_header_sx("calendar-header-child", "calendar-admin-header-child",
|
||||
_calendar_admin_header_sx(ctx))
|
||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"calendar-admin-row", "calendar-admin-header-child")
|
||||
return oobs
|
||||
|
||||
|
||||
# --- Slots layout (same full as cal-admin but different OOB) ---
|
||||
|
||||
async def _slots_full(ctx: dict, **kw: Any) -> str:
|
||||
return await _cal_admin_full({**ctx, "is_admin_section": True}, **kw)
|
||||
|
||||
|
||||
async def _slots_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import post_admin_header_sx
|
||||
from sx.sx_components import (
|
||||
_ensure_container_nav, _calendar_admin_header_sx, _clear_deeper_oob,
|
||||
)
|
||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||
+ _calendar_admin_header_sx(ctx, oob=True))
|
||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"calendar-admin-row", "calendar-admin-header-child")
|
||||
return oobs
|
||||
|
||||
|
||||
# --- Slot detail layout (extends cal-admin with slot header) ---
|
||||
|
||||
async def _slot_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import root_header_sx, post_admin_header_sx, header_child_sx
|
||||
from sx.sx_components import (
|
||||
_ensure_container_nav, _post_header_sx,
|
||||
_calendar_header_sx, _calendar_admin_header_sx, _slot_header_html,
|
||||
)
|
||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
root_hdr = root_header_sx(ctx)
|
||||
post_hdr = _post_header_sx(ctx)
|
||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
||||
child = (admin_hdr + _calendar_header_sx(ctx)
|
||||
+ _calendar_admin_header_sx(ctx) + _slot_header_html(ctx))
|
||||
return root_hdr + post_hdr + header_child_sx(child)
|
||||
|
||||
|
||||
async def _slot_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import post_admin_header_sx, oob_header_sx
|
||||
from sx.sx_components import (
|
||||
_ensure_container_nav, _calendar_admin_header_sx,
|
||||
_slot_header_html, _clear_deeper_oob,
|
||||
)
|
||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||
+ _calendar_admin_header_sx(ctx, oob=True))
|
||||
oobs += oob_header_sx("calendar-admin-header-child", "slot-header-child",
|
||||
_slot_header_html(ctx))
|
||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"calendar-admin-row", "calendar-admin-header-child",
|
||||
"slot-row", "slot-header-child")
|
||||
return oobs
|
||||
|
||||
|
||||
# --- Day admin layout (root + post + post-admin + child(cal + day + day-admin)) ---
|
||||
|
||||
async def _day_admin_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import root_header_sx, post_admin_header_sx, header_child_sx
|
||||
from sx.sx_components import (
|
||||
_ensure_container_nav, _post_header_sx,
|
||||
_calendar_header_sx, _day_header_sx, _day_admin_header_sx,
|
||||
)
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
root_hdr = root_header_sx(ctx)
|
||||
post_hdr = _post_header_sx(ctx)
|
||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
||||
child = (admin_hdr + _calendar_header_sx(ctx) + _day_header_sx(ctx)
|
||||
+ _day_admin_header_sx(ctx))
|
||||
return root_hdr + post_hdr + header_child_sx(child)
|
||||
|
||||
|
||||
async def _day_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import post_admin_header_sx, oob_header_sx
|
||||
from sx.sx_components import (
|
||||
_ensure_container_nav, _calendar_header_sx,
|
||||
_day_admin_header_sx, _clear_deeper_oob,
|
||||
)
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||
+ _calendar_header_sx(ctx, oob=True))
|
||||
oobs += oob_header_sx("day-header-child", "day-admin-header-child",
|
||||
_day_admin_header_sx(ctx))
|
||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"day-row", "day-header-child",
|
||||
"day-admin-row", "day-admin-header-child")
|
||||
return oobs
|
||||
|
||||
|
||||
# --- Entry layout (root + child(post + cal + day + entry), + menu) ---
|
||||
|
||||
def _entry_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import root_header_sx, header_child_sx
|
||||
from sx.sx_components import (
|
||||
_post_header_sx, _calendar_header_sx,
|
||||
_day_header_sx, _entry_header_html,
|
||||
)
|
||||
root_hdr = root_header_sx(ctx)
|
||||
child = (_post_header_sx(ctx) + _calendar_header_sx(ctx)
|
||||
+ _day_header_sx(ctx) + _entry_header_html(ctx))
|
||||
return root_hdr + header_child_sx(child)
|
||||
|
||||
|
||||
def _entry_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import oob_header_sx
|
||||
from sx.sx_components import (
|
||||
_day_header_sx, _entry_header_html, _clear_deeper_oob,
|
||||
)
|
||||
oobs = _day_header_sx(ctx, oob=True)
|
||||
oobs += oob_header_sx("day-header-child", "entry-header-child",
|
||||
_entry_header_html(ctx))
|
||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"day-row", "day-header-child",
|
||||
"entry-row", "entry-header-child")
|
||||
return oobs
|
||||
|
||||
|
||||
# --- Entry admin layout (root + post + child(post-admin + cal + day + entry + entry-admin), + menu) ---
|
||||
|
||||
async def _entry_admin_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import root_header_sx, post_admin_header_sx, header_child_sx
|
||||
from sx.sx_components import (
|
||||
_ensure_container_nav, _post_header_sx,
|
||||
_calendar_header_sx, _day_header_sx,
|
||||
_entry_header_html, _entry_admin_header_html,
|
||||
)
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
root_hdr = root_header_sx(ctx)
|
||||
post_hdr = _post_header_sx(ctx)
|
||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
||||
child = (admin_hdr + _calendar_header_sx(ctx) + _day_header_sx(ctx)
|
||||
+ _entry_header_html(ctx) + _entry_admin_header_html(ctx))
|
||||
return root_hdr + post_hdr + header_child_sx(child)
|
||||
|
||||
|
||||
async def _entry_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import post_admin_header_sx, oob_header_sx
|
||||
from sx.sx_components import (
|
||||
_ensure_container_nav, _entry_header_html,
|
||||
_entry_admin_header_html, _clear_deeper_oob,
|
||||
)
|
||||
ctx = await _ensure_container_nav(ctx)
|
||||
slug = (ctx.get("post") or {}).get("slug", "")
|
||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||
+ _entry_header_html(ctx, oob=True))
|
||||
oobs += oob_header_sx("entry-header-child", "entry-admin-header-child",
|
||||
_entry_admin_header_html(ctx))
|
||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||
"post-admin-row", "post-admin-header-child",
|
||||
"calendar-row", "calendar-header-child",
|
||||
"day-row", "day-header-child",
|
||||
"entry-row", "entry-header-child",
|
||||
"entry-admin-row", "entry-admin-header-child")
|
||||
return oobs
|
||||
|
||||
|
||||
# --- Ticket types layout (extends entry admin with ticket-types header, + menu) ---
|
||||
|
||||
def _ticket_types_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import root_header_sx, header_child_sx
|
||||
from sx.sx_components import (
|
||||
_post_header_sx, _calendar_header_sx, _day_header_sx,
|
||||
_entry_header_html, _entry_admin_header_html,
|
||||
_ticket_types_header_html,
|
||||
)
|
||||
root_hdr = root_header_sx(ctx)
|
||||
child = (_post_header_sx(ctx) + _calendar_header_sx(ctx)
|
||||
+ _day_header_sx(ctx) + _entry_header_html(ctx)
|
||||
+ _entry_admin_header_html(ctx) + _ticket_types_header_html(ctx))
|
||||
return root_hdr + header_child_sx(child)
|
||||
|
||||
|
||||
def _ticket_types_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import oob_header_sx
|
||||
from sx.sx_components import (
|
||||
_entry_admin_header_html, _ticket_types_header_html, _clear_deeper_oob,
|
||||
)
|
||||
oobs = _entry_admin_header_html(ctx, oob=True)
|
||||
oobs += oob_header_sx("entry-admin-header-child", "ticket_types-header-child",
|
||||
_ticket_types_header_html(ctx))
|
||||
return oobs
|
||||
|
||||
|
||||
# --- Ticket type detail layout (extends ticket types with ticket-type header, + menu) ---
|
||||
|
||||
def _ticket_type_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import root_header_sx, header_child_sx
|
||||
from sx.sx_components import (
|
||||
_post_header_sx, _calendar_header_sx, _day_header_sx,
|
||||
_entry_header_html, _entry_admin_header_html,
|
||||
_ticket_types_header_html, _ticket_type_header_html,
|
||||
)
|
||||
root_hdr = root_header_sx(ctx)
|
||||
child = (_post_header_sx(ctx) + _calendar_header_sx(ctx)
|
||||
+ _day_header_sx(ctx) + _entry_header_html(ctx)
|
||||
+ _entry_admin_header_html(ctx) + _ticket_types_header_html(ctx)
|
||||
+ _ticket_type_header_html(ctx))
|
||||
return root_hdr + header_child_sx(child)
|
||||
|
||||
|
||||
def _ticket_type_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import oob_header_sx
|
||||
from sx.sx_components import (
|
||||
_ticket_types_header_html, _ticket_type_header_html,
|
||||
)
|
||||
oobs = _ticket_types_header_html(ctx, oob=True)
|
||||
oobs += oob_header_sx("ticket_types-header-child", "ticket_type-header-child",
|
||||
_ticket_type_header_html(ctx))
|
||||
return oobs
|
||||
|
||||
|
||||
# --- Markets layout (root + child(post + markets)) ---
|
||||
|
||||
def _markets_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import root_header_sx, header_child_sx
|
||||
from sx.sx_components import _post_header_sx, _markets_header_sx
|
||||
root_hdr = root_header_sx(ctx)
|
||||
child = _post_header_sx(ctx) + _markets_header_sx(ctx)
|
||||
return root_hdr + header_child_sx(child)
|
||||
|
||||
|
||||
def _markets_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import oob_header_sx
|
||||
from sx.sx_components import _post_header_sx, _markets_header_sx
|
||||
oobs = _post_header_sx(ctx, oob=True)
|
||||
oobs += oob_header_sx("post-header-child", "markets-header-child",
|
||||
_markets_header_sx(ctx))
|
||||
return oobs
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Page helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _register_events_helpers() -> None:
|
||||
from shared.sx.pages import register_page_helpers
|
||||
|
||||
register_page_helpers("events", {
|
||||
"calendar-admin-content": _h_calendar_admin_content,
|
||||
"day-admin-content": _h_day_admin_content,
|
||||
"slots-content": _h_slots_content,
|
||||
"slot-content": _h_slot_content,
|
||||
"entry-content": _h_entry_content,
|
||||
"entry-menu": _h_entry_menu,
|
||||
"entry-admin-content": _h_entry_admin_content,
|
||||
"admin-menu": _h_admin_menu,
|
||||
"ticket-types-content": _h_ticket_types_content,
|
||||
"ticket-type-content": _h_ticket_type_content,
|
||||
"tickets-content": _h_tickets_content,
|
||||
"ticket-detail-content": _h_ticket_detail_content,
|
||||
"ticket-admin-content": _h_ticket_admin_content,
|
||||
"markets-content": _h_markets_content,
|
||||
})
|
||||
|
||||
|
||||
def _h_calendar_admin_content():
|
||||
from quart import g
|
||||
return getattr(g, "calendar_admin_content", "")
|
||||
|
||||
|
||||
def _h_day_admin_content():
|
||||
from quart import g
|
||||
return getattr(g, "day_admin_content", "")
|
||||
|
||||
|
||||
def _h_slots_content():
|
||||
from quart import g
|
||||
return getattr(g, "slots_content", "")
|
||||
|
||||
|
||||
def _h_slot_content():
|
||||
from quart import g
|
||||
return getattr(g, "slot_content", "")
|
||||
|
||||
|
||||
def _h_entry_content():
|
||||
from quart import g
|
||||
return getattr(g, "entry_content", "")
|
||||
|
||||
|
||||
def _h_entry_menu():
|
||||
from quart import g
|
||||
return getattr(g, "entry_menu", "")
|
||||
|
||||
|
||||
def _h_entry_admin_content():
|
||||
from quart import g
|
||||
return getattr(g, "entry_admin_content", "")
|
||||
|
||||
|
||||
def _h_admin_menu():
|
||||
from shared.sx.helpers import sx_call
|
||||
return sx_call("events-admin-placeholder-nav")
|
||||
|
||||
|
||||
def _h_ticket_types_content():
|
||||
from quart import g
|
||||
return getattr(g, "ticket_types_content", "")
|
||||
|
||||
|
||||
def _h_ticket_type_content():
|
||||
from quart import g
|
||||
return getattr(g, "ticket_type_content", "")
|
||||
|
||||
|
||||
def _h_tickets_content():
|
||||
from quart import g
|
||||
return getattr(g, "tickets_content", "")
|
||||
|
||||
|
||||
def _h_ticket_detail_content():
|
||||
from quart import g
|
||||
return getattr(g, "ticket_detail_content", "")
|
||||
|
||||
|
||||
def _h_ticket_admin_content():
|
||||
from quart import g
|
||||
return getattr(g, "ticket_admin_content", "")
|
||||
|
||||
|
||||
def _h_markets_content():
|
||||
from quart import g
|
||||
return getattr(g, "markets_content", "")
|
||||
89
events/sxc/pages/events.sx
Normal file
89
events/sxc/pages/events.sx
Normal file
@@ -0,0 +1,89 @@
|
||||
;; Events pages — mounted on various nested blueprints
|
||||
|
||||
;; Calendar admin (mounted on calendar.admin bp)
|
||||
(defpage calendar-admin
|
||||
:path "/"
|
||||
:auth :admin
|
||||
:layout :events-calendar-admin
|
||||
:content (calendar-admin-content))
|
||||
|
||||
;; Day admin (mounted on day.admin bp)
|
||||
(defpage day-admin
|
||||
:path "/"
|
||||
:auth :admin
|
||||
:layout :events-day-admin
|
||||
:content (day-admin-content))
|
||||
|
||||
;; Slots listing (mounted on slots bp)
|
||||
(defpage slots-listing
|
||||
:path "/"
|
||||
:auth :public
|
||||
:layout :events-slots
|
||||
:content (slots-content))
|
||||
|
||||
;; Slot detail (mounted on slot bp)
|
||||
(defpage slot-detail
|
||||
:path "/"
|
||||
:auth :admin
|
||||
:layout :events-slot
|
||||
:content (slot-content))
|
||||
|
||||
;; Entry detail (mounted on calendar_entry bp)
|
||||
(defpage entry-detail
|
||||
:path "/"
|
||||
:auth :admin
|
||||
:layout :events-entry
|
||||
:content (entry-content)
|
||||
:menu (entry-menu))
|
||||
|
||||
;; Entry admin (mounted on calendar_entry.admin bp)
|
||||
(defpage entry-admin
|
||||
:path "/"
|
||||
:auth :admin
|
||||
:layout :events-entry-admin
|
||||
:content (entry-admin-content)
|
||||
:menu (admin-menu))
|
||||
|
||||
;; Ticket types listing (mounted on ticket_types bp)
|
||||
(defpage ticket-types-listing
|
||||
:path "/"
|
||||
:auth :public
|
||||
:layout :events-ticket-types
|
||||
:content (ticket-types-content)
|
||||
:menu (admin-menu))
|
||||
|
||||
;; Ticket type detail (mounted on ticket_type bp)
|
||||
(defpage ticket-type-detail
|
||||
:path "/"
|
||||
:auth :admin
|
||||
:layout :events-ticket-type
|
||||
:content (ticket-type-content)
|
||||
:menu (admin-menu))
|
||||
|
||||
;; My tickets (mounted on tickets bp)
|
||||
(defpage my-tickets
|
||||
:path "/"
|
||||
:auth :public
|
||||
:layout :root
|
||||
:content (tickets-content))
|
||||
|
||||
;; Ticket detail (mounted on tickets bp)
|
||||
(defpage ticket-detail
|
||||
:path "/<code>/"
|
||||
:auth :public
|
||||
:layout :root
|
||||
:content (ticket-detail-content))
|
||||
|
||||
;; Ticket admin dashboard (mounted on ticket_admin bp)
|
||||
(defpage ticket-admin
|
||||
:path "/"
|
||||
:auth :admin
|
||||
:layout :root
|
||||
:content (ticket-admin-content))
|
||||
|
||||
;; Markets (mounted on markets bp)
|
||||
(defpage events-markets
|
||||
:path "/"
|
||||
:auth :public
|
||||
:layout :events-markets
|
||||
:content (markets-content))
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- Desktop nav -->
|
||||
{% import 'macros/links.html' as links %}
|
||||
{% call links.link(
|
||||
url_for('calendar.slots.get', calendar_slug=calendar.slug),
|
||||
url_for('calendar.slots.defpage_slots_listing', calendar_slug=calendar.slug),
|
||||
hx_select_search,
|
||||
select_colours,
|
||||
True,
|
||||
@@ -14,5 +14,5 @@
|
||||
{% endcall %}
|
||||
{% if g.rights.admin %}
|
||||
{% from 'macros/admin_nav.html' import admin_nav_item %}
|
||||
{{ admin_nav_item(url_for('calendar.admin.admin', calendar_slug=calendar.slug)) }}
|
||||
{{ admin_nav_item(url_for('calendar.admin.defpage_calendar_admin', calendar_slug=calendar.slug)) }}
|
||||
{% endif %}
|
||||
@@ -23,7 +23,7 @@
|
||||
<div class="text-xs font-medium">
|
||||
{% call links.link(
|
||||
url_for(
|
||||
'calendar.slots.slot.get',
|
||||
'calendar.slots.slot.defpage_slot_detail',
|
||||
calendar_slug=calendar.slug,
|
||||
slot_id=entry.slot.id
|
||||
),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% import 'macros/links.html' as links %}
|
||||
{% macro header_row(oob=False) %}
|
||||
{% call links.menu_row(id='markets-row', oob=oob) %}
|
||||
{% call links.link(url_for('markets.home'), hx_select_search) %}
|
||||
{% call links.link(url_for('markets.defpage_events_markets'), hx_select_search) %}
|
||||
<i class="fa fa-shopping-bag" aria-hidden="true"></i>
|
||||
<div>
|
||||
Markets
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
|
||||
<a
|
||||
class="relative inline-flex items-center justify-center text-emerald-700"
|
||||
href="{{ url_for('tickets.my_tickets') }}"
|
||||
href="{{ url_for('tickets.defpage_my_tickets') }}"
|
||||
>
|
||||
<span class="relative inline-flex items-center justify-center">
|
||||
<i class="fa-solid fa-shopping-cart text-2xl" aria-hidden="true"></i>
|
||||
@@ -166,7 +166,7 @@
|
||||
|
||||
<a
|
||||
class="relative inline-flex items-center justify-center text-emerald-700"
|
||||
href="{{ url_for('tickets.my_tickets') }}"
|
||||
href="{{ url_for('tickets.defpage_my_tickets') }}"
|
||||
>
|
||||
<span class="relative inline-flex items-center justify-center">
|
||||
<i class="fa-solid fa-shopping-cart text-2xl" aria-hidden="true"></i>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="space-y-2 mb-4">
|
||||
{% for ticket in created_tickets %}
|
||||
<a
|
||||
href="{{ url_for('tickets.ticket_detail', code=ticket.code) }}"
|
||||
href="{{ url_for('tickets.defpage_ticket_detail', code=ticket.code) }}"
|
||||
class="flex items-center justify-between p-2 rounded-lg bg-white border border-emerald-100 hover:border-emerald-300 transition text-sm"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
<div class="mt-3 flex gap-2">
|
||||
<a
|
||||
href="{{ url_for('tickets.my_tickets') }}"
|
||||
href="{{ url_for('tickets.defpage_my_tickets') }}"
|
||||
class="text-sm text-emerald-700 hover:text-emerald-900 underline"
|
||||
>
|
||||
View all my tickets
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<section id="ticket-detail" class="{{styles.list_container}} max-w-lg mx-auto">
|
||||
|
||||
{# Back link #}
|
||||
<a href="{{ url_for('tickets.my_tickets') }}"
|
||||
<a href="{{ url_for('tickets.defpage_my_tickets') }}"
|
||||
class="inline-flex items-center gap-1 text-sm text-stone-500 hover:text-stone-700 mb-4">
|
||||
<i class="fa fa-arrow-left" aria-hidden="true"></i>
|
||||
Back to my tickets
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="space-y-4">
|
||||
{% for ticket in tickets %}
|
||||
<a
|
||||
href="{{ url_for('tickets.ticket_detail', code=ticket.code) }}"
|
||||
href="{{ url_for('tickets.defpage_ticket_detail', code=ticket.code) }}"
|
||||
class="block rounded-xl border border-stone-200 bg-white p-4 hover:shadow-md transition"
|
||||
>
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
|
||||
Reference in New Issue
Block a user