Initial commit: demo sito clinica veterinaria

This commit is contained in:
2026-04-04 10:14:07 +02:00
commit 0ca0306a34
111 changed files with 17895 additions and 0 deletions

View File

@@ -0,0 +1,328 @@
/*
* DESIGN: "Clinical Warmth"
* Sezione prenotazione: form elegante su sfondo blu petrolio
* Layout: testo a sinistra + form a destra
*/
import { useState } from "react";
import { motion } from "framer-motion";
import { useInView } from "framer-motion";
import { useRef } from "react";
import { Button } from "@/components/ui/button";
import { Calendar, Clock, User, Phone, PawPrint, CheckCircle2 } from "lucide-react";
import { toast } from "sonner";
const services = [
"Visita generale",
"Radiologia / Ecografia",
"Chirurgia (consulenza)",
"Laboratorio analisi",
"Vaccinazione",
"Dermatologia",
"Odontoiatria",
"Oncologia",
];
const timeSlots = [
"09:00", "09:30", "10:00", "10:30", "11:00", "11:30",
"14:30", "15:00", "15:30", "16:00", "16:30", "17:00",
];
export default function BookingSection() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true, margin: "-80px" });
const [submitted, setSubmitted] = useState(false);
const [form, setForm] = useState({
name: "",
phone: "",
petName: "",
petType: "cane",
service: "",
date: "",
time: "",
notes: "",
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!form.name || !form.phone || !form.service || !form.date) {
toast.error("Compila tutti i campi obbligatori");
return;
}
setSubmitted(true);
toast.success("Richiesta inviata!", {
description: "Ti contatteremo entro 24 ore per confermare l'appuntamento.",
});
};
return (
<section id="prenotazione" className="py-20 md:py-28 bg-[#1B4F72] relative overflow-hidden">
{/* Decorazioni di sfondo */}
<div className="absolute top-0 right-0 w-96 h-96 rounded-full bg-white/5 -translate-y-1/2 translate-x-1/2" />
<div className="absolute bottom-0 left-0 w-64 h-64 rounded-full bg-[#4ECDC4]/10 translate-y-1/2 -translate-x-1/2" />
<div className="container relative z-10">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-start">
{/* Colonna sinistra: testo */}
<motion.div
ref={ref}
initial={{ opacity: 0, x: -30 }}
animate={isInView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.8 }}
className="text-white"
>
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-0.5 bg-[#4ECDC4]" />
<span className="text-[#4ECDC4] text-sm font-semibold uppercase tracking-widest">
Prenotazioni
</span>
</div>
<h2
className="text-white mb-6"
style={{
fontFamily: "'Cormorant Garamond', serif",
fontSize: "clamp(2rem, 4vw, 3rem)",
fontWeight: 600,
lineHeight: 1.2,
}}
>
Prenota la tua visita{" "}
<span className="italic text-[#4ECDC4]">online</span>
</h2>
<p className="text-white/80 leading-relaxed mb-8 text-base">
Compila il modulo per richiedere un appuntamento. Ti contatteremo entro 24 ore
per confermare la data e l'orario. Per urgenze, chiama direttamente il numero
dedicato disponibile 24 ore su 24.
</p>
{/* Info box urgenze */}
<div className="bg-white/10 backdrop-blur-sm rounded-xl p-5 border border-white/20 mb-8">
<p className="text-[#4ECDC4] font-semibold text-sm mb-2 uppercase tracking-wide">
Urgenze 24h
</p>
<a
href="tel:3205322439"
className="text-white text-2xl font-bold hover:text-[#4ECDC4] transition-colors"
style={{ fontFamily: "'Cormorant Garamond', serif" }}
>
320 532.24.39
</a>
<p className="text-white/60 text-xs mt-1">Disponibile 7 giorni su 7</p>
</div>
{/* Orari */}
<div className="space-y-3">
<p className="text-white/70 text-sm font-semibold uppercase tracking-wide mb-3">
Orari di apertura
</p>
{[
{ days: "Lunedì — Venerdì", hours: "09:00 — 12:30 · 14:30 — 19:00" },
{ days: "Sabato", hours: "09:00 — 12:30" },
{ days: "Domenica", hours: "Solo urgenze" },
].map((slot) => (
<div key={slot.days} className="flex justify-between items-center text-sm">
<span className="text-white/70">{slot.days}</span>
<span className="text-white font-medium">{slot.hours}</span>
</div>
))}
</div>
</motion.div>
{/* Colonna destra: form */}
<motion.div
initial={{ opacity: 0, x: 30 }}
animate={isInView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.8, delay: 0.2 }}
>
{submitted ? (
<div className="bg-white rounded-2xl p-8 text-center shadow-2xl">
<div className="w-16 h-16 rounded-full bg-[#4ECDC4]/15 flex items-center justify-center mx-auto mb-4">
<CheckCircle2 size={32} className="text-[#4ECDC4]" />
</div>
<h3
className="text-[#1B4F72] mb-2"
style={{ fontFamily: "'Cormorant Garamond', serif", fontSize: "1.8rem" }}
>
Richiesta inviata!
</h3>
<p className="text-gray-600 text-sm mb-6">
Abbiamo ricevuto la tua richiesta di appuntamento. Ti contatteremo entro 24 ore
per confermare data e orario.
</p>
<Button
className="bg-[#1B4F72] hover:bg-[#163d5a] text-white"
onClick={() => setSubmitted(false)}
>
Nuova prenotazione
</Button>
</div>
) : (
<form
onSubmit={handleSubmit}
className="bg-white rounded-2xl p-6 md:p-8 shadow-2xl space-y-4"
>
<h3
className="text-[#1B4F72] mb-2"
style={{ fontFamily: "'Cormorant Garamond', serif", fontSize: "1.5rem", fontWeight: 600 }}
>
Richiedi un appuntamento
</h3>
{/* Nome e telefono */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label className="text-xs font-semibold text-gray-600 uppercase tracking-wide block mb-1.5">
Nome e Cognome *
</label>
<div className="relative">
<User size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<input
type="text"
required
placeholder="Mario Rossi"
value={form.name}
onChange={(e) => setForm({ ...form, name: e.target.value })}
className="w-full pl-9 pr-3 py-2.5 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-[#4ECDC4] focus:border-transparent transition-all"
/>
</div>
</div>
<div>
<label className="text-xs font-semibold text-gray-600 uppercase tracking-wide block mb-1.5">
Telefono *
</label>
<div className="relative">
<Phone size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<input
type="tel"
required
placeholder="333 123 4567"
value={form.phone}
onChange={(e) => setForm({ ...form, phone: e.target.value })}
className="w-full pl-9 pr-3 py-2.5 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-[#4ECDC4] focus:border-transparent transition-all"
/>
</div>
</div>
</div>
{/* Animale */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label className="text-xs font-semibold text-gray-600 uppercase tracking-wide block mb-1.5">
Nome dell'animale
</label>
<div className="relative">
<PawPrint size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<input
type="text"
placeholder="Fido"
value={form.petName}
onChange={(e) => setForm({ ...form, petName: e.target.value })}
className="w-full pl-9 pr-3 py-2.5 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-[#4ECDC4] focus:border-transparent transition-all"
/>
</div>
</div>
<div>
<label className="text-xs font-semibold text-gray-600 uppercase tracking-wide block mb-1.5">
Tipo di animale
</label>
<select
value={form.petType}
onChange={(e) => setForm({ ...form, petType: e.target.value })}
className="w-full px-3 py-2.5 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-[#4ECDC4] focus:border-transparent transition-all bg-white"
>
<option value="cane">Cane</option>
<option value="gatto">Gatto</option>
<option value="altro">Altro</option>
</select>
</div>
</div>
{/* Servizio */}
<div>
<label className="text-xs font-semibold text-gray-600 uppercase tracking-wide block mb-1.5">
Tipo di visita *
</label>
<select
required
value={form.service}
onChange={(e) => setForm({ ...form, service: e.target.value })}
className="w-full px-3 py-2.5 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-[#4ECDC4] focus:border-transparent transition-all bg-white"
>
<option value="">Seleziona un servizio</option>
{services.map((s) => (
<option key={s} value={s}>{s}</option>
))}
</select>
</div>
{/* Data e ora */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label className="text-xs font-semibold text-gray-600 uppercase tracking-wide block mb-1.5">
Data preferita *
</label>
<div className="relative">
<Calendar size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<input
type="date"
required
value={form.date}
min={new Date().toISOString().split("T")[0]}
onChange={(e) => setForm({ ...form, date: e.target.value })}
className="w-full pl-9 pr-3 py-2.5 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-[#4ECDC4] focus:border-transparent transition-all"
/>
</div>
</div>
<div>
<label className="text-xs font-semibold text-gray-600 uppercase tracking-wide block mb-1.5">
Orario preferito
</label>
<div className="relative">
<Clock size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<select
value={form.time}
onChange={(e) => setForm({ ...form, time: e.target.value })}
className="w-full pl-9 pr-3 py-2.5 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-[#4ECDC4] focus:border-transparent transition-all bg-white"
>
<option value="">Qualsiasi orario</option>
{timeSlots.map((t) => (
<option key={t} value={t}>{t}</option>
))}
</select>
</div>
</div>
</div>
{/* Note */}
<div>
<label className="text-xs font-semibold text-gray-600 uppercase tracking-wide block mb-1.5">
Note aggiuntive
</label>
<textarea
rows={3}
placeholder="Descrivi brevemente il motivo della visita..."
value={form.notes}
onChange={(e) => setForm({ ...form, notes: e.target.value })}
className="w-full px-3 py-2.5 border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-[#4ECDC4] focus:border-transparent transition-all resize-none"
/>
</div>
<Button
type="submit"
className="w-full bg-[#4ECDC4] hover:bg-[#3ab5ad] text-white font-bold py-3 text-base shadow-lg shadow-[#4ECDC4]/30 transition-all duration-300 hover:shadow-xl"
>
Invia Richiesta di Appuntamento
</Button>
<p className="text-xs text-gray-400 text-center">
* Campi obbligatori. Ti contatteremo entro 24 ore per confermare.
</p>
</form>
)}
</motion.div>
</div>
</div>
</section>
);
}