- Add eligibility filtering to /api/services: exclude services below
user's
age, gray out services requiring patch tests that are missing/expired
- Add new endpoint /api/services/eligible-for/{user_id} for admin
booking
flows to check eligibility for a specific user
- Add image metadata stripping: uploads now strip all EXIF/GPS data
via imaging library (security improvement)
- Update ServiceCard frontend: show grayed-out state for ineligible
services with "contact us" link (public) or just warning (admin)
- Add 2 patch test services to seed data: Gel Polish Full Set,
Luxury Gel Manicure (48h each)
- Remove deprecated local-dev.sh script
53 lines
1.4 KiB
Svelte
53 lines
1.4 KiB
Svelte
<script lang="ts">
|
|
import type { Service } from '$lib/types/booking';
|
|
|
|
let {
|
|
service,
|
|
selected = false,
|
|
onclick,
|
|
showContactLink = false
|
|
}: {
|
|
service: Service;
|
|
selected?: boolean;
|
|
onclick?: () => void;
|
|
showContactLink?: boolean;
|
|
} = $props();
|
|
|
|
const isGrayedOut = $derived(
|
|
service.patch_test_status === 'required' || service.patch_test_status === 'expired'
|
|
);
|
|
</script>
|
|
|
|
<button
|
|
type="button"
|
|
class="cursor-pointer rounded-lg border border-input bg-background p-4 text-left transition-colors hover:bg-fuchsia-50 hover:text-accent-foreground {selected
|
|
? 'bg-fuchsia-100'
|
|
: ''} {isGrayedOut ? 'opacity-50' : ''}"
|
|
onclick={() => !isGrayedOut && onclick?.()}
|
|
disabled={isGrayedOut}
|
|
>
|
|
<div class="flex flex-col justify-between h-full min-h-[6rem]">
|
|
<div>
|
|
<h3 class="font-semibold">{service.name}</h3>
|
|
{#if isGrayedOut}
|
|
<p class="text-sm text-amber-600">
|
|
{#if service.patch_test_status === 'required'}
|
|
Patch test required
|
|
{:else}
|
|
Patch test expired
|
|
{/if}
|
|
{#if showContactLink}
|
|
- <a href="/contact" class="underline">contact us</a>
|
|
{/if}
|
|
</p>
|
|
{:else}
|
|
<p class="text-sm text-gray-600">{service.description}</p>
|
|
{/if}
|
|
</div>
|
|
<div class="flex items-center justify-between mt-2 text-sm text-gray-500">
|
|
<span>{service.duration_minutes} mins</span>
|
|
<span class="font-semibold text-foreground">£{service.price}</span>
|
|
</div>
|
|
</div>
|
|
</button>
|