Inline ticket +/- updates without full page refresh
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 58s

Extract shared _ticket_widget.html with stable #page-ticket-{id} target.
Adjust route returns re-rendered widget + OOB cart-mini swap, same
pattern as the entry detail page's ticket adjust.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-22 22:59:27 +00:00
parent b8724eaf66
commit 39f500c41c
4 changed files with 96 additions and 112 deletions

View File

@@ -31,63 +31,7 @@
<div class="shrink-0">
{% set qty = pending_tickets.get(entry.id, 0) %}
{% set ticket_url = url_for('page_summary.adjust_ticket') %}
<div class="flex items-center gap-2 text-sm">
<span class="text-green-600 font-medium">&pound;{{ '%.2f'|format(entry.ticket_price) }}</span>
{% if qty == 0 %}
<form
action="{{ ticket_url }}"
method="post"
hx-post="{{ ticket_url }}"
hx-swap="none"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="hidden" name="count" value="1">
<button
type="submit"
class="relative inline-flex items-center justify-center text-stone-500 hover:bg-emerald-50 rounded p-1"
>
<i class="fa fa-cart-plus text-2xl" aria-hidden="true"></i>
</button>
</form>
{% else %}
<form
action="{{ ticket_url }}"
method="post"
hx-post="{{ ticket_url }}"
hx-swap="none"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="hidden" name="count" value="{{ qty - 1 }}">
<button type="submit"
class="inline-flex items-center justify-center w-8 h-8 text-sm font-medium rounded-full border border-emerald-600 text-emerald-700 hover:bg-emerald-50 text-xl">-</button>
</form>
<a class="relative inline-flex items-center justify-center text-emerald-700" href="{{ cart_url('/') }}">
<span class="relative inline-flex items-center justify-center">
<i class="fa-solid fa-shopping-cart text-xl" aria-hidden="true"></i>
<span class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 pointer-events-none">
<span class="flex items-center justify-center bg-black text-white rounded-full w-4 h-4 text-xs font-bold">{{ qty }}</span>
</span>
</span>
</a>
<form
action="{{ ticket_url }}"
method="post"
hx-post="{{ ticket_url }}"
hx-swap="none"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="hidden" name="count" value="{{ qty + 1 }}">
<button type="submit"
class="inline-flex items-center justify-center w-8 h-8 text-sm font-medium rounded-full border border-emerald-600 text-emerald-700 hover:bg-emerald-50 text-xl">+</button>
</form>
{% endif %}
</div>
{% include '_types/page_summary/_ticket_widget.html' %}
</div>
{% endif %}
</div>

View File

@@ -28,58 +28,10 @@
{# Ticket widget below card #}
{% if entry.ticket_price is not none %}
<div class="border-t border-stone-100 px-3 py-2 flex items-center justify-between">
<span class="text-xs text-green-600 font-medium">&pound;{{ '%.2f'|format(entry.ticket_price) }}/ticket</span>
<div class="border-t border-stone-100 px-3 py-2">
{% set qty = pending_tickets.get(entry.id, 0) %}
{% set ticket_url = url_for('page_summary.adjust_ticket') %}
{% if qty == 0 %}
<form
action="{{ ticket_url }}"
method="post"
hx-post="{{ ticket_url }}"
hx-swap="none"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="hidden" name="count" value="1">
<button type="submit"
class="relative inline-flex items-center justify-center text-stone-500 hover:bg-emerald-50 rounded p-1">
<i class="fa fa-cart-plus text-xl" aria-hidden="true"></i>
</button>
</form>
{% else %}
<div class="flex items-center gap-1">
<form
action="{{ ticket_url }}"
method="post"
hx-post="{{ ticket_url }}"
hx-swap="none"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="hidden" name="count" value="{{ qty - 1 }}">
<button type="submit"
class="inline-flex items-center justify-center w-6 h-6 text-xs font-medium rounded-full border border-emerald-600 text-emerald-700 hover:bg-emerald-50">-</button>
</form>
<span class="inline-flex items-center justify-center px-1.5 py-0.5 rounded-full bg-stone-100 text-xs font-medium">{{ qty }}</span>
<form
action="{{ ticket_url }}"
method="post"
hx-post="{{ ticket_url }}"
hx-swap="none"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="hidden" name="count" value="{{ qty + 1 }}">
<button type="submit"
class="inline-flex items-center justify-center w-6 h-6 text-xs font-medium rounded-full border border-emerald-600 text-emerald-700 hover:bg-emerald-50">+</button>
</form>
</div>
{% endif %}
{% include '_types/page_summary/_ticket_widget.html' %}
</div>
{% endif %}
</article>

View File

@@ -0,0 +1,63 @@
{# Inline ticket +/- widget for page summary cards.
Variables: entry, qty, ticket_url
Wrapped in a div with stable ID for HTMX targeting. #}
<div id="page-ticket-{{ entry.id }}" class="flex items-center gap-2">
<span class="text-green-600 font-medium text-sm">&pound;{{ '%.2f'|format(entry.ticket_price) }}</span>
{% if qty == 0 %}
<form
action="{{ ticket_url }}"
method="post"
hx-post="{{ ticket_url }}"
hx-target="#page-ticket-{{ entry.id }}"
hx-swap="outerHTML"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="hidden" name="count" value="1">
<button
type="submit"
class="relative inline-flex items-center justify-center text-stone-500 hover:bg-emerald-50 rounded p-1"
>
<i class="fa fa-cart-plus text-2xl" aria-hidden="true"></i>
</button>
</form>
{% else %}
<form
action="{{ ticket_url }}"
method="post"
hx-post="{{ ticket_url }}"
hx-target="#page-ticket-{{ entry.id }}"
hx-swap="outerHTML"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="hidden" name="count" value="{{ qty - 1 }}">
<button type="submit"
class="inline-flex items-center justify-center w-8 h-8 text-sm font-medium rounded-full border border-emerald-600 text-emerald-700 hover:bg-emerald-50 text-xl">-</button>
</form>
<a class="relative inline-flex items-center justify-center text-emerald-700" href="{{ cart_url('/') }}">
<span class="relative inline-flex items-center justify-center">
<i class="fa-solid fa-shopping-cart text-xl" aria-hidden="true"></i>
<span class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 pointer-events-none">
<span class="flex items-center justify-center bg-black text-white rounded-full w-4 h-4 text-xs font-bold">{{ qty }}</span>
</span>
</span>
</a>
<form
action="{{ ticket_url }}"
method="post"
hx-post="{{ ticket_url }}"
hx-target="#page-ticket-{{ entry.id }}"
hx-swap="outerHTML"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="entry_id" value="{{ entry.id }}">
<input type="hidden" name="count" value="{{ qty + 1 }}">
<button type="submit"
class="inline-flex items-center justify-center w-8 h-8 text-sm font-medium rounded-full border border-emerald-600 text-emerald-700 hover:bg-emerald-50 text-xl">+</button>
</form>
{% endif %}
</div>