You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

389 lines
15 KiB

'use client';
import { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
export default function Contact() {
const [formData, setFormData] = useState({
firstName: '',
lastName: '',
email: '',
phone: '',
message: '',
});
const [status, setStatus] = useState<'idle' | 'submitting' | 'success' | 'error'>('idle');
const [errorMessage, setErrorMessage] = useState('');
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setStatus('submitting');
setErrorMessage('');
const form = e.currentTarget;
const formDataObj = new FormData(form);
try {
const response = await fetch(form.action, {
method: form.method,
body: formDataObj,
headers: {
'Accept': 'application/json',
},
});
if (response.ok) {
setStatus('success');
setFormData({
firstName: '',
lastName: '',
email: '',
phone: '',
message: '',
});
form.reset();
// Reset success message after 6 seconds
setTimeout(() => {
setStatus('idle');
}, 6000);
} else {
const responseData = await response.json();
if (responseData.errors) {
setErrorMessage(responseData.errors.map((error: { message: string }) => error.message).join(', '));
} else {
setErrorMessage('Oops! There was a problem submitting your form. Please try again.');
}
setStatus('error');
}
} catch (error) {
console.error('Form submission error:', error);
setErrorMessage('Oops! There was a problem submitting your form. Please check your connection and try again.');
setStatus('error');
}
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};
return (
<section id="contact" className="py-20 md:py-32 bg-white">
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-100px' }}
transition={{ duration: 0.8, ease: [0.25, 0.1, 0.25, 1] }}
className="text-center mb-12"
>
<h2 style={{ color: '#00171F' }} className="text-3xl md:text-4xl lg:text-5xl font-bold mb-4">
Contact Me
</h2>
<p style={{ color: '#00171F' }} className="text-lg md:text-xl">
I&apos;m here for you!
</p>
<p style={{ color: '#00171F' }} className="mt-2">
I'm available for both private sessions as well as public speaking arrangements and tailored workshops. Contact me directly for more detailed information and a non-commitment quote.
</p>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-100px' }}
transition={{ duration: 0.8, delay: 0.2, ease: [0.25, 0.1, 0.25, 1] }}
>
<AnimatePresence mode="wait">
{status === 'success' ? (
<motion.div
key="success"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="relative overflow-hidden"
>
{/* Animated background circles */}
<motion.div
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 0.1 }}
transition={{ duration: 0.8, ease: 'easeOut' }}
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-96 h-96 rounded-full"
style={{ backgroundColor: '#EED2CC' }}
/>
<motion.div
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 0.15 }}
transition={{ duration: 0.8, delay: 0.2, ease: 'easeOut' }}
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-64 h-64 rounded-full"
style={{ backgroundColor: '#7D6E5E' }}
/>
<motion.div
initial={{ opacity: 0, scale: 0.5, y: 50 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{
type: 'spring',
stiffness: 200,
damping: 20,
duration: 0.6
}}
className="relative text-center py-16 px-6 rounded-2xl"
style={{ backgroundColor: '#FBF7F4' }}
>
{/* Success icon with multiple animations */}
<motion.div
initial={{ scale: 0, rotate: -180 }}
animate={{ scale: 1, rotate: 0 }}
transition={{
type: 'spring',
stiffness: 200,
damping: 15,
delay: 0.2
}}
className="relative w-24 h-24 mx-auto mb-8"
>
<motion.div
initial={{ scale: 0 }}
animate={{ scale: [0, 1.2, 1] }}
transition={{ duration: 0.6, delay: 0.3 }}
className="absolute inset-0 rounded-full"
style={{ backgroundColor: '#EED2CC' }}
/>
<motion.div
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ duration: 0.4, delay: 0.5 }}
className="absolute inset-0 flex items-center justify-center"
>
<motion.svg
initial={{ pathLength: 0, opacity: 0 }}
animate={{ pathLength: 1, opacity: 1 }}
transition={{ duration: 0.6, delay: 0.6 }}
className="w-12 h-12"
fill="none"
stroke="#00171F"
strokeWidth="3"
strokeLinecap="round"
strokeLinejoin="round"
viewBox="0 0 24 24"
>
<motion.path
d="M5 13l4 4L19 7"
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
transition={{ duration: 0.5, delay: 0.7 }}
/>
</motion.svg>
</motion.div>
</motion.div>
{/* Confetti effect using dots */}
{[...Array(12)].map((_, i) => (
<motion.div
key={i}
initial={{
opacity: 0,
scale: 0,
x: 0,
y: 0,
}}
animate={{
opacity: [0, 1, 0],
scale: [0, 1, 0],
x: Math.cos((i * Math.PI * 2) / 12) * 100,
y: Math.sin((i * Math.PI * 2) / 12) * 100,
}}
transition={{
duration: 1.5,
delay: 0.8 + i * 0.05,
ease: 'easeOut',
}}
className="absolute top-1/2 left-1/2 w-2 h-2 rounded-full"
style={{
backgroundColor: ['#EED2CC', '#7D6E5E', '#00171F'][i % 3]
}}
/>
))}
<motion.h3
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.9, type: 'spring', stiffness: 100 }}
style={{ color: '#00171F' }}
className="text-3xl md:text-4xl font-bold mb-4 relative z-10"
>
Thank you for your message!
</motion.h3>
<motion.p
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 1.0 }}
style={{ color: '#00171F' }}
className="text-lg md:text-xl opacity-90 relative z-10"
>
I&apos;ll get back to you soon.
</motion.p>
{/* Subtle pulse animation */}
<motion.div
animate={{
scale: [1, 1.05, 1],
opacity: [0.3, 0.5, 0.3]
}}
transition={{
duration: 2,
repeat: Infinity,
ease: 'easeInOut'
}}
className="absolute inset-0 rounded-2xl pointer-events-none"
style={{ backgroundColor: '#EED2CC' }}
/>
</motion.div>
</motion.div>
) : (
<motion.form
key="form"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onSubmit={handleSubmit}
action="https://formspree.io/f/mpwblljv"
method="POST"
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 mb-2" style={{ color: '#00171F' }}>
First name <span className="text-red-500">*</span>
</label>
<input
type="text"
id="firstName"
name="firstName"
required
value={formData.firstName}
onChange={handleChange}
className="w-full px-4 py-3 border rounded-lg outline-none transition-all"
style={{ borderColor: '#EED2CC', color: '#00171F' }}
/>
</div>
<div>
<label htmlFor="lastName" className="block text-sm font-medium mb-2" style={{ color: '#00171F' }}>
Last name <span className="text-red-500">*</span>
</label>
<input
type="text"
id="lastName"
name="lastName"
required
value={formData.lastName}
onChange={handleChange}
className="w-full px-4 py-3 border rounded-lg outline-none transition-all"
style={{ borderColor: '#EED2CC', color: '#00171F' }}
/>
</div>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium mb-2" style={{ color: '#00171F' }}>
Email <span className="text-red-500">*</span>
</label>
<input
type="email"
id="email"
name="email"
required
value={formData.email}
onChange={handleChange}
className="w-full px-4 py-3 border rounded-lg outline-none transition-all"
style={{ borderColor: '#EED2CC', color: '#00171F' }}
/>
</div>
<div>
<label htmlFor="phone" className="block text-sm font-medium mb-2" style={{ color: '#00171F' }}>
Phone
</label>
<input
type="tel"
id="phone"
name="phone"
value={formData.phone}
onChange={handleChange}
className="w-full px-4 py-3 border rounded-lg outline-none transition-all"
style={{ borderColor: '#EED2CC', color: '#00171F' }}
/>
</div>
<div>
<label htmlFor="message" className="block text-sm font-medium mb-2" style={{ color: '#00171F' }}>
Message
</label>
<textarea
id="message"
name="message"
rows={6}
value={formData.message}
onChange={handleChange}
className="w-full px-4 py-3 border rounded-lg outline-none transition-all resize-none"
style={{ borderColor: '#EED2CC', color: '#00171F' }}
/>
</div>
<AnimatePresence>
{errorMessage && (
<motion.div
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
className="p-4 rounded-lg border"
style={{
backgroundColor: '#FBF7F4',
borderColor: '#EED2CC',
color: '#00171F'
}}
>
<p className="text-sm">{errorMessage}</p>
</motion.div>
)}
</AnimatePresence>
<button
type="submit"
disabled={status === 'submitting'}
style={{ backgroundColor: '#00171F' }}
className="w-full text-white px-8 py-4 rounded-full text-lg font-semibold hover:opacity-90 transition-all transform hover:scale-105 shadow-lg hover:shadow-xl disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none"
>
{status === 'submitting' ? (
<span className="flex items-center justify-center">
<motion.svg
animate={{ rotate: 360 }}
transition={{ duration: 1, repeat: Infinity, ease: 'linear' }}
className="w-5 h-5 mr-2"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</motion.svg>
Sending...
</span>
) : (
'Send'
)}
</button>
</motion.form>
)}
</AnimatePresence>
</motion.div>
</div>
</section>
);
}

Powered by TurnKey Linux.