feat(frontend): add former name display, referral discount type, and refunds to bookings

Update frontend types, stores, and components to support name history display and new API fields.

- Add previousFirstName/previousLastName to User type and BookingUser type
- Add referral discount_source type and refunds array to Booking type
- Create nameDisplay.ts utility for rendering '(formerly ...)' labels
- Create booking.ts utility for booking-related helpers
- Update 25+ admin, payments, today, and account components to display
  former names on booking cards, modals, appointment views, and user lists

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-06-20 16:59:31 +01:00
co-authored by Sisyphus
parent 1cf7083bcc
commit 1a3829b4d9
27 changed files with 597 additions and 300 deletions
@@ -5,6 +5,7 @@
import * as Modal from '$lib/components/ui/dialog';
import { Button } from '$lib/components/ui/button';
import * as AlertDialog from '$lib/components/ui/alert-dialog';
import { formatUserName } from '$lib/utils/nameDisplay';
interface ServiceItem {
id: string;
@@ -36,6 +37,8 @@
full_name: string;
email: string;
phone: string;
previous_first_name?: string | null;
previous_last_name?: string | null;
};
}
@@ -181,7 +184,7 @@
<Modal.Header>
<Modal.Title class="text-lg font-semibold">Booking Change Request</Modal.Title>
<Modal.Description>
Review the requested changes to {editRequest.user.full_name}'s booking.
Review the requested changes to {formatUserName(editRequest.user.full_name, editRequest.user.previous_first_name, editRequest.user.previous_last_name)}'s booking.
</Modal.Description>
</Modal.Header>
@@ -194,22 +197,30 @@
<div class="space-y-2">
<div>
<div class="text-xs text-gray-500">Name</div>
<div class="font-medium">{editRequest.user.full_name}</div>
<div class="font-medium">{formatUserName(editRequest.user.full_name, editRequest.user.previous_first_name, editRequest.user.previous_last_name)}</div>
</div>
<div class="grid gap-3 md:grid-cols-2">
<div>
<div class="text-xs text-gray-500">Phone</div>
<div class="font-medium">{editRequest.user.phone || '—'}</div>
<div class="font-medium">
{#if editRequest.user.phone}
<a href="tel:{editRequest.user.phone}" class="text-blue-600 hover:underline">{editRequest.user.phone}</a>
{:else}{/if}
</div>
</div>
<div>
<div class="text-xs text-gray-500">Email</div>
<div class="font-medium break-all">{editRequest.user.email || '—'}</div>
<div class="font-medium break-all">
{#if editRequest.user.email}
<a href="mailto:{editRequest.user.email}" class="text-blue-600 hover:underline">{editRequest.user.email}</a>
{:else}{/if}
</div>
</div>
</div>
</div>
</div>
<!-- Date & Time Change -->
{#if isTimeChanged()}
<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
<h3 class="mb-3 text-sm font-semibold tracking-wide text-gray-600 uppercase">
Date & Time Change
@@ -227,26 +238,23 @@
)}
</div>
</div>
{#if isTimeChanged()}
<div>
<div class="mb-1 text-xs text-gray-500">After</div>
<div class="font-medium text-emerald-700">
{formatDateLine1(editRequest.proposed.start_time!)}
</div>
<div class="text-sm text-gray-600">
{formatDateLine2(
editRequest.proposed.start_time!,
getDuration(editRequest.proposed.services)
)}
</div>
<div>
<div class="mb-1 text-xs text-gray-500">After</div>
<div class="font-medium text-emerald-700">
{formatDateLine1(editRequest.proposed.start_time!)}
</div>
{:else}
<div class="text-sm text-gray-500 italic">No change</div>
{/if}
<div class="text-sm text-gray-600">
{formatDateLine2(
editRequest.proposed.start_time!,
getDuration(editRequest.proposed.services)
)}
</div>
</div>
</div>
</div>
{/if}
<!-- Services Change -->
{#if areServicesChanged()}
<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
<h3 class="mb-3 text-sm font-semibold tracking-wide text-gray-600 uppercase">
Services Change
@@ -314,8 +322,9 @@
</div>
</div>
</div>
{/if}
<!-- Notes Change -->
{#if editRequest.proposed.notes !== editRequest.original.notes}
<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
<h3 class="mb-3 text-sm font-semibold tracking-wide text-gray-600 uppercase">
Booking Notes Change
@@ -327,14 +336,11 @@
</div>
<div>
<div class="mb-1 text-xs text-gray-500">Proposed</div>
{#if editRequest.proposed.notes && editRequest.proposed.notes !== editRequest.original.notes}
<div class="text-sm">{editRequest.proposed.notes}</div>
{:else}
<div class="text-sm text-gray-500 italic">No change</div>
{/if}
<div class="text-sm">{editRequest.proposed.notes}</div>
</div>
</div>
</div>
{/if}
<!-- Request Notes -->
{#if editRequest.notes}