feat: Implement a 15-minute rate limit per email for contact form submissions.
This commit is contained in:
@@ -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 }}
|
||||||
|
|||||||
Reference in New Issue
Block a user