From db5f6ff1358563a31190eca6547c22e8c461ef7c Mon Sep 17 00:00:00 2001 From: Stephen Adamson Date: Thu, 28 May 2026 16:31:22 +0100 Subject: [PATCH] fix: admin booking modals and schedule components polish Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../lib/components/admin/BookingModal.svelte | 40 +++++++++++++++++-- .../components/admin/EditBookingModal.svelte | 4 +- .../lib/components/admin/HolidayHours.svelte | 36 +++++++++++------ .../src/lib/components/admin/UserModal.svelte | 30 +++++++++----- .../components/admin/WalkInCreateModal.svelte | 5 ++- .../components/admin/WeeklySchedule.svelte | 25 ++++++++---- 6 files changed, 104 insertions(+), 36 deletions(-) diff --git a/frontend/src/lib/components/admin/BookingModal.svelte b/frontend/src/lib/components/admin/BookingModal.svelte index 22a40e5..04d7b7f 100644 --- a/frontend/src/lib/components/admin/BookingModal.svelte +++ b/frontend/src/lib/components/admin/BookingModal.svelte @@ -5,17 +5,20 @@ import * as Modal from '$lib/components/ui/dialog'; import { Button } from '$lib/components/ui/button'; import ApprovalModal from '$lib/components/admin/ApprovalModal.svelte'; + import RescheduleModal from '$lib/components/admin/RescheduleModal.svelte'; import type { Booking } from '$lib/types/booking'; interface Props { open: boolean; bookingId: string; + onReschedule?: () => void; } - let { open = $bindable(), bookingId }: Props = $props(); + let { open = $bindable(), bookingId, onReschedule }: Props = $props(); let selectedBooking = $state(null); let showApprovalModal = $state(false); + let showRescheduleModal = $state(false); // Calculate total duration from services // IMPORTANT: Use override_duration_minutes when present — services may have been @@ -131,7 +134,7 @@ - +
@@ -302,7 +305,7 @@
Email
-
{selectedBooking.user?.email || '—'}
+
{selectedBooking.user?.email || '—'}
Phone
@@ -478,6 +481,24 @@ {/if} + {#if selectedBooking && !['completed', 'client_cancelled', 'we_cancelled', 'no_show', 'no_deposit'].includes(selectedBooking.status)} + + {/if} @@ -494,3 +515,16 @@ }} /> {/if} + + +{#if selectedBooking && showRescheduleModal} + { + showRescheduleModal = false; + fetchBookingDetails(); + onReschedule?.(); + }} + /> +{/if} diff --git a/frontend/src/lib/components/admin/EditBookingModal.svelte b/frontend/src/lib/components/admin/EditBookingModal.svelte index 1c473d4..8259833 100644 --- a/frontend/src/lib/components/admin/EditBookingModal.svelte +++ b/frontend/src/lib/components/admin/EditBookingModal.svelte @@ -390,7 +390,7 @@ - +
@@ -418,7 +418,7 @@
Email
-
{booking.user?.email || '—'}
+
{booking.user?.email || '—'}
Phone
diff --git a/frontend/src/lib/components/admin/HolidayHours.svelte b/frontend/src/lib/components/admin/HolidayHours.svelte index 61b6b40..4165484 100644 --- a/frontend/src/lib/components/admin/HolidayHours.svelte +++ b/frontend/src/lib/components/admin/HolidayHours.svelte @@ -13,6 +13,8 @@ import * as AlertDialog from '$lib/components/ui/alert-dialog'; import { Skeleton } from '$lib/components/ui/skeleton'; + const TIME15 = ['00', '15', '30', '45']; + // =============== Types =============== type WorkingHourRow = { weekday: number; @@ -527,20 +529,30 @@ - + - + {/each} diff --git a/frontend/src/lib/components/admin/UserModal.svelte b/frontend/src/lib/components/admin/UserModal.svelte index 58e38eb..0995aa9 100644 --- a/frontend/src/lib/components/admin/UserModal.svelte +++ b/frontend/src/lib/components/admin/UserModal.svelte @@ -225,13 +225,12 @@ }); function handleOpenBooking(bookingId: string) { - open = false; openBookingModal(bookingId); } - +
@@ -271,7 +270,7 @@
Email
-
{selectedUser.email || '—'}
+
{selectedUser.email || '—'}
Phone
@@ -280,13 +279,23 @@
Date of Birth
- {selectedUser.dateOfBirth - ? new SvelteDate(selectedUser.dateOfBirth).toLocaleDateString('en-US', { + {#if selectedUser.dateOfBirth} + {(() => { + const dob = new SvelteDate(selectedUser.dateOfBirth); + const dateStr = dob.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' - }) - : '—'} + }); + const today = new Date(); + let age = today.getFullYear() - dob.getFullYear(); + const m = today.getMonth() - dob.getMonth(); + if (m < 0 || (m === 0 && today.getDate() < dob.getDate())) age--; + return `${dateStr} (${age})`; + })()} + {:else} + — + {/if}
@@ -308,9 +317,10 @@
{#if customerRelationship?.lastVisitDate} {new SvelteDate(customerRelationship.lastVisitDate).toLocaleDateString('en-US', { - year: 'numeric', + weekday: 'short', + day: 'numeric', month: 'short', - day: 'numeric' + year: 'numeric' })} {:else} — @@ -324,7 +334,7 @@ Profile
{/if} diff --git a/frontend/src/lib/components/admin/WalkInCreateModal.svelte b/frontend/src/lib/components/admin/WalkInCreateModal.svelte index e80d057..5687f13 100644 --- a/frontend/src/lib/components/admin/WalkInCreateModal.svelte +++ b/frontend/src/lib/components/admin/WalkInCreateModal.svelte @@ -373,6 +373,7 @@ if (res.ok) { toast.success('Booking created successfully!'); open = false; + window.dispatchEvent(new CustomEvent('bookingApproved')); onBookingCreated?.(); } else { const errorText = await res.text(); @@ -413,7 +414,7 @@ - + Walk-In Booking @@ -724,7 +725,7 @@ {#if serviceOverrides[service.id]}
{service.name}
-
+
- + > + {#each Array(24) as _, hour} + {#each TIME15 as min} + + {/each} + {/each} + - + > + {#each Array(24) as _, hour} + {#each TIME15 as min} + + {/each} + {/each} + {/each}