feat: add email verification, profile pictures, deposits, and calendar
export Backend: - Add email verification code generation and verification endpoints - Add profile picture upload with S3 storage and image processing - Add deposit_required field to users with 48h advance booking requirement - Add loyalty stamps that accumulate on completed bookings - Auto-transition bookings: confirmed → in_progress → completed - Add booking cancellation handler with no-show detection - Add ICS calendar file download endpoint for bookings - Sync bookings to CalDAV on confirmation Frontend: - Add schedule page route - Add avatar and image-cropper UI components - Update shadcn-svelte components (button, dialog) - Add "Add to Calendar" button in booking modal Database: - Add verification_codes table - Add profile_pic_url, loyalty_stamps, deposits_required to users - Various schema updates
This commit is contained in:
@@ -131,7 +131,7 @@
|
||||
|
||||
interval = setInterval(() => {
|
||||
calculateTimes();
|
||||
}, 60000); // Update every minute
|
||||
}, 15000); // Update every 15 seconds
|
||||
|
||||
return () => {
|
||||
if (interval) clearInterval(interval);
|
||||
@@ -193,18 +193,22 @@
|
||||
|
||||
{#if activeAppointment}
|
||||
{#if isInProgress}
|
||||
<Badge class="bg-blue-100 px-3 py-1 text-sm text-blue-800">
|
||||
<span class="relative mr-2 flex h-2 w-2">
|
||||
<span
|
||||
class="absolute inline-flex h-full w-full animate-ping rounded-full bg-blue-400 opacity-75"
|
||||
></span>
|
||||
<span class="relative inline-flex h-2 w-2 rounded-full bg-blue-600"></span>
|
||||
</span>
|
||||
In Progress • {timeRemaining} min remaining
|
||||
{#if freeTimeAfter > 0}
|
||||
• {freeTimeAfter} min free
|
||||
<div class="flex flex-col gap-2 items-end">
|
||||
<Badge class="bg-blue-100 px-3 py-1 text-sm text-blue-800">
|
||||
<span class="relative mr-2 flex h-2 w-2">
|
||||
<span
|
||||
class="absolute inline-flex h-full w-full animate-ping rounded-full bg-blue-400 opacity-75"
|
||||
></span>
|
||||
<span class="relative inline-flex h-2 w-2 rounded-full bg-blue-600"></span>
|
||||
</span>
|
||||
In Progress • {timeRemaining} min remaining
|
||||
</Badge>
|
||||
{#if freeTimeAfter > 0 && timeRemaining > 29}
|
||||
<Badge class="bg-blue-100 px-3 py-1 text-sm text-blue-800">
|
||||
{freeTimeAfter} min free afterwards
|
||||
</Badge>
|
||||
{/if}
|
||||
</Badge>
|
||||
</div>
|
||||
{:else}
|
||||
<Badge class="bg-amber-100 px-3 py-1 text-sm text-amber-800">
|
||||
Starts in {timeRemaining} min
|
||||
@@ -259,10 +263,11 @@
|
||||
class="h-20 w-20 rounded-full object-cover ring-4 ring-blue-200"
|
||||
/>
|
||||
{:else}
|
||||
{@const initials = activeAppointment.user?.full_name?.split(' ').map(n => n[0]).join('') || '?'}
|
||||
<div
|
||||
class="flex h-20 w-20 items-center justify-center rounded-full bg-gray-200 text-2xl font-bold text-gray-600 ring-4 ring-blue-200"
|
||||
>
|
||||
{activeAppointment.user?.full_name?.charAt(0) || '?'}
|
||||
{initials}
|
||||
</div>
|
||||
{/if}
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user