feat(bookings): implement ticket receipts and seat sharing system
Add receipt tokens and booking_seats table to track individual tickets Create receipt and seat view pages with QR code generation
This commit is contained in:
23
server/api/public/receipts/[token].get.ts
Normal file
23
server/api/public/receipts/[token].get.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { PublicBookingReceipt } from '~~/shared/booking'
|
||||
|
||||
import { getBookingReceiptByReceiptToken } from '../../../utils/booking-repository'
|
||||
import { buildAppUrl } from '../../../utils/app-url'
|
||||
import { getRequiredRouteParam, httpError } from '../../../utils/http'
|
||||
|
||||
export default defineEventHandler(async (event): Promise<PublicBookingReceipt> => {
|
||||
const token = getRequiredRouteParam(event, 'token', 'Receipt token')
|
||||
const receipt = await getBookingReceiptByReceiptToken(token)
|
||||
|
||||
if (!receipt) {
|
||||
httpError(404, 'Receipt not found')
|
||||
}
|
||||
|
||||
return {
|
||||
booking: receipt.booking,
|
||||
receiptUrl: buildAppUrl(event, `/receipt/${receipt.booking.receiptToken}`),
|
||||
seats: receipt.seats.map((seat) => ({
|
||||
...seat,
|
||||
seatUrl: buildAppUrl(event, `/seat/${seat.seatToken}`)
|
||||
}))
|
||||
}
|
||||
})
|
||||
34
server/api/public/receipts/[token]/seats/[seatId].patch.ts
Normal file
34
server/api/public/receipts/[token]/seats/[seatId].patch.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import type { PublicBookingSeatWithUrl } from '~~/shared/booking'
|
||||
|
||||
import { updateBookingSeatShareByReceiptToken } from '../../../../../utils/booking-repository'
|
||||
import { parseSeatShareInput } from '../../../../../utils/bookings'
|
||||
import { buildAppUrl } from '../../../../../utils/app-url'
|
||||
import { getRequiredRouteParam, httpError } from '../../../../../utils/http'
|
||||
|
||||
export default defineEventHandler(async (event): Promise<{ seat: PublicBookingSeatWithUrl }> => {
|
||||
const token = getRequiredRouteParam(event, 'token', 'Receipt token')
|
||||
const seatId = getRequiredRouteParam(event, 'seatId', 'Seat')
|
||||
const body = await readBody<{
|
||||
shared?: boolean
|
||||
recipientName?: string | null
|
||||
recipientPhone?: string | null
|
||||
}>(event)
|
||||
|
||||
const input = parseSeatShareInput(body)
|
||||
const seat = await updateBookingSeatShareByReceiptToken({
|
||||
receiptToken: token,
|
||||
seatId,
|
||||
...input
|
||||
})
|
||||
|
||||
if (!seat) {
|
||||
httpError(404, 'Seat not found')
|
||||
}
|
||||
|
||||
return {
|
||||
seat: {
|
||||
...seat,
|
||||
seatUrl: buildAppUrl(event, `/seat/${seat.seatToken}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
23
server/api/public/seats/[token].get.ts
Normal file
23
server/api/public/seats/[token].get.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { PublicSeatReceipt } from '~~/shared/booking'
|
||||
|
||||
import { getSeatReceiptBySeatToken } from '../../../utils/booking-repository'
|
||||
import { buildAppUrl } from '../../../utils/app-url'
|
||||
import { getRequiredRouteParam, httpError } from '../../../utils/http'
|
||||
|
||||
export default defineEventHandler(async (event): Promise<PublicSeatReceipt> => {
|
||||
const token = getRequiredRouteParam(event, 'token', 'Seat token')
|
||||
const receipt = await getSeatReceiptBySeatToken(token)
|
||||
|
||||
if (!receipt) {
|
||||
httpError(404, 'Seat ticket not found')
|
||||
}
|
||||
|
||||
return {
|
||||
booking: receipt.booking,
|
||||
receiptUrl: buildAppUrl(event, `/receipt/${receipt.booking.receiptToken}`),
|
||||
seat: {
|
||||
...receipt.seat,
|
||||
seatUrl: buildAppUrl(event, `/seat/${receipt.seat.seatToken}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user