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' }}
+
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 }}