From 67e4c0db872a6de3d71603641d96b9b153aa0981 Mon Sep 17 00:00:00 2001 From: padreug Date: Fri, 1 Aug 2025 22:08:10 +0200 Subject: [PATCH] feat: Implement ticket grouping in MyTickets for improved organization - Enhance useUserTickets composable to group tickets by event, providing counts for paid, pending, and registered tickets. - Update MyTickets.vue to display tickets in organized groups, improving user experience with clear event headers and ticket summaries. - Refactor ticket display logic to accommodate grouped ticket views, ensuring a cohesive layout across different ticket statuses. --- src/composables/useUserTickets.ts | 46 +++ src/pages/MyTickets.vue | 552 +++++++++++++++++------------- 2 files changed, 358 insertions(+), 240 deletions(-) diff --git a/src/composables/useUserTickets.ts b/src/composables/useUserTickets.ts index b9c80a9..f82ca95 100644 --- a/src/composables/useUserTickets.ts +++ b/src/composables/useUserTickets.ts @@ -4,6 +4,14 @@ import type { Ticket } from '@/lib/types/event' import { fetchUserTickets } from '@/lib/api/events' import { useAuth } from './useAuth' +interface GroupedTickets { + eventId: string + tickets: Ticket[] + paidCount: number + pendingCount: number + registeredCount: number +} + export function useUserTickets() { const { isAuthenticated, currentUser } = useAuth() @@ -54,6 +62,43 @@ export function useUserTickets() { return sortedTickets.value.filter(ticket => ticket.paid && !ticket.registered) }) + // Group tickets by event + const groupedTickets = computed(() => { + const groups = new Map() + + sortedTickets.value.forEach(ticket => { + if (!groups.has(ticket.event)) { + groups.set(ticket.event, { + eventId: ticket.event, + tickets: [], + paidCount: 0, + pendingCount: 0, + registeredCount: 0 + }) + } + + const group = groups.get(ticket.event)! + group.tickets.push(ticket) + + if (ticket.paid) { + group.paidCount++ + } else { + group.pendingCount++ + } + + if (ticket.registered) { + group.registeredCount++ + } + }) + + // Convert to array and sort by most recent ticket in each group + return Array.from(groups.values()).sort((a, b) => { + const aLatest = Math.max(...a.tickets.map(t => new Date(t.time).getTime())) + const bLatest = Math.max(...b.tickets.map(t => new Date(t.time).getTime())) + return bLatest - aLatest + }) + }) + // Load tickets when authenticated const loadTickets = async () => { if (isAuthenticated.value && currentUser.value) { @@ -68,6 +113,7 @@ export function useUserTickets() { pendingTickets, registeredTickets, unregisteredTickets, + groupedTickets, isLoading, error, diff --git a/src/pages/MyTickets.vue b/src/pages/MyTickets.vue index 21f11f2..1d7aa3e 100644 --- a/src/pages/MyTickets.vue +++ b/src/pages/MyTickets.vue @@ -18,6 +18,7 @@ const { pendingTickets, registeredTickets, unregisteredTickets, + groupedTickets, isLoading, error, refresh @@ -131,292 +132,363 @@ onMounted(async () => { -
- - +
+
+ +
- Ticket #{{ ticket.id.slice(0, 8) }} -
- - {{ getTicketStatus(ticket).label }} - - +
+

Event: {{ group.eventId }}

+

+ {{ group.tickets.length }} ticket{{ group.tickets.length !== 1 ? 's' : '' }} • + {{ group.paidCount }} paid • + {{ group.pendingCount }} pending • + {{ group.registeredCount }} registered +

+ + {{ group.tickets.length }} total +
- - Event ID: {{ ticket.event }} - - - -
-
- Status: -
- - {{ getTicketStatus(ticket).label }} -
-
-
- Purchased: - {{ formatDate(ticket.time) }} -
-
- Time: - {{ formatTime(ticket.time) }} -
-
- Registered: - {{ formatDate(ticket.reg_timestamp) }} -
- - -
-
- Ticket QR Code -
- Loading... +
+ + +
+ + +
+ Ticket #{{ ticket.id.slice(0, 8) }} +
+ + {{ getTicketStatus(ticket).label }} + +
-
-

Ticket ID

-
-

{{ ticket.id }}

+
+ + +
+
+ Status: +
+ + {{ getTicketStatus(ticket).label }} +
+
+
+ Purchased: + {{ formatDate(ticket.time) }} +
+
+ Time: + {{ formatTime(ticket.time) }} +
+
+ Registered: + {{ formatDate(ticket.reg_timestamp) }} +
+ + +
+
+ Ticket QR Code +
+ Loading... +
+
+

