refactor(ui): streamline booking form layout and table actions

Consolidate booking table row actions into a dropdown menu
Update booking page layout to use a sidebar card for event details
This commit is contained in:
2026-05-08 16:52:30 +08:00
parent b6749bc5e7
commit 25720b21e1
2 changed files with 132 additions and 97 deletions

View File

@@ -285,62 +285,43 @@
</template>
<template #actions-cell="{ row }">
<div class="flex flex-wrap justify-end gap-1.5 py-0.5">
<UButton
:to="confirmationPath(row.original)"
label="Open"
color="neutral"
variant="outline"
icon="i-lucide-external-link"
size="sm"
/>
<UButton
:to="receiptPath(row.original)"
label="Receipt"
color="neutral"
variant="outline"
icon="i-lucide-receipt"
size="sm"
/>
<UButton
label="Edit"
color="neutral"
variant="outline"
icon="i-lucide-pencil-line"
size="sm"
:disabled="!bookingConfig"
@click="openBookingEditor(row.original)"
/>
<UButton
label="Transfer"
color="neutral"
variant="outline"
icon="i-lucide-send"
size="sm"
:disabled="!hasTransferTargets(row.original)"
@click="openTransferEditor(row.original)"
/>
<UButton
v-if="row.original.status === 'confirmed'"
label="Unconfirm"
color="error"
variant="outline"
icon="i-lucide-x-circle"
size="sm"
:loading="cancellingBookingId === row.original.id"
:disabled="cancellingBookingId !== null && cancellingBookingId !== row.original.id"
@click="cancelBookingConfirmation(row.original)"
/>
<UButton
label="Delete"
color="error"
variant="outline"
icon="i-lucide-trash-2"
size="sm"
:loading="deletingBookingId === row.original.id"
:disabled="Boolean(deletingBookingId) && deletingBookingId !== row.original.id"
@click="deleteBooking(row.original)"
/>
<div class="flex flex-nowrap items-center justify-end gap-1 py-0.5 whitespace-nowrap">
<UTooltip text="Open booking">
<UButton
:to="confirmationPath(row.original)"
color="neutral"
variant="ghost"
icon="i-lucide-external-link"
size="sm"
class="min-w-9 justify-center"
aria-label="Open booking"
/>
</UTooltip>
<UTooltip text="Open receipt">
<UButton
:to="receiptPath(row.original)"
color="neutral"
variant="ghost"
icon="i-lucide-receipt"
size="sm"
class="min-w-9 justify-center"
aria-label="Open receipt"
/>
</UTooltip>
<UDropdownMenu :items="bookingActionMenuItems(row.original)">
<UButton
color="neutral"
variant="ghost"
icon="i-lucide-ellipsis-vertical"
size="sm"
class="min-w-9 justify-center"
:loading="isBookingRowActionBusy(row.original)"
:disabled="isBookingRowActionBusy(row.original)"
aria-label="More actions"
/>
</UDropdownMenu>
</div>
</template>
</UTable>
@@ -798,6 +779,59 @@ function receiptPath(booking: PublicBooking) {
return `/receipt/${booking.receiptToken}`
}
function isBookingRowActionBusy(booking: PublicBooking) {
return Boolean(
(deletingBookingId.value && deletingBookingId.value !== booking.id)
|| (cancellingBookingId.value && cancellingBookingId.value !== booking.id)
|| deletingBookingId.value === booking.id
|| cancellingBookingId.value === booking.id
)
}
function bookingActionMenuItems(booking: PublicBooking) {
const busy = isBookingRowActionBusy(booking)
const items = [
[
{
label: 'Edit booking',
icon: 'i-lucide-pencil-line',
disabled: busy || !bookingConfig.value,
onSelect: () => openBookingEditor(booking)
},
{
label: 'Transfer booking',
icon: 'i-lucide-send',
disabled: busy || !hasTransferTargets(booking),
onSelect: () => openTransferEditor(booking)
}
]
]
if (booking.status === 'confirmed') {
items.push([
{
label: 'Unconfirm booking',
icon: 'i-lucide-x-circle',
color: 'error',
disabled: busy,
onSelect: () => cancelBookingConfirmation(booking)
}
])
}
items.push([
{
label: 'Delete booking',
icon: 'i-lucide-trash-2',
color: 'error',
disabled: busy,
onSelect: () => deleteBooking(booking)
}
])
return items
}
function openBookingEditor(booking: PublicBooking) {
detailsBooking.value = booking
detailsForm.customerName = booking.customerName