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,279 @@
/*
* DESIGN: "Clinical Warmth"
* Sezione registrazione/login: tabs con form eleganti
* Sfondo bianco, accenti blu petrolio e verde acqua
*/
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 { User, Mail, Lock, Eye, EyeOff, CheckCircle2, PawPrint } from "lucide-react";
import { toast } from "sonner";
export default function AuthSection() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true, margin: "-80px" });
const [tab, setTab] = useState<"login" | "register">("register");
const [showPassword, setShowPassword] = useState(false);
const [registered, setRegistered] = useState(false);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (tab === "register") {
setRegistered(true);
toast.success("Registrazione completata!", {
description: "Benvenuto nella Clinica Veterinaria Formiginese.",
});
} else {
toast.success("Accesso effettuato!", {
description: "Bentornato nella tua area personale.",
});
}
};
const benefits = [
"Storico visite e referti digitali",
"Promemoria vaccinazioni automatici",
"Prenotazioni online prioritarie",
"Comunicazioni dirette con il veterinario",
"Gestione di più animali domestici",
];
return (
<section id="registrazione" className="py-20 md:py-28 bg-white">
<div className="container">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
{/* Colonna sinistra: benefici */}
<motion.div
ref={ref}
initial={{ opacity: 0, x: -30 }}
animate={isInView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.8 }}
>
<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">
Area Personale
</span>
</div>
<h2
className="text-[#1B4F72] mb-6"
style={{
fontFamily: "'Cormorant Garamond', serif",
fontSize: "clamp(2rem, 4vw, 3rem)",
fontWeight: 600,
lineHeight: 1.2,
}}
>
Registrati e gestisci{" "}
<span className="italic">la salute del tuo animale</span>
</h2>
<p className="text-gray-600 leading-relaxed mb-8 text-base">
Crea il tuo profilo personale per accedere a tutti i servizi digitali della clinica.
Tieni traccia della storia clinica del tuo animale, ricevi promemoria e prenota
le visite in pochi click.
</p>
{/* Benefits list */}
<div className="space-y-3 mb-8">
{benefits.map((benefit) => (
<div key={benefit} className="flex items-center gap-3">
<div className="w-6 h-6 rounded-full bg-[#4ECDC4]/15 flex items-center justify-center flex-shrink-0">
<CheckCircle2 size={14} className="text-[#4ECDC4]" />
</div>
<span className="text-gray-700 text-sm">{benefit}</span>
</div>
))}
</div>
{/* Decorazione */}
<div className="bg-[#F5F0E8] rounded-2xl p-6 flex items-center gap-4">
<div className="w-14 h-14 rounded-full bg-[#1B4F72] flex items-center justify-center flex-shrink-0">
<PawPrint size={24} className="text-[#4ECDC4]" />
</div>
<div>
<p className="text-[#1B4F72] font-semibold text-sm">Già più di 500 famiglie</p>
<p className="text-gray-600 text-xs mt-0.5">
si affidano alla nostra clinica per la cura dei loro animali
</p>
</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 }}
>
{registered ? (
<div className="bg-[#F5F0E8] rounded-2xl p-8 text-center shadow-sm">
<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" }}
>
Benvenuto!
</h3>
<p className="text-gray-600 text-sm mb-6">
La tua registrazione è avvenuta con successo. Ora puoi accedere a tutti i servizi
della tua area personale.
</p>
<Button
className="bg-[#1B4F72] hover:bg-[#163d5a] text-white"
onClick={() => setRegistered(false)}
>
Vai all'area personale
</Button>
</div>
) : (
<div className="bg-white rounded-2xl shadow-lg border border-gray-100 overflow-hidden">
{/* Tabs */}
<div className="flex border-b border-gray-100">
{(["register", "login"] as const).map((t) => (
<button
key={t}
onClick={() => setTab(t)}
className={`flex-1 py-4 text-sm font-semibold transition-all duration-200 ${
tab === t
? "text-[#1B4F72] border-b-2 border-[#4ECDC4] bg-[#F5F0E8]/50"
: "text-gray-400 hover:text-gray-600"
}`}
>
{t === "register" ? "Registrati" : "Accedi"}
</button>
))}
</div>
<form onSubmit={handleSubmit} className="p-6 md:p-8 space-y-4">
{tab === "register" && (
<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
</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"
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">
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="Rossi"
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>
)}
<div>
<label className="text-xs font-semibold text-gray-600 uppercase tracking-wide block mb-1.5">
Email
</label>
<div className="relative">
<Mail size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<input
type="email"
required
placeholder="mario.rossi@email.it"
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">
Password
</label>
<div className="relative">
<Lock size={15} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<input
type={showPassword ? "text" : "password"}
required
placeholder="••••••••"
className="w-full pl-9 pr-10 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"
/>
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
>
{showPassword ? <EyeOff size={15} /> : <Eye size={15} />}
</button>
</div>
</div>
{tab === "register" && (
<div className="flex items-start gap-2 pt-1">
<input
type="checkbox"
required
id="privacy"
className="mt-0.5 accent-[#4ECDC4]"
/>
<label htmlFor="privacy" className="text-xs text-gray-500 leading-relaxed">
Accetto la{" "}
<button
type="button"
className="text-[#4ECDC4] hover:underline"
onClick={() => toast.info("Privacy policy in arrivo")}
>
Privacy Policy
</button>{" "}
e i{" "}
<button
type="button"
className="text-[#4ECDC4] hover:underline"
onClick={() => toast.info("Termini di servizio in arrivo")}
>
Termini di Servizio
</button>
</label>
</div>
)}
<Button
type="submit"
className="w-full bg-[#1B4F72] hover:bg-[#163d5a] text-white font-bold py-3 text-base transition-all duration-300"
>
{tab === "register" ? "Crea il tuo account" : "Accedi all'area personale"}
</Button>
{tab === "login" && (
<p className="text-center text-xs text-gray-400">
<button
type="button"
className="text-[#4ECDC4] hover:underline"
onClick={() => toast.info("Recupero password in arrivo")}
>
Password dimenticata?
</button>
</p>
)}
</form>
</div>
)}
</motion.div>
</div>
</div>
</section>
);
}