fix(activities): simplify purchase success modal + dialog overflow

Three small fixes the buyer flagged on the multi-ticket purchase
flow:

1. Drop the inline QR grid from the success modal. The buyer's
   real ticket interaction lives in My Tickets — the modal's job
   is just to confirm the purchase landed and point them there.
   N stacked QRs made the dialog overflow on small viewports
   (point 2) and duplicated UI that already exists on the
   destination page.
2. DialogContent gets `max-h-[90dvh] overflow-y-auto` so even
   long content (long invoice expiry text, multiple methods, etc.)
   scrolls inside the dialog instead of bleeding off the viewport.
3. Companion to events ext c8602e0 which switched every row to a
   fresh short-hash id (was: first row reused the 64-hex
   payment_hash, rest got short hashes — inconsistent). No webapp
   code change for that — we just consume what the backend
   returns — but worth noting the ids you'll see now are all
   uniform short hashes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-23 22:46:17 +02:00
commit 70c798072e

View file

@ -53,7 +53,6 @@ const {
handleOpenLightningWallet,
resetPaymentState,
cleanup,
ticketQRCodes,
purchasedTicketIds,
showTicketQR
} = useTicketPurchase()
@ -251,7 +250,7 @@ onUnmounted(() => {
<template>
<Dialog :open="isOpen" @update:open="handleClose">
<DialogContent class="sm:max-w-[425px]">
<DialogContent class="sm:max-w-[425px] max-h-[90dvh] overflow-y-auto">
<DialogHeader>
<DialogTitle class="flex items-center gap-2">
<CreditCard class="w-5 h-5" />
@ -543,10 +542,14 @@ onUnmounted(() => {
</div>
</div>
<!-- Ticket QR Codes (After Successful Purchase) one QR per
row so each attendee can be scanned independently at the
door. Single-ticket purchases just render one. -->
<div v-else-if="showTicketQR && purchasedTicketIds.length > 0" class="py-4 flex flex-col items-center gap-4">
<!-- Success state. QRs live in My Tickets no need to
pre-render them here; this view's job is to confirm the
purchase landed and route the buyer to where they actually
interact with their tickets. -->
<div v-else-if="showTicketQR && purchasedTicketIds.length > 0" class="py-6 flex flex-col items-center gap-4">
<div class="flex justify-center">
<Ticket class="w-12 h-12 text-green-600" />
</div>
<div class="text-center space-y-2">
<h3 class="text-lg font-semibold text-green-600">
{{ purchasedTicketIds.length > 1
@ -555,41 +558,15 @@ onUnmounted(() => {
</h3>
<p class="text-sm text-muted-foreground">
<span v-if="purchasedTicketIds.length > 1">
Each attendee scans their own QR at the door
independent of the others.
Each attendee gets their own scannable QR in My Tickets
hand them out independently for the door scan.
</span>
<span v-else>
Your ticket is now in your tickets area.
Your ticket is now in My Tickets.
</span>
</p>
</div>
<div class="w-full space-y-3">
<div
v-for="(ticketId, index) in purchasedTicketIds"
:key="ticketId"
class="bg-muted/50 rounded-lg p-4"
>
<div class="text-center space-y-2">
<div v-if="purchasedTicketIds.length > 1" class="text-xs font-medium text-muted-foreground">
Ticket {{ index + 1 }} of {{ purchasedTicketIds.length }}
</div>
<div class="flex justify-center">
<img
v-if="ticketQRCodes[ticketId]"
:src="ticketQRCodes[ticketId]"
:alt="`Ticket QR ${index + 1}`"
class="w-32 h-32 border rounded-lg bg-white p-1"
/>
<Ticket v-else class="w-12 h-12 text-green-600" />
</div>
<div class="bg-background border rounded px-2 py-1 max-w-full">
<p class="text-[10px] font-mono break-all">{{ ticketId }}</p>
</div>
</div>
</div>
</div>
<div class="space-y-3 w-full">
<Button @click="() => $router.push('/my-tickets')" class="w-full">
View My Tickets