Adds the complete Next.js website including i18n routing, house and apartment pages, Beds24 v2 integration for live availability/pricing, Stripe checkout, contact forms, Docker setup and deployment docs. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
96 lines
3.7 KiB
TypeScript
96 lines
3.7 KiB
TypeScript
"use client";
|
|
|
|
import { useTranslations } from "next-intl";
|
|
import { useRouter } from "next/navigation";
|
|
import { useState } from "react";
|
|
import { Calendar, ArrowRight } from "lucide-react";
|
|
import { tomorrowDateString, addMonths } from "@/src/lib/date";
|
|
|
|
interface BookingBannerProps {
|
|
locale: string;
|
|
}
|
|
|
|
export function BookingBanner({ locale }: BookingBannerProps) {
|
|
const t = useTranslations("home.bookingBanner");
|
|
const router = useRouter();
|
|
const [arrival, setArrival] = useState(tomorrowDateString());
|
|
const [months, setMonths] = useState(3);
|
|
|
|
const handleSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
const departure = addMonths(arrival, months);
|
|
const searchParams = new URLSearchParams({
|
|
arrival,
|
|
departure,
|
|
months: String(months),
|
|
});
|
|
router.push(`/${locale}/houses?${searchParams.toString()}`);
|
|
};
|
|
|
|
return (
|
|
<section className="relative z-20 -mt-16 mb-24">
|
|
<div className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<form
|
|
onSubmit={handleSubmit}
|
|
className="bg-white rounded-3xl shadow-2xl shadow-brand-grey-dark/15 border border-brand-grey-soft/80 overflow-hidden"
|
|
>
|
|
<div className="h-1.5 w-full bg-gradient-to-r from-brand-green via-brand-green-light to-brand-green" />
|
|
<div className="p-8 md:p-10">
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 items-end">
|
|
<div className="space-y-3">
|
|
<label
|
|
htmlFor="booking-arrival"
|
|
className="flex items-center gap-2 text-base font-bold text-brand-grey-dark"
|
|
>
|
|
<Calendar className="w-5 h-5 text-brand-green" />
|
|
{t("arrival")}
|
|
</label>
|
|
<div className="relative">
|
|
<input
|
|
id="booking-arrival"
|
|
type="date"
|
|
required
|
|
value={arrival}
|
|
min={tomorrowDateString()}
|
|
onChange={(e) => setArrival(e.target.value)}
|
|
className="w-full pl-4 pr-4 py-4 text-lg rounded-xl border-2 border-brand-grey-soft/60 bg-brand-grey-soft/20 text-brand-grey-dark focus:outline-none focus:ring-2 focus:ring-brand-green focus:border-transparent transition-all"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<label
|
|
htmlFor="booking-months"
|
|
className="block text-base font-bold text-brand-grey-dark"
|
|
>
|
|
{t("stayMonths")}
|
|
</label>
|
|
<div className="relative">
|
|
<input
|
|
id="booking-months"
|
|
type="number"
|
|
min={1}
|
|
max={24}
|
|
required
|
|
value={months}
|
|
onChange={(e) => setMonths(Number(e.target.value))}
|
|
className="w-full px-4 py-4 text-lg text-center rounded-xl border-2 border-brand-grey-soft/60 bg-brand-grey-soft/20 text-brand-grey-dark focus:outline-none focus:ring-2 focus:ring-brand-green focus:border-transparent transition-all"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
type="submit"
|
|
className="inline-flex items-center justify-center gap-3 bg-brand-green text-white text-lg font-bold px-8 py-4 rounded-xl hover:bg-brand-green-dark hover:shadow-xl hover:-translate-y-1 transition-all"
|
|
>
|
|
{t("checkAvailability")}
|
|
<ArrowRight className="w-6 h-6" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|