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
@@ -3,6 +3,7 @@
import { SvelteDate } from 'svelte/reactivity';
import { toast } from 'svelte-sonner';
import { formatDuration } from '$lib/utils/format';
import { formatUserName } from '$lib/utils/nameDisplay';
import * as Card from '$lib/components/ui/card';
import { Button } from '$lib/components/ui/button';
import { Badge } from '$lib/components/ui/badge';
@@ -35,6 +36,8 @@
full_name: string;
phone?: string;
profile_pic_url?: string;
previous_first_name?: string;
previous_last_name?: string;
};
services: Array<{
service_name?: string;
@@ -645,7 +648,7 @@
{#if activeAppointment.user?.profile_pic_url}
<img
src={activeAppointment.user.profile_pic_url}
alt={activeAppointment.user.full_name}
alt={formatUserName(activeAppointment.user.full_name, activeAppointment.user.previous_first_name, activeAppointment.user.previous_last_name)}
class="h-14 w-14 shrink-0 rounded-full object-cover ring-2 ring-blue-200 sm:h-16 sm:w-16 sm:ring-4 md:h-20 md:w-20"
/>
{:else}
@@ -660,11 +663,11 @@
{initials}
</div>
{/if}
<div class="min-w-0">
<div class="truncate text-lg font-semibold">
{activeAppointment.user?.full_name || 'Guest'}
</div>
<div class="truncate text-sm text-gray-600">{activeAppointment.user?.phone || '—'}</div>
<div class="min-w-0">
<div class="truncate text-lg font-semibold">
{formatUserName(activeAppointment.user?.full_name || 'Guest', activeAppointment.user?.previous_first_name, activeAppointment.user?.previous_last_name)}
</div>
<div class="truncate text-sm text-gray-600">{activeAppointment.user?.phone || '—'}</div>
{#if activeAppointment.user}
<button
type="button"