Today's Appointments Timeline view of all bookings
{#if loading}
{#each Array(5) as _, i (i)}
{/each}
{:else if timeline.length === 0}

No appointments today

Looks like you have a quiet day

{:else}
{#each timeline as item (item.id)} {#if item.type === 'appointment'}
{formatTime(item.data.start_time)}
{item.data.services.join(', ')} {formatDuration(item.data.duration_minutes)}
{:else if item.type === 'blocker'}
{formatTime(item.data.start_time)}
{item.data.description || 'Untitled'}
{formatDuration(item.data.duration_minutes)}
{:else if item.type === 'lunch'}
{item.data.startLabel}

Suggested lunch: {formatDuration(item.data.duration)} available

{item.data.startLabel} – {item.data.endLabel}

{/if} {/each}
{/if}
Add Time Blocker Block off a period of time today.

Defaults to "break" if left empty

Start Time

{#if whLoading} {:else if !workingHours}

Loading working hours…

{:else if !workingHours.isOpen}

Closed today

{:else} {/if}

End Time

{#if whLoading} {:else if !workingHours}

Loading working hours…

{:else if !workingHours.isOpen}

Closed today

{:else if availableEndOptions.length === 0}

No available end time after selected start

{:else} {/if}
{#if checkingOverlap}
Checking for conflicting bookings…
{:else if hasOverlap}
Booking exists in this timeslot
{#each overlappingBookings as booking (booking.id)}
{booking.user?.full_name || 'Unknown'}
{new SvelteDate(booking.start_time).toLocaleTimeString('en-GB', { hour: 'numeric', minute: '2-digit', hour12: true })} {' · '}{formatDuration(booking.duration_minutes)} {#if booking.services?.length} {' · '}{booking.services.join(', ')}{/if}
{#if booking.user?.id} {/if}
{/each}
{/if}
Delete time blocker? This will remove the "{blockerToDelete?.description}" time blocker. This action cannot be undone. { showDeleteAlert = false; blockerToDelete = null; }}>Cancel Delete