xpeditis2.0/apps/frontend/app/contact/page.tsx
2026-01-26 00:08:04 +01:00

566 lines
22 KiB
TypeScript

'use client';
import { useState, useRef } from 'react';
import { motion, useInView } from 'framer-motion';
import {
Mail,
Phone,
MapPin,
Clock,
Send,
MessageSquare,
Headphones,
Building2,
CheckCircle2,
Loader2,
} from 'lucide-react';
import { LandingHeader, LandingFooter } from '@/components/layout';
export default function ContactPage() {
const [formData, setFormData] = useState({
firstName: '',
lastName: '',
email: '',
company: '',
phone: '',
subject: '',
message: '',
});
const [isSubmitting, setIsSubmitting] = useState(false);
const [isSubmitted, setIsSubmitted] = useState(false);
const [error, setError] = useState('');
const heroRef = useRef(null);
const formRef = useRef(null);
const contactRef = useRef(null);
const isHeroInView = useInView(heroRef, { once: true });
const isFormInView = useInView(formRef, { once: true });
const isContactInView = useInView(contactRef, { once: true });
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
setIsSubmitting(true);
// Simulate form submission
await new Promise((resolve) => setTimeout(resolve, 1500));
setIsSubmitting(false);
setIsSubmitted(true);
};
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>
) => {
setFormData((prev) => ({
...prev,
[e.target.name]: e.target.value,
}));
};
const contactMethods = [
{
icon: Mail,
title: 'Email',
description: 'Envoyez-nous un email',
value: 'contact@xpeditis.com',
link: 'mailto:contact@xpeditis.com',
color: 'from-blue-500 to-cyan-500',
},
{
icon: Phone,
title: 'Téléphone',
description: 'Appelez-nous',
value: '+33 1 23 45 67 89',
link: 'tel:+33123456789',
color: 'from-green-500 to-emerald-500',
},
{
icon: MessageSquare,
title: 'Chat en direct',
description: 'Discutez avec notre équipe',
value: 'Disponible 24/7',
link: '#chat',
color: 'from-purple-500 to-pink-500',
},
{
icon: Headphones,
title: 'Support',
description: 'Centre d\'aide',
value: 'support.xpeditis.com',
link: 'https://support.xpeditis.com',
color: 'from-orange-500 to-red-500',
},
];
const offices = [
{
city: 'Paris',
address: '123 Avenue des Champs-Élysées',
postalCode: '75008 Paris, France',
phone: '+33 1 23 45 67 89',
email: 'paris@xpeditis.com',
isHQ: true,
},
{
city: 'Rotterdam',
address: 'Wilhelminakade 123',
postalCode: '3072 AP Rotterdam, Netherlands',
phone: '+31 10 123 4567',
email: 'rotterdam@xpeditis.com',
isHQ: false,
},
{
city: 'Hambourg',
address: 'Am Sandtorkai 50',
postalCode: '20457 Hamburg, Germany',
phone: '+49 40 123 4567',
email: 'hamburg@xpeditis.com',
isHQ: false,
},
];
const subjects = [
{ value: '', label: 'Sélectionnez un sujet' },
{ value: 'demo', label: 'Demande de démonstration' },
{ value: 'pricing', label: 'Questions sur les tarifs' },
{ value: 'partnership', label: 'Partenariat' },
{ value: 'support', label: 'Support technique' },
{ value: 'press', label: 'Relations presse' },
{ value: 'careers', label: 'Recrutement' },
{ value: 'other', label: 'Autre' },
];
const containerVariants = {
hidden: { opacity: 0, y: 50 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.6,
staggerChildren: 0.1,
},
},
};
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.5 },
},
};
return (
<div className="min-h-screen bg-white">
<LandingHeader activePage="contact" />
{/* Hero Section */}
<section ref={heroRef} className="relative pt-32 pb-20 bg-gradient-to-br from-brand-navy to-brand-navy/95 overflow-hidden">
<div className="absolute inset-0 opacity-10">
<div className="absolute top-20 left-20 w-96 h-96 bg-brand-turquoise rounded-full blur-3xl" />
<div className="absolute bottom-20 right-20 w-96 h-96 bg-brand-green rounded-full blur-3xl" />
</div>
<div className="relative z-10 max-w-7xl mx-auto px-6 lg:px-8">
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={isHeroInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.8 }}
className="text-center"
>
<motion.div
initial={{ scale: 0.8, opacity: 0 }}
animate={isHeroInView ? { scale: 1, opacity: 1 } : {}}
transition={{ duration: 0.6, delay: 0.2 }}
className="inline-flex items-center space-x-2 bg-white/10 backdrop-blur-sm px-4 py-2 rounded-full mb-8 border border-white/20"
>
<Mail className="w-5 h-5 text-brand-turquoise" />
<span className="text-white/90 text-sm font-medium">Nous contacter</span>
</motion.div>
<h1 className="text-4xl lg:text-6xl font-bold text-white mb-6 leading-tight">
Une question ?
<br />
<span className="text-transparent bg-clip-text bg-gradient-to-r from-brand-turquoise to-brand-green">
Nous sommes pour vous
</span>
</h1>
<p className="text-xl text-white/80 mb-10 max-w-3xl mx-auto leading-relaxed">
Notre équipe est disponible pour répondre à toutes vos questions sur notre plateforme,
nos services et nos tarifs. N'hésitez pas à nous contacter !
</p>
</motion.div>
</div>
{/* Wave */}
<div className="absolute bottom-0 left-0 right-0">
<svg className="w-full h-16" viewBox="0 0 1440 60" preserveAspectRatio="none">
<path
d="M0,30 C240,50 480,10 720,30 C960,50 1200,10 1440,30 L1440,60 L0,60 Z"
fill="white"
/>
</svg>
</div>
</section>
{/* Contact Methods */}
<section ref={contactRef} className="py-16 bg-gray-50">
<motion.div
variants={containerVariants}
initial="hidden"
animate={isContactInView ? 'visible' : 'hidden'}
className="max-w-7xl mx-auto px-6 lg:px-8"
>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{contactMethods.map((method, index) => {
const IconComponent = method.icon;
return (
<motion.a
key={index}
href={method.link}
variants={itemVariants}
whileHover={{ y: -5 }}
className="bg-white p-6 rounded-2xl shadow-lg border border-gray-100 hover:shadow-xl transition-all group"
>
<div
className={`w-12 h-12 rounded-xl bg-gradient-to-br ${method.color} flex items-center justify-center mb-4 group-hover:scale-110 transition-transform`}
>
<IconComponent className="w-6 h-6 text-white" />
</div>
<h3 className="text-lg font-bold text-brand-navy mb-1">{method.title}</h3>
<p className="text-gray-500 text-sm mb-2">{method.description}</p>
<p className="text-brand-turquoise font-medium">{method.value}</p>
</motion.a>
);
})}
</div>
</motion.div>
</section>
{/* Contact Form & Info */}
<section ref={formRef} className="py-20">
<div className="max-w-7xl mx-auto px-6 lg:px-8">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
{/* Form */}
<motion.div
initial={{ opacity: 0, x: -50 }}
animate={isFormInView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.8 }}
>
<h2 className="text-3xl font-bold text-brand-navy mb-6">Envoyez-nous un message</h2>
<p className="text-gray-600 mb-8">
Remplissez le formulaire ci-dessous et nous vous répondrons dans les plus brefs délais.
</p>
{isSubmitted ? (
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
className="bg-green-50 border border-green-200 rounded-2xl p-8 text-center"
>
<div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
<CheckCircle2 className="w-8 h-8 text-green-600" />
</div>
<h3 className="text-2xl font-bold text-green-800 mb-2">Message envoyé !</h3>
<p className="text-green-700 mb-6">
Merci pour votre message. Notre équipe vous répondra dans les 24 heures.
</p>
<button
onClick={() => {
setIsSubmitted(false);
setFormData({
firstName: '',
lastName: '',
email: '',
company: '',
phone: '',
subject: '',
message: '',
});
}}
className="text-brand-turquoise font-medium hover:underline"
>
Envoyer un autre message
</button>
</motion.div>
) : (
<form onSubmit={handleSubmit} className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label htmlFor="firstName" className="block text-sm font-medium text-gray-700 mb-2">
Prénom *
</label>
<input
type="text"
id="firstName"
name="firstName"
required
value={formData.firstName}
onChange={handleChange}
className="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-brand-turquoise focus:border-transparent transition-all"
placeholder="Jean"
/>
</div>
<div>
<label htmlFor="lastName" className="block text-sm font-medium text-gray-700 mb-2">
Nom *
</label>
<input
type="text"
id="lastName"
name="lastName"
required
value={formData.lastName}
onChange={handleChange}
className="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-brand-turquoise focus:border-transparent transition-all"
placeholder="Dupont"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-2">
Email *
</label>
<input
type="email"
id="email"
name="email"
required
value={formData.email}
onChange={handleChange}
className="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-brand-turquoise focus:border-transparent transition-all"
placeholder="jean.dupont@exemple.com"
/>
</div>
<div>
<label htmlFor="phone" className="block text-sm font-medium text-gray-700 mb-2">
Téléphone
</label>
<input
type="tel"
id="phone"
name="phone"
value={formData.phone}
onChange={handleChange}
className="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-brand-turquoise focus:border-transparent transition-all"
placeholder="+33 6 12 34 56 78"
/>
</div>
</div>
<div>
<label htmlFor="company" className="block text-sm font-medium text-gray-700 mb-2">
Entreprise
</label>
<input
type="text"
id="company"
name="company"
value={formData.company}
onChange={handleChange}
className="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-brand-turquoise focus:border-transparent transition-all"
placeholder="Votre entreprise"
/>
</div>
<div>
<label htmlFor="subject" className="block text-sm font-medium text-gray-700 mb-2">
Sujet *
</label>
<select
id="subject"
name="subject"
required
value={formData.subject}
onChange={handleChange}
className="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-brand-turquoise focus:border-transparent transition-all"
>
{subjects.map((subject) => (
<option key={subject.value} value={subject.value}>
{subject.label}
</option>
))}
</select>
</div>
<div>
<label htmlFor="message" className="block text-sm font-medium text-gray-700 mb-2">
Message *
</label>
<textarea
id="message"
name="message"
required
rows={5}
value={formData.message}
onChange={handleChange}
className="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-brand-turquoise focus:border-transparent transition-all resize-none"
placeholder="Comment pouvons-nous vous aider ?"
/>
</div>
{error && (
<div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg">
{error}
</div>
)}
<button
type="submit"
disabled={isSubmitting}
className="w-full px-8 py-4 bg-brand-turquoise text-white rounded-lg hover:bg-brand-turquoise/90 transition-all font-semibold text-lg flex items-center justify-center space-x-2 disabled:opacity-50 disabled:cursor-not-allowed"
>
{isSubmitting ? (
<>
<Loader2 className="w-5 h-5 animate-spin" />
<span>Envoi en cours...</span>
</>
) : (
<>
<Send className="w-5 h-5" />
<span>Envoyer le message</span>
</>
)}
</button>
</form>
)}
</motion.div>
{/* Offices */}
<motion.div
initial={{ opacity: 0, x: 50 }}
animate={isFormInView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.8, delay: 0.2 }}
>
<h2 className="text-3xl font-bold text-brand-navy mb-6">Nos bureaux</h2>
<p className="text-gray-600 mb-8">
Retrouvez-nous dans nos bureaux à travers l'Europe ou contactez-nous par email.
</p>
<div className="space-y-6">
{offices.map((office, index) => (
<div
key={index}
className={`bg-white p-6 rounded-2xl border-2 transition-all ${
office.isHQ
? 'border-brand-turquoise shadow-lg'
: 'border-gray-200 hover:border-brand-turquoise/50'
}`}
>
<div className="flex items-start space-x-4">
<div
className={`w-12 h-12 rounded-xl flex items-center justify-center flex-shrink-0 ${
office.isHQ ? 'bg-brand-turquoise' : 'bg-gray-100'
}`}
>
<Building2 className={`w-6 h-6 ${office.isHQ ? 'text-white' : 'text-gray-600'}`} />
</div>
<div className="flex-1">
<div className="flex items-center space-x-2 mb-2">
<h3 className="text-xl font-bold text-brand-navy">{office.city}</h3>
{office.isHQ && (
<span className="px-2 py-1 bg-brand-turquoise/10 text-brand-turquoise text-xs font-medium rounded-full">
Siège social
</span>
)}
</div>
<div className="space-y-2 text-gray-600">
<div className="flex items-center space-x-2">
<MapPin className="w-4 h-4 text-gray-400" />
<span>{office.address}</span>
</div>
<div className="flex items-center space-x-2">
<span className="text-gray-400 ml-6">{office.postalCode}</span>
</div>
<div className="flex items-center space-x-2">
<Phone className="w-4 h-4 text-gray-400" />
<a href={`tel:${office.phone.replace(/\s/g, '')}`} className="hover:text-brand-turquoise">
{office.phone}
</a>
</div>
<div className="flex items-center space-x-2">
<Mail className="w-4 h-4 text-gray-400" />
<a href={`mailto:${office.email}`} className="hover:text-brand-turquoise">
{office.email}
</a>
</div>
</div>
</div>
</div>
</div>
))}
</div>
{/* Hours */}
<div className="mt-8 bg-gray-50 p-6 rounded-2xl">
<div className="flex items-center space-x-3 mb-4">
<Clock className="w-6 h-6 text-brand-turquoise" />
<h3 className="text-lg font-bold text-brand-navy">Horaires d'ouverture</h3>
</div>
<div className="space-y-2 text-gray-600">
<div className="flex justify-between">
<span>Lundi - Vendredi</span>
<span className="font-medium">9h00 - 18h00</span>
</div>
<div className="flex justify-between">
<span>Samedi</span>
<span className="font-medium">10h00 - 14h00</span>
</div>
<div className="flex justify-between">
<span>Dimanche</span>
<span className="font-medium text-gray-400">Fermé</span>
</div>
</div>
<p className="mt-4 text-sm text-gray-500">
* Support technique disponible 24/7 pour les clients Enterprise
</p>
</div>
</motion.div>
</div>
</div>
</section>
{/* Map Section */}
<section className="py-20 bg-gray-50">
<div className="max-w-7xl mx-auto px-6 lg:px-8">
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="text-center mb-12"
>
<h2 className="text-3xl font-bold text-brand-navy mb-4">Notre présence en Europe</h2>
<p className="text-gray-600">
Des bureaux stratégiquement situés pour mieux vous servir
</p>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8, delay: 0.2 }}
className="bg-white rounded-2xl shadow-lg overflow-hidden"
>
<div className="aspect-[21/9] bg-gradient-to-br from-brand-navy/5 to-brand-turquoise/5 flex items-center justify-center">
<div className="text-center">
<MapPin className="w-16 h-16 text-brand-turquoise mx-auto mb-4" />
<p className="text-gray-500">Carte interactive bientôt disponible</p>
</div>
</div>
</motion.div>
</div>
</section>
<LandingFooter />
</div>
);
}