From 3d334a6b96836823398bb53399331085c8f5e25d Mon Sep 17 00:00:00 2001 From: Chris Dumas Date: Tue, 26 May 2026 09:39:10 +0000 Subject: [PATCH] Implement property detail and enquiry entry flow --- prisma/seed.ts | 24 +-- src/app/bookings/new/page.tsx | 31 ++- src/app/contact/page.tsx | 28 ++- src/app/layout.tsx | 75 ++++++++ src/app/page.tsx | 7 +- src/app/properties/[slug]/page.tsx | 296 +++++++++++++++++++++++++++++ src/lib/booking.ts | 117 ++++-------- src/lib/properties.ts | 179 +++++++++++++++++ src/lib/propertySeedData.ts | 258 +++++++++++++++++++++++++ src/lib/site.ts | 48 ++--- tests/e2e/property-detail.spec.ts | 36 ++++ 11 files changed, 966 insertions(+), 133 deletions(-) create mode 100644 src/app/properties/[slug]/page.tsx create mode 100644 src/lib/properties.ts create mode 100644 src/lib/propertySeedData.ts create mode 100644 tests/e2e/property-detail.spec.ts diff --git a/prisma/seed.ts b/prisma/seed.ts index d9f2154..1976b00 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -1,23 +1,24 @@ import { PrismaClient } from '@prisma/client'; +import { seedPropertyInventory } from '@/lib/properties'; const prisma = new PrismaClient(); async function main() { const existing = await prisma.siteSettings.findFirst(); - if (existing) { - return; + if (!existing) { + await prisma.siteSettings.create({ + data: { + businessName: 'Holiday Property Booking', + tagline: 'Curated stays, clear availability, and a direct booking flow.', + contactEmail: 'hello@example.com', + defaultSeoTitle: 'Holiday Property Booking', + defaultSeoDescription: 'Book holiday properties with live availability, clear pricing, and secure checkout.', + }, + }); } - await prisma.siteSettings.create({ - data: { - businessName: 'Holiday Property Booking', - tagline: 'Curated stays, clear availability, and a direct booking flow.', - contactEmail: 'hello@example.com', - defaultSeoTitle: 'Holiday Property Booking', - defaultSeoDescription: 'Book holiday properties with live availability, clear pricing, and secure checkout.', - }, - }); + await seedPropertyInventory(); } main() @@ -28,4 +29,3 @@ main() .finally(async () => { await prisma.$disconnect(); }); - diff --git a/src/app/bookings/new/page.tsx b/src/app/bookings/new/page.tsx index 40409ef..4315a07 100644 --- a/src/app/bookings/new/page.tsx +++ b/src/app/bookings/new/page.tsx @@ -10,6 +10,12 @@ export const metadata: Metadata = { description: 'Start a holiday property booking, check the live quote core, and continue to checkout.', }; +type NewBookingPageProps = { + searchParams?: Promise<{ + propertySlug?: string; + }>; +}; + async function startBooking(formData: FormData) { 'use server'; @@ -32,7 +38,12 @@ async function startBooking(formData: FormData) { redirect(result.checkoutUrl); } -export default function NewBookingPage() { +export default async function NewBookingPage({ searchParams }: NewBookingPageProps) { + const resolvedSearchParams = searchParams ? await searchParams : undefined; + const selectedPropertySlug = resolvedSearchParams?.propertySlug; + const selectedProperty = + bookingCatalog.find((property) => property.slug === selectedPropertySlug) ?? bookingCatalog[0] ?? null; + return ( <>
@@ -48,12 +59,16 @@ export default function NewBookingPage() {