|
|
|
|
@@ -2,13 +2,7 @@
|
|
|
|
|
// @ts-nocheck — generated by catalog-eject; runtime-correct but TS strict-mode false-positives on inlined catalog body
|
|
|
|
|
import Button from "@/components/ui/Button";
|
|
|
|
|
import TextAnimation from "@/components/ui/TextAnimation";
|
|
|
|
|
import ImageOrVideo from "@/components/ui/ImageOrVideo";
|
|
|
|
|
import GridOrCarousel from "@/components/ui/GridOrCarousel";
|
|
|
|
|
import ScrollReveal from "@/components/ui/ScrollReveal";
|
|
|
|
|
import Input from "@/components/ui/Input";
|
|
|
|
|
import Textarea from "@/components/ui/Textarea";
|
|
|
|
|
import Label from "@/components/ui/Label";
|
|
|
|
|
import { useState } from "react";
|
|
|
|
|
|
|
|
|
|
const testimonials = [
|
|
|
|
|
{
|
|
|
|
|
@@ -43,41 +37,20 @@ const testimonials = [
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
type Testimonial = {
|
|
|
|
|
name: string;
|
|
|
|
|
role: string;
|
|
|
|
|
quote: string;
|
|
|
|
|
rating: number;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const TestimonialsInline = () => {
|
|
|
|
|
const [reviews, setReviews] = useState(testimonials);
|
|
|
|
|
const [name, setName] = useState("");
|
|
|
|
|
const [quote, setQuote] = useState("");
|
|
|
|
|
const [rating, setRating] = useState(5);
|
|
|
|
|
const [submitted, setSubmitted] = useState(false);
|
|
|
|
|
|
|
|
|
|
const handleSubmit = (e: React.FormEvent) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
if (name && quote) {
|
|
|
|
|
setReviews([{ name, role: "Nouveau client", quote, rating }, ...reviews]);
|
|
|
|
|
setSubmitted(true);
|
|
|
|
|
setName("");
|
|
|
|
|
setQuote("");
|
|
|
|
|
setRating(5);
|
|
|
|
|
setTimeout(() => setSubmitted(false), 4000);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<section aria-label="Testimonials section" className="py-24 bg-background-accent relative overflow-hidden">
|
|
|
|
|
<section aria-label="Testimonials section" className="bg-background-accent relative overflow-hidden">
|
|
|
|
|
<div className="absolute top-0 left-0 w-full h-full overflow-hidden pointer-events-none">
|
|
|
|
|
<div className="absolute -top-40 -right-40 w-96 h-96 bg-primary-cta opacity-5 rounded-full blur-3xl"></div>
|
|
|
|
|
<div className="absolute -bottom-40 -left-40 w-96 h-96 bg-card opacity-30 rounded-full blur-3xl"></div>
|
|
|
|
|
<div className="absolute top-20 left-10 text-6xl opacity-20">🌸</div>
|
|
|
|
|
<div className="absolute bottom-20 right-10 text-6xl opacity-20">🌺</div>
|
|
|
|
|
<div className="absolute top-1/2 right-1/4 text-5xl opacity-20">🌼</div>
|
|
|
|
|
<div className="absolute bottom-1/4 left-1/4 text-5xl opacity-20">🌻</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="w-content-width mx-auto relative z-10">
|
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-16 items-start">
|
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-12 items-start">
|
|
|
|
|
|
|
|
|
|
<div className="lg:col-span-5 flex flex-col gap-8">
|
|
|
|
|
<div className="flex flex-col gap-4">
|
|
|
|
|
@@ -96,104 +69,65 @@ const TestimonialsInline = () => {
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<form onSubmit={handleSubmit} className="flex flex-col gap-5 bg-background p-8 rounded-3xl shadow-2xl border border-primary-cta/10">
|
|
|
|
|
{submitted ? (
|
|
|
|
|
<div className="flex flex-col items-center justify-center py-12 text-center gap-4 h-full min-h-[300px]">
|
|
|
|
|
<div className="w-20 h-20 bg-green-100 text-green-600 rounded-full flex items-center justify-center text-4xl mb-2 shadow-inner">
|
|
|
|
|
✓
|
|
|
|
|
</div>
|
|
|
|
|
<h3 className="text-3xl font-bold text-foreground">Merci !</h3>
|
|
|
|
|
<p className="text-accent text-lg">Votre avis a bien été publié et ajouté à la liste.</p>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
<div className="flex flex-col gap-2">
|
|
|
|
|
<Label htmlFor="name" className="text-foreground font-bold text-sm uppercase tracking-wide">Votre nom</Label>
|
|
|
|
|
<Input
|
|
|
|
|
id="name"
|
|
|
|
|
value={name}
|
|
|
|
|
onChange={(e) => setName(e.target.value)}
|
|
|
|
|
placeholder="Ex: Jean Dupont"
|
|
|
|
|
required={true}
|
|
|
|
|
className="bg-card border-none focus:ring-2 focus:ring-primary-cta rounded-xl py-3 px-4"
|
|
|
|
|
></Input>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-col gap-2">
|
|
|
|
|
<Label className="text-foreground font-bold text-sm uppercase tracking-wide">Votre note</Label>
|
|
|
|
|
<div className="flex gap-2 items-center bg-card w-fit px-4 py-2 rounded-xl">
|
|
|
|
|
{[1, 2, 3, 4, 5].map((star) => (
|
|
|
|
|
<button
|
|
|
|
|
key={star}
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() => setRating(star)}
|
|
|
|
|
className={`text-3xl transition-all duration-200 hover:scale-125 ${star <= rating ? 'text-yellow-500 drop-shadow-sm' : 'text-gray-300'}`}
|
|
|
|
|
>
|
|
|
|
|
★
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-col gap-2">
|
|
|
|
|
<Label htmlFor="quote" className="text-foreground font-bold text-sm uppercase tracking-wide">Votre message</Label>
|
|
|
|
|
<Textarea
|
|
|
|
|
id="quote"
|
|
|
|
|
value={quote}
|
|
|
|
|
onChange={(e) => setQuote(e.target.value)}
|
|
|
|
|
placeholder="Racontez-nous votre moment..."
|
|
|
|
|
rows={4}
|
|
|
|
|
required={true}
|
|
|
|
|
className="bg-card border-none focus:ring-2 focus:ring-primary-cta resize-none rounded-xl py-3 px-4"
|
|
|
|
|
></Textarea>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<Button text="Publier mon avis" variant="primary" className="w-full mt-4 py-4 text-lg rounded-xl font-bold shadow-lg hover:shadow-xl transition-shadow" />
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</form>
|
|
|
|
|
<div className="flex flex-col gap-5 bg-background p-8 rounded-theme shadow-2xl border border-primary-cta/10 text-center">
|
|
|
|
|
<h3 className="text-2xl font-bold text-foreground mb-2">Laissez un avis sur Google</h3>
|
|
|
|
|
<p className="text-accent mb-6">Votre retour nous aide à nous améliorer et permet aux autres clients de découvrir notre brasserie.</p>
|
|
|
|
|
<Button
|
|
|
|
|
text="Laisser un avis Google"
|
|
|
|
|
variant="primary"
|
|
|
|
|
href="https://maps.google.com"
|
|
|
|
|
className="w-full py-4 text-lg"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="lg:col-span-7 flex flex-col gap-8">
|
|
|
|
|
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 bg-background/50 p-6 rounded-3xl backdrop-blur-sm border border-primary-cta/10">
|
|
|
|
|
<h3 className="text-3xl font-bold text-primary-cta">Derniers avis</h3>
|
|
|
|
|
<div className="flex items-center gap-3 bg-background px-5 py-3 rounded-2xl shadow-md">
|
|
|
|
|
<span className="font-black text-2xl text-foreground">4.5</span>
|
|
|
|
|
<span className="text-yellow-500 text-xl">★★★★½</span>
|
|
|
|
|
<span className="text-accent text-sm font-medium ml-1">({reviews.length} avis)</span>
|
|
|
|
|
<div className="lg:col-span-7 flex flex-col gap-6">
|
|
|
|
|
<div className="flex items-center justify-between mb-2">
|
|
|
|
|
<div className="flex items-center gap-3">
|
|
|
|
|
<div className="flex gap-1">
|
|
|
|
|
{[1, 2, 3, 4, 5].map((star) => (
|
|
|
|
|
<svg key={star} className="w-6 h-6 text-primary-cta fill-current" viewBox="0 0 24 24">
|
|
|
|
|
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
|
|
|
|
|
</svg>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
<span className="text-2xl font-bold text-foreground">4.8</span>
|
|
|
|
|
</div>
|
|
|
|
|
<span className="text-accent font-medium">Basé sur 124 avis</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-6">
|
|
|
|
|
{reviews.slice(0, 4).map((testimonial, idx) => (
|
|
|
|
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
|
|
|
{testimonials.map((testimonial, idx) => (
|
|
|
|
|
<ScrollReveal key={idx} variant="slide-up" delay={idx * 0.1}>
|
|
|
|
|
<div className="flex flex-col gap-4 p-8 bg-card rounded-3xl shadow-lg border border-primary-cta/5 h-full hover:-translate-y-2 transition-transform duration-300 relative overflow-hidden group">
|
|
|
|
|
<div className="absolute top-0 right-0 w-24 h-24 bg-primary-cta opacity-5 rounded-bl-full -mr-4 -mt-4 transition-transform group-hover:scale-110"></div>
|
|
|
|
|
<div className="text-yellow-500 text-lg">
|
|
|
|
|
{Array.from({ length: 5 }).map((_, i) => (
|
|
|
|
|
<span key={i}>{i < testimonial.rating ? '★' : '☆'}</span>
|
|
|
|
|
))}
|
|
|
|
|
<div className="bg-card p-6 rounded-theme border border-primary-cta/5 h-full flex flex-col justify-between">
|
|
|
|
|
<div>
|
|
|
|
|
<div className="flex gap-1 mb-4">
|
|
|
|
|
{[...Array(5)].map((_, i) => (
|
|
|
|
|
<svg key={i} className={`w-4 h-4 ${i < testimonial.rating ?'text-primary-cta fill-current' : 'text-primary-cta/20 fill-current'}`} viewBox="0 0 24 24">
|
|
|
|
|
<path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z" />
|
|
|
|
|
</svg>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
<p className="text-foreground text-lg font-medium leading-relaxed mb-6">"{testimonial.quote}"</p>
|
|
|
|
|
</div>
|
|
|
|
|
<p className="text-foreground text-lg leading-relaxed font-medium flex-grow relative z-10">"{testimonial.quote}"</p>
|
|
|
|
|
<div className="flex flex-col mt-4 pt-4 border-t border-primary-cta/10 relative z-10">
|
|
|
|
|
<span className="text-foreground font-bold text-xl">{testimonial.name}</span>
|
|
|
|
|
<span className="text-accent font-medium">{testimonial.role}</span>
|
|
|
|
|
<div className="flex items-center gap-3 pt-4 border-t border-primary-cta/10">
|
|
|
|
|
<div className="w-10 h-10 rounded-full bg-primary-cta/10 flex items-center justify-center text-primary-cta font-bold text-lg">
|
|
|
|
|
{testimonial.name.charAt(0)}
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<p className="font-bold text-foreground">{testimonial.name}</p>
|
|
|
|
|
<p className="text-sm text-accent">{testimonial.role}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</ScrollReveal>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
)};
|
|
|
|
|
|
|
|
|
|
export default function TestimonialsSection() {
|
|
|
|
|
return (
|
|
|
|
|
<div data-webild-section="testimonials" id="testimonials">
|
|
|
|
|
<TestimonialsInline />
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default TestimonialsInline;
|