Walk-In Booking Quickly book a walk-in customer with immediate time slot reservation
{#if reservationExpiresAt && !isReservationExpired}
Slot held for
{reservationCountdown}
{:else if isReservationExpired}
Slot released — please re-check availability
{/if} {#if currentStep === 1} Select Customer Choose an existing member or create a guest booking
{#if userType === 'member'}
{ userQuery = e.currentTarget.value; }} onkeydown={(e) => { if (e.key === 'Enter') { e.preventDefault(); fetchUsers(); } }} />
{#if loadingUsers}
{#each Array(3) as _, i (i)} {/each}
{:else if users.length === 0}
{userQuery ? 'No users found. Try a different search.' : 'Search for a user above to get started.'}
{:else}
    {#each users.slice(0, 4) as user (user.id)}
  • {/each}
{/if}
{:else}
(guestName = e.currentTarget.value)} />
{ guestPhone = e.currentTarget.value; }} onblur={() => { if (guestPhone && !isValidUKPhone(guestPhone)) guestPhoneError = 'Invalid UK phone number'; else guestPhoneError = ''; }} /> {#if guestPhoneError}

{guestPhoneError}

{/if}

Booking as a guest creates a temporary record. Encourage them to sign up for loyalty benefits.

{/if}
currentStep++} />
{/if} {#if currentStep === 2} Choose Services Select one or more treatments for this appointment {#if loadingServices}
{#each Array(4) as _, i (i)} {/each}
{:else if services.length === 0}

No services available.

{:else} {/if} {#if selectedServices.length > 0}

Selected Services

{#each selectedServices as service (service.id)}
{service.name} {service.duration_minutes} mins • £{service.price}
{/each}
Estimated Duration: {formattedTotalDuration}
Total Cost: £{getTotalPrice()}
{#if maxSlotDuration > 0}
Available Slot Duration: {formatDuration(maxSlotDuration)}
{#if isOverDuration}
Warning: Selected services ({formattedTotalDuration}) exceed available slot duration ({formatDuration(maxSlotDuration)}). Please remove services or customize durations.
{/if} {/if}
{/if}
{/if} {#if currentStep === 3} Customize Services Adjust pricing or duration if needed, and add appointment notes

Service Details

Override default pricing or duration for special cases (discounts, extended sessions, etc.)

{#each selectedServices as service (service.id)} {#if serviceOverrides[service.id]}
{service.name}
handlePriceInput(service.id, e.currentTarget.value)} />
handleDurationInput(service.id, e.currentTarget.value)} />
{#if serviceOverrides[service.id] && (Math.abs(parseFloat(serviceOverrides[service.id].price) - serviceOverrides[service.id].originalPrice) > 0.01 || parseInt(serviceOverrides[service.id].duration) !== serviceOverrides[service.id].originalDuration)}
{#if Math.abs(parseFloat(serviceOverrides[service.id].price) - serviceOverrides[service.id].originalPrice) > 0.01} Price modified from £{serviceOverrides[ service.id ].originalPrice.toFixed(2)} {/if} {#if Math.abs(parseFloat(serviceOverrides[service.id].price) - serviceOverrides[service.id].originalPrice) > 0.01 && parseInt(serviceOverrides[service.id].duration) !== serviceOverrides[service.id].originalDuration} • {/if} {#if parseInt(serviceOverrides[service.id].duration) !== serviceOverrides[service.id].originalDuration} Duration modified from {serviceOverrides[service.id].originalDuration} mins {/if}
{/if}
{/if} {/each}
Total Duration: {formattedTotalDuration}
Total Cost: £{getTotalPrice().toFixed(2)}
{/if}