the-tip-top-frontend/app/contact/page.tsx
soufiane 866911cbd4 fix(a11y): correct WAVE accessibility audit issues
- Footer: add label for newsletter email input, improve text contrast (beige-600 -> beige-700)
- Contact: add aria-label to map marker link, improve red asterisk contrast (red-500 -> red-600)
- Historique: add label for search input field
- Profil: improve label contrast (gray-600 -> gray-700), use semantic dl/dt/dd structure

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 00:20:37 +01:00

345 lines
16 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import { useState } from "react";
import type { Metadata } from "next";
import Link from "next/link";
export default function ContactPage() {
const [formData, setFormData] = useState({
fullName: '',
email: '',
subject: '',
message: '',
acceptPolicy: false,
});
const [isSubmitting, setIsSubmitting] = useState(false);
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));
};
const handleCheckboxChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFormData(prev => ({ ...prev, acceptPolicy: e.target.checked }));
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitting(true);
try {
// Appel à l'API backend
const response = await fetch('http://localhost:4000/api/contact', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
fullName: formData.fullName,
email: formData.email,
subject: formData.subject,
message: formData.message,
}),
});
const data = await response.json();
if (response.ok && data.success) {
alert('✅ Votre message a été envoyé avec succès ! Nous vous répondrons dans les plus brefs délais.');
// Reset form
setFormData({
fullName: '',
email: '',
subject: '',
message: '',
acceptPolicy: false,
});
} else {
alert('❌ ' + (data.message || 'Une erreur est survenue. Veuillez réessayer.'));
}
} catch (error) {
console.error('Erreur lors de l\'envoi du message:', error);
alert('❌ Une erreur est survenue lors de l\'envoi de votre message. Veuillez réessayer.');
} finally {
setIsSubmitting(false);
}
};
return (
<div className="min-h-screen bg-gradient-to-br from-beige-100 via-beige-50 to-beige-100">
{/* Hero Section */}
<section className="bg-gradient-to-r from-white to-beige-50 py-12 border-b-2 border-beige-300">
<div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto text-center">
<h1 className="text-4xl md:text-5xl font-bold text-primary-300 mb-4">
Contactez-nous
</h1>
<p className="text-lg text-gray-600">
Une question sur le jeu-concours ? Besoin d'aide ? Notre équipe est là pour vous accompagner !
</p>
</div>
</div>
</section>
{/* Main Content */}
<section className="py-12">
<div className="container mx-auto px-4">
<div className="max-w-6xl mx-auto">
<div className="grid lg:grid-cols-2 gap-12">
{/* Contact Form */}
<div>
<div className="bg-white rounded-xl shadow-md p-8 border border-beige-300">
<h2 className="text-2xl font-bold text-gray-800 mb-6">Envoyez-nous un message</h2>
<form onSubmit={handleSubmit} className="space-y-6">
{/* Nom complet */}
<div>
<label htmlFor="fullName" className="block text-sm font-semibold text-gray-700 mb-2">
Nom complet <span className="text-red-600" aria-hidden="true">*</span>
</label>
<input
id="fullName"
name="fullName"
type="text"
required
value={formData.fullName}
onChange={handleChange}
placeholder="Votre nom et prénom"
className="w-full px-4 py-3 border-2 border-beige-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
/>
</div>
{/* Email */}
<div>
<label htmlFor="email" className="block text-sm font-semibold text-gray-700 mb-2">
Email <span className="text-red-600" aria-hidden="true">*</span>
</label>
<input
id="email"
name="email"
type="email"
required
value={formData.email}
onChange={handleChange}
placeholder="votre@email.com"
className="w-full px-4 py-3 border-2 border-beige-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
/>
</div>
{/* Sujet */}
<div>
<label htmlFor="subject" className="block text-sm font-semibold text-gray-700 mb-2">
Sujet <span className="text-red-600" aria-hidden="true">*</span>
</label>
<select
id="subject"
name="subject"
required
value={formData.subject}
onChange={handleChange}
className="w-full px-4 py-3 border-2 border-beige-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500 bg-white"
>
<option value="">Sélectionnez un sujet</option>
<option value="jeu-concours">Question sur le jeu-concours</option>
<option value="code">Problème avec mon code</option>
<option value="lot">Réclamation de lot</option>
<option value="compte">Gestion de compte</option>
<option value="autre">Autre demande</option>
</select>
</div>
{/* Message */}
<div>
<label htmlFor="message" className="block text-sm font-semibold text-gray-700 mb-2">
Message <span className="text-red-600" aria-hidden="true">*</span>
</label>
<textarea
id="message"
name="message"
required
value={formData.message}
onChange={handleChange}
placeholder="Décrivez votre demande en détail..."
rows={6}
className="w-full px-4 py-3 border-2 border-beige-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500 resize-none"
/>
</div>
{/* Checkbox RGPD */}
<div className="flex items-start gap-3">
<input
id="acceptPolicy"
name="acceptPolicy"
type="checkbox"
required
checked={formData.acceptPolicy}
onChange={handleCheckboxChange}
className="mt-1 w-5 h-5 text-primary-500 border-beige-300 rounded focus:ring-2 focus:ring-primary-500"
/>
<label htmlFor="acceptPolicy" className="text-sm text-gray-700 select-none cursor-pointer">
J'accepte que mes données soient collectées et traitées conformément à la{' '}
<Link href="/privacy" className="text-primary-500 underline hover:text-primary-600">
politique de confidentialité
</Link>{' '}
<span className="text-red-600" aria-hidden="true">*</span>
</label>
</div>
{/* Submit Button */}
<div>
<button
type="submit"
disabled={isSubmitting}
className="w-full bg-gradient-to-r from-primary-500 to-primary-600 hover:from-primary-400 hover:to-primary-500 disabled:from-gray-400 disabled:to-gray-500 text-white font-bold px-8 py-4 rounded-lg transition-all duration-300 shadow-lg hover:shadow-[0_0_20px_rgba(11,96,41,0.4)] hover:scale-105"
>
{isSubmitting ? "Envoi en cours..." : "Envoyer le message"}
</button>
</div>
</form>
</div>
</div>
{/* Contact Info */}
<div className="space-y-6">
{/* Nos coordonnées */}
<div className="bg-white rounded-xl shadow-md p-8 border border-beige-300">
<h2 className="text-2xl font-bold text-gray-800 mb-6">Nos coordonnées</h2>
<div className="space-y-6">
{/* Siège social */}
<div className="flex items-start gap-4">
<div className="w-12 h-12 bg-gradient-to-br from-primary-500 to-primary-600 rounded-full flex items-center justify-center text-xl shadow-md flex-shrink-0">📍</div>
<div>
<h3 className="font-semibold text-gray-800 mb-1">Siège social</h3>
<a
href="https://www.google.com/maps/search/?api=1&query=18+Avenue+Thiers+06000+Nice+France"
target="_blank"
rel="noopener noreferrer"
className="text-gray-600 text-sm hover:text-primary-500 transition-colors block"
>
Thé Tip Top<br />
18 Avenue Thiers<br />
06000 Nice, France
</a>
</div>
</div>
{/* Téléphone */}
<div className="flex items-start gap-4">
<div className="w-12 h-12 bg-gradient-to-br from-primary-500 to-primary-600 rounded-full flex items-center justify-center text-xl shadow-md flex-shrink-0">📞</div>
<div>
<h3 className="font-semibold text-gray-800 mb-1">Téléphone</h3>
<p className="text-gray-600 text-sm">
<a href="tel:+33123456789" className="hover:text-primary-500 transition-colors">
+33 1 23 45 67 89
</a><br />
<span className="text-xs">Du lundi au vendredi<br />9h00 - 18h00</span>
</p>
</div>
</div>
{/* Email */}
<div className="flex items-start gap-4">
<div className="w-12 h-12 bg-gradient-to-br from-primary-500 to-primary-600 rounded-full flex items-center justify-center text-xl shadow-md flex-shrink-0"></div>
<div>
<h3 className="font-semibold text-gray-800 mb-1">Email</h3>
<div className="text-gray-600 text-sm space-y-1">
<p>
<a href="mailto:thetiptopgr3@gmail.com" className="hover:text-primary-500 transition-colors">
thetiptopgr3@gmail.com
</a>
</p>
</div>
</div>
</div>
{/* Service client */}
<div className="flex items-start gap-4">
<div className="w-12 h-12 bg-gradient-to-br from-primary-500 to-primary-600 rounded-full flex items-center justify-center text-xl shadow-md flex-shrink-0">🕐</div>
<div>
<h3 className="font-semibold text-gray-800 mb-1">Service client</h3>
<p className="text-gray-600 text-sm">
Réponse sous 24h<br />
Support multilingue<br />
Du lundi au samedi
</p>
</div>
</div>
</div>
</div>
{/* Google Maps */}
<div className="bg-white rounded-xl shadow-md p-4 border border-beige-300">
<h2 className="text-xl font-bold text-gray-800 mb-4">Nous trouver</h2>
<div className="rounded-lg overflow-hidden relative">
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2884.5!2d7.2619!3d43.7102!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x12cdd0106a852d31%3A0x40819a5fd979a70!2s18%20Av.%20Thiers%2C%2006000%20Nice%2C%20France!5e0!3m2!1sfr!2sfr!4v1700000000000!5m2!1sfr!2sfr"
width="100%"
height="250"
style={{ border: 0 }}
allowFullScreen
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
title="Localisation Thé Tip Top - 18 Avenue Thiers, Nice"
></iframe>
{/* Point rouge cliquable */}
<a
href="https://www.google.com/maps/search/?api=1&query=18+Avenue+Thiers+06000+Nice+France"
target="_blank"
rel="noopener noreferrer"
className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-10 group"
aria-label="Voir notre emplacement sur Google Maps - 18 Avenue Thiers, Nice"
>
<span className="block w-6 h-6 bg-primary-500 rounded-full border-2 border-white shadow-lg cursor-pointer hover:scale-125 transition-transform animate-pulse" aria-hidden="true"></span>
<span className="absolute -bottom-1 left-1/2 transform -translate-x-1/2 w-0 h-0 border-l-[6px] border-r-[6px] border-t-[8px] border-l-transparent border-r-transparent border-t-primary-500" aria-hidden="true"></span>
</a>
</div>
<a
href="https://www.google.com/maps/search/?api=1&query=18+Avenue+Thiers+06000+Nice+France"
target="_blank"
rel="noopener noreferrer"
className="mt-3 inline-flex items-center gap-2 text-sm text-primary-500 hover:text-primary-600 transition-colors"
>
Ouvrir dans Google Maps
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
</a>
</div>
</div>
</div>
</div>
</div>
</section>
{/* CTA FAQ Section */}
<section className="py-12">
<div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto">
<div className="bg-gradient-to-r from-primary-50 to-primary-100 rounded-xl p-8 border-l-4 border-primary-500 shadow-lg">
<div className="flex items-start gap-4">
<div className="w-16 h-16 bg-gradient-to-br from-primary-500 to-primary-600 rounded-full flex items-center justify-center text-3xl shadow-md flex-shrink-0">💡</div>
<div className="flex-1">
<h3 className="text-xl font-bold text-gray-800 mb-2">Avant de nous contacter</h3>
<p className="text-gray-700 mb-4">
Consultez notre FAQ, vous y trouverez peut-être la réponse à votre question !
</p>
<Link
href="/faq"
className="inline-flex items-center justify-center bg-gradient-to-r from-primary-500 to-primary-600 hover:from-primary-400 hover:to-primary-500 text-white font-bold px-6 py-3 rounded-lg transition-all duration-300 shadow-lg hover:scale-105"
>
Voir la FAQ
</Link>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
);
}