diff --git a/frontend/src/routes/prices/+page.svelte b/frontend/src/routes/prices/+page.svelte index e65cd7e..d061c3b 100644 --- a/frontend/src/routes/prices/+page.svelte +++ b/frontend/src/routes/prices/+page.svelte @@ -3,96 +3,75 @@ import { Button } from '$lib/components/ui/button/index.js'; import { Separator } from '$lib/components/ui/separator/index.js'; import { toast } from 'svelte-sonner'; + import { authStore } from '$lib/stores/auth.svelte'; - const services = [ - { - category: 'Nail Services', - items: [ - { - service: 'Classic Manicure', - duration: '45 minutes', - price: '£25.00', - description: 'Shape, cuticle care, polish' - }, - { - service: 'Gel Manicure', - duration: '1 hour', - price: '£35.00', - description: 'Long-lasting gel polish application' - }, - { - service: 'Classic Pedicure', - duration: '1 hour', - price: '£30.00', - description: 'Soak, exfoliate, shape, polish' - }, - { - service: 'Gel Pedicure', - duration: '1 hour 15 minutes', - price: '£40.00', - description: 'Premium pedicure with gel polish' - }, - { - service: 'Nail Art', - duration: '30 minutes', - price: '£15.00', - description: 'Custom designs and decorations' - }, - { - service: 'Nail Removal', - duration: '20 minutes', - price: '£10.00', - description: 'Safe gel or acrylic removal' + type Service = { + id: string; + name: string; + description: string; + price: number; + duration_minutes: number; + patch_test_duration_hours: number; + minimum_age_required: number; + }; + + let services = $state([]); + let servicesLoading = $state(true); + + // Fetch active services for the price list + async function fetchServices() { + servicesLoading = true; + try { + const response = await fetch('/api/services', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${authStore.currentToken}` } - ] - }, - { - category: 'Eyebrow Services', - items: [ - { - service: 'Eyebrow Shaping', - duration: '30 minutes', - price: '£15.00', - description: 'Wax and tweeze to perfect shape' - }, - { - service: 'Eyebrow Tint & Shape', - duration: '45 minutes', - price: '£25.00', - description: 'Shape and tint for definition' - } - ] - }, - { - category: 'Waxing Services', - items: [ - { - service: 'Full Leg Wax', - duration: '1 hour', - price: '£35.00', - description: 'Smooth legs from ankle to hip' - }, - { - service: 'Half Leg Wax', - duration: '30 minutes', - price: '£20.00', - description: 'Lower or upper leg waxing' - }, - { - service: 'Bikini Wax', - duration: '30 minutes', - price: '£20.00', - description: 'Clean bikini line waxing' - }, - { - service: 'Underarm Wax', - duration: '15 minutes', - price: '£12.00', - description: 'Quick and comfortable underarm waxing' - } - ] + }); + + if (response.ok) { + const data: Service[] = await response.json(); + services = data; + } else { + console.error('Failed to fetch services:', response.status); + toast.error('Failed to load services'); + // Fallback to empty array + services = []; + } + } catch (err) { + console.error('Error fetching services:', err); + toast.error('Network error loading services'); + // Fallback to empty array + services = []; + } finally { + servicesLoading = false; } - ]; + } + + // Format duration from minutes to human readable + function formatDuration(minutes: number): string { + const hours = Math.floor(minutes / 60); + const remainingMinutes = minutes % 60; + + if (hours === 0) { + return `${remainingMinutes} minutes`; + } else if (remainingMinutes === 0) { + return `${hours} ${hours === 1 ? 'hour' : 'hours'}`; + } else { + return `${hours} ${hours === 1 ? 'hour' : 'hours'} ${remainingMinutes} minutes`; + } + } + + // Format price as currency + function formatPrice(price: number): string { + return `£${price.toFixed(2)}`; + } + + // Initialize on component mount + $effect(() => { + fetchServices(); + });
@@ -101,95 +80,108 @@

Professional beauty treatments with transparent pricing

-
- {#each services as category, categoryIndex} -
-
-

{category.category}

-
-
- {#each category.items as service, index} - -
-
-
-

{service.service}

-

{service.description}

- -

- - - - - {service.duration} - -

-
-
- -
{service.price}
- - -
+ {#if servicesLoading} +
+
+
Loading services...
+
+
+
+ {:else if services.length === 0} +
+
No services available at the moment.
+ +
+ {:else} +
+ {#each services as service, index} + +
+
+
+

{service.name}

+

{service.description}

+ +

+ + + + + {formatDuration(service.duration_minutes)} + +

+ {#if service.patch_test_duration_hours > 0} +

+ Patch test required {service.patch_test_duration_hours}h before appointment +

+ {/if} + {#if service.minimum_age_required > 0} +

+ Minimum age: {service.minimum_age_required} years +

+ {/if} +
+
+ +
{formatPrice(service.price)}
+ +
- {/each} +
-
- - {#if categoryIndex < services.length - 1} - - {/if} - {/each} -
- - - - -
-

Important Information:

-
    -
  • - • Prices and durations are estimates and may vary based on individual requirements -
  • -
  • • Patch tests are required 24-48 hours before certain treatments
  • -
  • • 24 hours notice required for cancellations
  • -
  • • Payment is due at the time of service
  • -
  • • Deposit required for new and guest accounts
  • -
-
-
-
- - -
-

Ready to Book?

-
- - + + {#if index < services.length - 1} + + {/if} + {/each}
-
+ + + + +
+

Important Information:

+
    +
  • + • Prices and durations are estimates and may vary based on individual requirements +
  • +
  • • Patch tests are required 24-48 hours before certain treatments
  • +
  • • 24 hours notice required for cancellations
  • +
  • • Payment is due at the time of service
  • +
  • • Deposit required for new and guest accounts
  • +
+
+
+
+ + +
+

Ready to Book?

+
+ + +
+
+ {/if}