feat: update portfolio with new contact form functionality and improved styling
- Removed outdated CV file and replaced with a new image for the profile. - Implemented a new email service using EmailJS for contact form submissions. - Enhanced the contact form to handle errors and success messages. - Updated the About section for grammatical accuracy. - Modified the Hero component to link to the new CV file and updated GitHub profile link. - Updated project links to point to the correct GitHub repositories. - Improved styling for error messages and avatar image with hover effects.
This commit is contained in:
@@ -69,7 +69,7 @@ const About = () => {
|
||||
<motion.div className="about-card" variants={itemVariants}>
|
||||
<h3>Ma passion</h3>
|
||||
<p>
|
||||
Ce qui m'anime le plus, c'est la création d'solutions innovantes qui résolvent
|
||||
Ce qui m'anime le plus, c'est la création de solutions innovantes qui résolvent
|
||||
des problèmes réels. J'aime particulièrement le développement mobile avec
|
||||
<strong> Flutter</strong> et le développement web moderne avec
|
||||
<strong> React</strong> et <strong> TypeScript</strong>.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useState } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Mail, Phone, MapPin, Send, Github, Linkedin, MessageCircle, CheckCircle } from 'lucide-react';
|
||||
import { Mail, Phone, MapPin, Send, Github, Linkedin, MessageCircle, CheckCircle, AlertCircle } from 'lucide-react';
|
||||
import { sendContactEmail } from '../services/emailService';
|
||||
import type { ContactFormData } from '../services/emailService';
|
||||
|
||||
const Contact = () => {
|
||||
const [formData, setFormData] = useState({
|
||||
@@ -11,6 +13,7 @@ const Contact = () => {
|
||||
});
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [isSubmitted, setIsSubmitted] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
const { name, value } = e.target;
|
||||
@@ -23,32 +26,51 @@ const Contact = () => {
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
setError(null);
|
||||
|
||||
// Simulation d'envoi (remplacez par votre logique d'envoi réelle)
|
||||
setTimeout(() => {
|
||||
setIsSubmitting(false);
|
||||
setIsSubmitted(true);
|
||||
setFormData({ name: '', email: '', subject: '', message: '' });
|
||||
try {
|
||||
const contactData: ContactFormData = {
|
||||
name: formData.name,
|
||||
email: formData.email,
|
||||
subject: formData.subject,
|
||||
message: formData.message
|
||||
};
|
||||
|
||||
// Reset du message de succès après 5 secondes
|
||||
setTimeout(() => {
|
||||
setIsSubmitted(false);
|
||||
}, 5000);
|
||||
}, 2000);
|
||||
const result = await sendContactEmail(contactData);
|
||||
|
||||
if (result.success) {
|
||||
setIsSubmitted(true);
|
||||
setFormData({ name: '', email: '', subject: '', message: '' });
|
||||
|
||||
// Reset du message de succès après 5 secondes
|
||||
setTimeout(() => {
|
||||
setIsSubmitted(false);
|
||||
}, 5000);
|
||||
} else {
|
||||
setError(result.message);
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : 'Une erreur est survenue lors de l\'envoi du message.';
|
||||
setError(errorMessage);
|
||||
console.error('Erreur lors de l\'envoi de l\'email:', err);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const contactInfo = [
|
||||
{
|
||||
icon: <Mail size={24} />,
|
||||
title: "Email",
|
||||
content: "dayronvanleemput@gmail.com", // Remplacez par votre email
|
||||
content: "dayronvanleemput@gmail.com",
|
||||
link: "mailto:dayronvanleemput@gmail.com",
|
||||
color: "#EA4335"
|
||||
},
|
||||
{
|
||||
icon: <Phone size={24} />,
|
||||
title: "Téléphone",
|
||||
content: "+32 455 19 47 62", // Remplacez par votre numéro
|
||||
content: "+32 455 19 47 62",
|
||||
link: "tel:+32455194762",
|
||||
color: "#34A853"
|
||||
},
|
||||
@@ -214,6 +236,18 @@ const Contact = () => {
|
||||
Message envoyé avec succès ! Je vous répondrai bientôt.
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<motion.div
|
||||
className="error-message"
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.8 }}
|
||||
>
|
||||
<AlertCircle size={20} />
|
||||
{error}
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
<form onSubmit={handleSubmit} className="contact-form">
|
||||
<div className="form-row">
|
||||
@@ -330,7 +364,7 @@ const Contact = () => {
|
||||
viewport={{ once: true }}
|
||||
>
|
||||
<p>
|
||||
© 2025 Dayron Van Leemput. Développé avec ❤️ en React et TypeScript.
|
||||
© 2025 Dayron Van Leemput.
|
||||
</p>
|
||||
</motion.footer>
|
||||
</div>
|
||||
|
||||
@@ -5,8 +5,8 @@ const Hero = () => {
|
||||
const handleDownloadCV = () => {
|
||||
// Ici, vous pouvez ajouter le lien vers votre CV
|
||||
const link = document.createElement('a');
|
||||
link.href = '/cv-dayron-van-leemput.pdf'; // Ajoutez votre CV dans le dossier public
|
||||
link.download = 'CV-Dayron-Van-Leemput.pdf';
|
||||
link.href = '/Dayron_Van_Leemput_CV.pdf'; // Ajoutez votre CV dans le dossier public
|
||||
link.download = 'Dayron_Van_Leemput_CV.pdf';
|
||||
link.click();
|
||||
};
|
||||
|
||||
@@ -85,7 +85,7 @@ const Hero = () => {
|
||||
transition={{ duration: 0.8, delay: 1.2 }}
|
||||
>
|
||||
<motion.a
|
||||
href="https://github.com/dayronvanleemput" // Remplacez par votre profil GitHub
|
||||
href="https://github.com/Dayron-HELHa" // Remplacez par votre profil GitHub
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="social-link"
|
||||
@@ -119,10 +119,11 @@ const Hero = () => {
|
||||
whileHover={{ scale: 1.05, rotate: 5 }}
|
||||
transition={{ type: "spring", stiffness: 300, damping: 10 }}
|
||||
>
|
||||
{/* Vous pouvez remplacer ceci par votre photo */}
|
||||
<div className="avatar-placeholder">
|
||||
<span>DV</span>
|
||||
</div>
|
||||
<img
|
||||
src="/dvl.jpg"
|
||||
alt="Dayron Van Leemput - Portrait"
|
||||
className="avatar-image"
|
||||
/>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
|
||||
@@ -18,7 +18,7 @@ const Projects = () => {
|
||||
color: "#4CAF50",
|
||||
icon: <MapPin size={24} />,
|
||||
links: {
|
||||
github: "#", // Remplacez par votre lien GitHub
|
||||
github: "https://github.com/Dayron-HELHa/travel_mate", // Remplacez par votre lien GitHub
|
||||
demo: "#"
|
||||
},
|
||||
image: "/travel-mate-preview.png" // Ajoutez votre image dans le dossier public
|
||||
@@ -38,8 +38,8 @@ const Projects = () => {
|
||||
color: "#2196F3",
|
||||
icon: <ExternalLink size={24} />,
|
||||
links: {
|
||||
github: "https://github.com/dayronvanleemput/portfolio", // Remplacez par votre lien
|
||||
demo: "https://dayronvanleemput.dev" // Remplacez par votre lien
|
||||
github: "https://github.com/Dayron-HELHa/xeewy.eu", // Remplacez par votre lien
|
||||
demo: "https://xeewy.eu" // Remplacez par votre lien
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user