feat: Implement a 15-minute rate limit per email for contact form submissions.

This commit is contained in:
Van Leemput Dayron
2025-12-02 08:58:56 +01:00
parent 0518588121
commit 404e493aa8

View File

@@ -27,9 +27,24 @@ const Contact = () => {
const handleSubmit = async (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
// Vérification du délai de 15 minutes par email
const storageKey = `lastMessageTime_${formData.email}`;
const lastMessageTime = localStorage.getItem(storageKey);
if (lastMessageTime) {
const timeSinceLastMessage = Date.now() - parseInt(lastMessageTime, 10);
const fifteenMinutes = 15 * 60 * 1000;
if (timeSinceLastMessage < fifteenMinutes) {
const remainingMinutes = Math.ceil((fifteenMinutes - timeSinceLastMessage) / 60000);
setError(`Veuillez attendre ${remainingMinutes} minutes avant d'envoyer un nouveau message avec cette adresse email.`);
return;
}
}
setIsSubmitting(true); setIsSubmitting(true);
setError(null); setError(null);
try { try {
const contactData: ContactFormData = { const contactData: ContactFormData = {
name: formData.name, name: formData.name,
@@ -37,13 +52,14 @@ const Contact = () => {
subject: formData.subject, subject: formData.subject,
message: formData.message message: formData.message
}; };
const result = await sendContactEmail(contactData); const result = await sendContactEmail(contactData);
if (result.success) { if (result.success) {
localStorage.setItem(`lastMessageTime_${formData.email}`, Date.now().toString());
setIsSubmitted(true); setIsSubmitted(true);
setFormData({ name: '', email: '', subject: '', message: '' }); setFormData({ name: '', email: '', subject: '', message: '' });
// Reset du message de succès après 5 secondes // Reset du message de succès après 5 secondes
setTimeout(() => { setTimeout(() => {
setIsSubmitted(false); setIsSubmitted(false);
@@ -51,7 +67,7 @@ const Contact = () => {
} else { } else {
setError(result.message); setError(result.message);
} }
} catch (err) { } catch (err) {
const errorMessage = err instanceof Error ? err.message : 'Une erreur est survenue lors de l\'envoi du message.'; const errorMessage = err instanceof Error ? err.message : 'Une erreur est survenue lors de l\'envoi du message.';
setError(errorMessage); setError(errorMessage);
@@ -72,7 +88,7 @@ const Contact = () => {
{ {
icon: <Phone size={24} />, icon: <Phone size={24} />,
title: "Téléphone", title: "Téléphone",
content: "+32 455 19 47 62", content: "+32 455 19 47 62",
link: "tel:+32455194762", link: "tel:+32455194762",
color: "#34A853" color: "#34A853"
}, },
@@ -176,7 +192,7 @@ const Contact = () => {
}} }}
viewport={{ once: true }} viewport={{ once: true }}
> >
<div <div
className="contact-icon" className="contact-icon"
style={{ backgroundColor: `${contact.color}20`, color: contact.color }} style={{ backgroundColor: `${contact.color}20`, color: contact.color }}
> >
@@ -210,7 +226,7 @@ const Contact = () => {
}} }}
viewport={{ once: true }} viewport={{ once: true }}
> >
<div <div
className="social-icon" className="social-icon"
style={{ backgroundColor: `${social.color}20`, color: social.color }} style={{ backgroundColor: `${social.color}20`, color: social.color }}
> >
@@ -226,7 +242,7 @@ const Contact = () => {
{/* Formulaire de contact */} {/* Formulaire de contact */}
<motion.div className="contact-form-container" variants={itemVariants}> <motion.div className="contact-form-container" variants={itemVariants}>
<h3>{t('contact.sendMessage')}</h3> <h3>{t('contact.sendMessage')}</h3>
{isSubmitted && ( {isSubmitted && (
<motion.div <motion.div
className="success-message" className="success-message"
@@ -238,7 +254,7 @@ const Contact = () => {
{t('contact.success')} {t('contact.success')}
</motion.div> </motion.div>
)} )}
{error && ( {error && (
<motion.div <motion.div
className="error-message" className="error-message"
@@ -253,7 +269,7 @@ const Contact = () => {
<form onSubmit={handleSubmit} className="contact-form"> <form onSubmit={handleSubmit} className="contact-form">
<div className="form-row"> <div className="form-row">
<motion.div <motion.div
className="form-group" className="form-group"
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }} whileInView={{ opacity: 1, y: 0 }}
@@ -272,7 +288,7 @@ const Contact = () => {
/> />
</motion.div> </motion.div>
<motion.div <motion.div
className="form-group" className="form-group"
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }} whileInView={{ opacity: 1, y: 0 }}
@@ -292,7 +308,7 @@ const Contact = () => {
</motion.div> </motion.div>
</div> </div>
<motion.div <motion.div
className="form-group" className="form-group"
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }} whileInView={{ opacity: 1, y: 0 }}
@@ -311,7 +327,7 @@ const Contact = () => {
/> />
</motion.div> </motion.div>
<motion.div <motion.div
className="form-group" className="form-group"
initial={{ opacity: 0, y: 20 }} initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }} whileInView={{ opacity: 1, y: 0 }}