feat: Add My Tickets feature with ticket management

- Introduce MyTickets.vue page to display user tickets with filtering options for paid, pending, and registered tickets.
- Implement useUserTickets composable for fetching and managing user ticket data.
- Update Navbar.vue to include a link to the My Tickets page.
- Enhance events API to support fetching user tickets.
- Define Ticket type in event.ts for better type safety.
This commit is contained in:
padreug 2025-08-01 21:54:05 +02:00
parent f7450627bc
commit 63d636a8a0
6 changed files with 403 additions and 2 deletions

View file

@ -0,0 +1,77 @@
import { ref, computed } from 'vue'
import { useAsyncState } from '@vueuse/core'
import type { Ticket } from '@/lib/types/event'
import { fetchUserTickets } from '@/lib/api/events'
import { useAuth } from './useAuth'
export function useUserTickets() {
const { isAuthenticated, currentUser } = useAuth()
const { state: tickets, isLoading, error: asyncError, execute: refresh } = useAsyncState(
async () => {
if (!isAuthenticated.value || !currentUser.value) {
return []
}
return await fetchUserTickets(currentUser.value.id)
},
[] as Ticket[],
{
immediate: false,
resetOnExecute: false,
}
)
const error = computed(() => {
if (asyncError.value) {
return {
message: asyncError.value instanceof Error
? asyncError.value.message
: 'An error occurred while fetching tickets'
}
}
return null
})
const sortedTickets = computed(() => {
return [...tickets.value].sort((a, b) =>
new Date(b.time).getTime() - new Date(a.time).getTime()
)
})
const paidTickets = computed(() => {
return sortedTickets.value.filter(ticket => ticket.paid)
})
const pendingTickets = computed(() => {
return sortedTickets.value.filter(ticket => !ticket.paid)
})
const registeredTickets = computed(() => {
return sortedTickets.value.filter(ticket => ticket.registered)
})
const unregisteredTickets = computed(() => {
return sortedTickets.value.filter(ticket => ticket.paid && !ticket.registered)
})
// Load tickets when authenticated
const loadTickets = async () => {
if (isAuthenticated.value && currentUser.value) {
await refresh()
}
}
return {
// State
tickets: sortedTickets,
paidTickets,
pendingTickets,
registeredTickets,
unregisteredTickets,
isLoading,
error,
// Actions
refresh: loadTickets,
}
}