feat(bookings): allow cancelling booking confirmations

Add API endpoint to revert confirmed bookings to pending status
Add unconfirm buttons to the bookings list and confirmation page
Update inventory summary when a confirmation is cancelled
This commit is contained in:
2026-05-05 07:04:42 +08:00
parent 4e40bfd804
commit 13e85cfcd0
5 changed files with 179 additions and 3 deletions

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import type { ConfirmBookingResponse, PublicBooking } from '~~/shared/booking'
import type { CancelBookingConfirmationResponse, ConfirmBookingResponse, PublicBooking } from '~~/shared/booking'
import {
formatBookingCurrency,
@@ -15,6 +15,7 @@ const apiClient = useApiClient()
const token = String(route.params.token || '')
const confirming = ref(false)
const cancelling = ref(false)
let initialBooking: PublicBooking
@@ -114,6 +115,47 @@ async function confirmBooking() {
confirming.value = false
}
}
async function cancelBookingConfirmation() {
if (booking.value.status !== 'confirmed') {
return
}
if (import.meta.client && !window.confirm('Cancel this confirmation? The booking will return to pending and the seats will be released.')) {
return
}
cancelling.value = true
try {
const response = await apiClient<CancelBookingConfirmationResponse>(
`/api/public/bookings/${token}/cancel`,
{
method: 'POST'
}
)
booking.value = response.booking
toast.add({
title: response.alreadyPending ? 'Booking already pending' : 'Confirmation cancelled',
description: response.alreadyPending
? 'This booking was already pending confirmation.'
: 'The booking has been returned to pending status.',
color: response.alreadyPending ? 'warning' : 'success',
icon: 'i-lucide-x-circle'
})
} catch (error) {
toast.add({
title: 'Cancellation failed',
description: getErrorMessage(error, 'Please try again in a moment.'),
color: 'error',
icon: 'i-lucide-circle-alert'
})
} finally {
cancelling.value = false
}
}
</script>
<template>
@@ -198,13 +240,24 @@ async function confirmBooking() {
/>
<UButton
v-if="booking.status === 'pending'"
label="Confirm This Booking"
icon="i-lucide-check-check"
class="justify-center"
:disabled="booking.status === 'confirmed'"
:loading="confirming"
@click="confirmBooking"
/>
<UButton
v-else
label="Cancel Confirmation"
color="error"
variant="outline"
icon="i-lucide-x-circle"
class="justify-center"
:loading="cancelling"
@click="cancelBookingConfirmation"
/>
</div>
</UCard>
</div>