Ticket ID

+
+

{{ ticket.id }}

+
+
-
-
- -
+ + +
+
-
- - +
+
+ +
- Ticket #{{ ticket.id.slice(0, 8) }} -
- - {{ getTicketStatus(ticket).label }} - - +
+

Event: {{ group.eventId }}

+

+ {{ group.paidCount }} paid ticket{{ group.paidCount !== 1 ? 's' : '' }} +

+ + {{ group.paidCount }} paid +
- - Event ID: {{ ticket.event }} - - - -
-
- Status: -
- - {{ getTicketStatus(ticket).label }} -
-
-
- Purchased: - {{ formatDate(ticket.time) }} -
-
- Time: - {{ formatTime(ticket.time) }} -
-
- Registered: - {{ formatDate(ticket.reg_timestamp) }} -
- - -
-
- Ticket QR Code -
- Loading... +
+ + +
+ + +
+ Ticket #{{ ticket.id.slice(0, 8) }} +
+ + {{ getTicketStatus(ticket).label }} + +
-
-

Ticket ID

-
-

{{ ticket.id }}

+
+ + +
+
+ Status: +
+ + {{ getTicketStatus(ticket).label }} +
+
+
+ Purchased: + {{ formatDate(ticket.time) }} +
+
+ Time: + {{ formatTime(ticket.time) }} +
+
+ Registered: + {{ formatDate(ticket.reg_timestamp) }} +
+ + +
+
+ Ticket QR Code +
+ Loading... +
+
+

Ticket ID

+
+

{{ ticket.id }}

+
+
-
-
- -
+ + +
+
-
- - +
+
+ +
- Ticket #{{ ticket.id.slice(0, 8) }} -
- - {{ getTicketStatus(ticket).label }} - - +
+

Event: {{ group.eventId }}

+

+ {{ group.pendingCount }} pending ticket{{ group.pendingCount !== 1 ? 's' : '' }} +

+ + {{ group.pendingCount }} pending +
- - Event ID: {{ ticket.event }} - - - -
-
- Status: -
- - {{ getTicketStatus(ticket).label }} -
-
-
- Created: - {{ formatDate(ticket.time) }} -
-
- Time: - {{ formatTime(ticket.time) }} -
- - -
-
- Ticket QR Code -
- Loading... +
+ + +
+ + +
+ Ticket #{{ ticket.id.slice(0, 8) }} +
+ + {{ getTicketStatus(ticket).label }} + +
-
-

Ticket ID

-
-

{{ ticket.id }}

+
+ + +
+
+ Status: +
+ + {{ getTicketStatus(ticket).label }} +
+
+
+ Created: + {{ formatDate(ticket.time) }} +
+
+ Time: + {{ formatTime(ticket.time) }} +
+ + +
+
+ Ticket QR Code +
+ Loading... +
+
+

Ticket ID

+
+

{{ ticket.id }}

+
+
-
-
- -
+ + +
+
-
- - +
+
+ +
- Ticket #{{ ticket.id.slice(0, 8) }} -
- - {{ getTicketStatus(ticket).label }} - - +
+

Event: {{ group.eventId }}

+

+ {{ group.registeredCount }} registered ticket{{ group.registeredCount !== 1 ? 's' : '' }} +

+ + {{ group.registeredCount }} registered +
- - Event ID: {{ ticket.event }} - - - -
-
- Status: -
- - {{ getTicketStatus(ticket).label }} -
-
-
- Purchased: - {{ formatDate(ticket.time) }} -
-
- Time: - {{ formatTime(ticket.time) }} -
-
- Registered: - {{ formatDate(ticket.reg_timestamp) }} -
- - -
-
- Ticket QR Code -
- Loading... +
+ + +
+ + +
+ Ticket #{{ ticket.id.slice(0, 8) }} +
+ + {{ getTicketStatus(ticket).label }} + +
-
-

Ticket ID

-
-

{{ ticket.id }}

+
+ + +
+
+ Status: +
+ + {{ getTicketStatus(ticket).label }} +
+
+
+ Purchased: + {{ formatDate(ticket.time) }} +
+
+ Time: + {{ formatTime(ticket.time) }} +
+
+ Registered: + {{ formatDate(ticket.reg_timestamp) }} +
+ + +
+
+ Ticket QR Code +
+ Loading... +
+
+

Ticket ID

+
+

{{ ticket.id }}

+
+
-
-
- -
+ + +
+