diff --git a/src/modules/activities/components/PurchaseTicketDialog.vue b/src/modules/activities/components/PurchaseTicketDialog.vue index b162a45..c746d13 100644 --- a/src/modules/activities/components/PurchaseTicketDialog.vue +++ b/src/modules/activities/components/PurchaseTicketDialog.vue @@ -255,10 +255,16 @@ onUnmounted(() => { - Purchase Ticket + {{ quantity > 1 ? `Purchase ${quantity} tickets` : 'Purchase ticket' }} - Purchase a ticket for {{ event.name }} for {{ formatEventPrice(event.price_per_ticket, event.currency) }} + + {{ quantity }} tickets for {{ event.name }} · + {{ formatEventPrice(totalPrice, event.currency) }} + + + Purchase a ticket for {{ event.name }} for {{ formatEventPrice(event.price_per_ticket, event.currency) }} + @@ -540,9 +546,18 @@ onUnmounted(() => {
-

Ticket Purchased Successfully!

+

+ {{ quantity > 1 ? `${quantity} tickets purchased!` : 'Ticket purchased!' }} +

- Your ticket has been purchased and is now available in your tickets area. + + {{ quantity }} tickets are now in your tickets area on a + single purchase row. + + + Your ticket has been purchased and is now available in + your tickets area. +

@@ -552,7 +567,9 @@ onUnmounted(() => {
-

Ticket ID

+

+ {{ quantity > 1 ? 'Purchase ID (covers all tickets)' : 'Ticket ID' }} +

{{ purchasedTicketId }}

diff --git a/src/modules/activities/composables/useOwnedTickets.ts b/src/modules/activities/composables/useOwnedTickets.ts index e540fb3..82b4246 100644 --- a/src/modules/activities/composables/useOwnedTickets.ts +++ b/src/modules/activities/composables/useOwnedTickets.ts @@ -74,8 +74,17 @@ function getTickets(activityId: string): ActivityTicket[] { return ticketsByActivity.value.get(activityId) ?? [] } +/** Seats represented by a single ticket row. One row carries N + * seats via extra.quantity; default 1 for legacy single-purchase rows. */ +function seatsOnRow(ticket: ActivityTicket): number { + return Math.max(1, ticket.extra?.quantity ?? 1) +} + +/** Total paid seats across all rows for one activity (sums extra.quantity). */ function paidCount(activityId: string): number { - return getTickets(activityId).filter(t => t.paid).length + return getTickets(activityId) + .filter(t => t.paid) + .reduce((sum, t) => sum + seatsOnRow(t), 0) } export function useOwnedTickets() { @@ -116,6 +125,7 @@ export function useOwnedTickets() { ownedActivityIds, getTickets, paidCount, + seatsOnRow, refresh: fetchTickets, isLoading, error, diff --git a/src/modules/activities/composables/useUserTickets.ts b/src/modules/activities/composables/useUserTickets.ts index 2803100..d562086 100644 --- a/src/modules/activities/composables/useUserTickets.ts +++ b/src/modules/activities/composables/useUserTickets.ts @@ -84,14 +84,18 @@ export function useUserTickets() { const group = groups.get(eventKey)! group.tickets.push(ticket) + // A ticket row represents N seats via extra.quantity (default 1 + // for legacy single-purchase rows). Counters sum seats, not + // rows, so the user sees the actual ticket count they bought. + const seats = Math.max(1, ticket.extra?.quantity ?? 1) if (ticket.paid) { - group.paidCount++ + group.paidCount += seats } else { - group.pendingCount++ + group.pendingCount += seats } if (ticket.registered) { - group.registeredCount++ + group.registeredCount += seats } }) diff --git a/src/modules/activities/types/ticket.ts b/src/modules/activities/types/ticket.ts index 85ead95..164e370 100644 --- a/src/modules/activities/types/ticket.ts +++ b/src/modules/activities/types/ticket.ts @@ -37,6 +37,10 @@ export interface ActivityTicketExtra { email_notification_sent: boolean nostr_notification_sent: boolean refunded: boolean + /** Number of seats represented by this ticket row (1..10). One + * row per purchase keeps the schema unchanged; callers must + * multiply by this when surfacing seat counts. */ + quantity?: number } export interface ActivityTicket { diff --git a/src/modules/activities/views/ActivityDetailPage.vue b/src/modules/activities/views/ActivityDetailPage.vue index c347363..e026e2f 100644 --- a/src/modules/activities/views/ActivityDetailPage.vue +++ b/src/modules/activities/views/ActivityDetailPage.vue @@ -100,7 +100,7 @@ function goBack() { // --- Ticket purchase + owned-tickets surface ---------------------- -const { getTickets, paidCount, refresh: refreshOwnedTickets } = useOwnedTickets() +const { getTickets, paidCount, seatsOnRow, refresh: refreshOwnedTickets } = useOwnedTickets() const ownedTicketsForActivity = computed(() => getTickets(activityId)) const ownedPaidCount = computed(() => paidCount(activityId)) @@ -290,9 +290,16 @@ function goToMyTickets() {
- {{ ticket.id }} + + ×{{ seatsOnRow(ticket) }} + + {{ ticket.id }}