feat(bookings): improve admin booking wizard and user dashboard

Backend:
- Enriched GetAllUserBookings response with calculated total_amount,
  amount_paid, and duration_minutes.
- Refactored GetBookingHandler to return a flat booking object matching
  frontend expectations.
- Added account_role to admin user list response and sorted users by
  booking activity.
- Corrected function name oo to AdminCreateBookingForUserHandler.

Frontend:
- Rebuilt BookingCreateModal into a 4-step wizard supporting guest
  bookings, service overrides, and real-time availability checks.
- Fixed account dashboard logic to correctly identify upcoming vs past
  bookings and sort unpaid items to the top.
- Extracted booking flow into a shared BookingFlow component.
- Redirected admin users from home page to /today.
This commit is contained in:
2026-02-12 22:15:10 +00:00
parent 2ace6d4d87
commit 50746595e7
34 changed files with 7688 additions and 5413 deletions
@@ -0,0 +1,48 @@
<script lang="ts">
import type { Service } from '$lib/types/booking';
let {
service,
selected = false,
onclick
}: {
service: Service;
selected?: boolean;
onclick?: () => void;
} = $props();
</script>
<button
type="button"
class="cursor-pointer rounded-lg border border-input bg-background p-4 text-left transition-colors hover:bg-fuchsia-50 hover:text-accent-foreground {selected
? 'bg-fuchsia-100'
: ''}"
onclick={() => onclick?.()}
>
<div class="flex items-start justify-between">
<div class="flex-1">
<h3 class="font-semibold">{service.name}</h3>
<p class="text-sm text-gray-600">{service.description}</p>
<div class="mt-2 flex items-center space-x-4 text-sm text-gray-500">
<span>{service.duration_minutes} mins</span>
<span>£{service.price}</span>
</div>
</div>
<div
class="ml-3 flex h-5 w-5 items-center justify-center rounded border-2 {selected
? 'border-primary bg-primary'
: 'border-gray-300'}"
aria-hidden="true"
>
{#if selected}
<svg class="h-3 w-3 text-white" fill="currentColor" viewBox="0 0 20 20">
<path
fill-rule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clip-rule="evenodd"
></path>
</svg>
{/if}
</div>
</div>
</button>