diff --git a/package.json b/package.json
index 87671d1..6fe1d63 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,9 @@
"preview": "vite preview"
},
"dependencies": {
+
"@react-pdf/renderer": "^4.3.0",
+
"@tailwindcss/vite": "^4.1.11",
"framer": "^2.4.1",
"lottie-react": "^2.4.1",
diff --git a/src/components/ContactPage.jsx b/src/components/ContactPage.jsx
index 584fdda..b2a046b 100644
--- a/src/components/ContactPage.jsx
+++ b/src/components/ContactPage.jsx
@@ -1,105 +1,397 @@
import React, { useState, useEffect } from 'react';
-import { Link } from 'react-router-dom'; // Placeholder, navigation is handled by props
-import { Send, User, Mail } from 'lucide-react';
-import Footer from './Footer';
-
-const ContactPage = ({ darkMode, navigateTo }) => {
- // State to control the animations
- const [isVisible, setIsVisible] = useState(false);
-
- // useEffect to trigger the animation on component mount
- useEffect(() => {
- const timer = setTimeout(() => setIsVisible(true), 100);
- return () => clearTimeout(timer);
- }, []);
-
- return (
- // Main container with dynamic background
-
-
-
-
- {/* Animated content card */}
-
-
+// Import specific icons from lucide-react. This is the correct way to import them.
+import { Send, User, Mail, MessageSquare, BookOpen, CheckCircle, XCircle, MapPin, Phone, Linkedin, Twitter, Github, Sun, Moon } from 'lucide-react';
+
+// Footer Component: Displays copyright information.
+const Footer = () => {
+ return (
+
+ );
+};
+
+// App Component: Main entry point, manages dark mode and renders ContactPage.
+export default function App() {
+ // State to manage the dark mode toggle
+ const [darkMode, setDarkMode] = useState(false);
+
+ // Placeholder function for navigation. Can be expanded with React Router if needed.
+ const navigateTo = (path) => {
+ console.log(`Navigating to ${path}`);
+ };
+
+ return (
+ // Render the ContactPage, passing dark mode state and setter, and navigate function
+
+ );
+}
+
+// ContactPage Component: Handles the contact form, UI, and email sending logic.
+const ContactPage = ({ darkMode, navigateTo, setDarkMode }) => {
+ // State for animating the main content card visibility
+ const [isVisible, setIsVisible] = useState(false);
+ // State to store form input data
+ const [formData, setFormData] = useState({
+ name: '',
+ email: '',
+ subject: '',
+ message: '',
+ });
+ // State to store form validation errors
+ const [errors, setErrors] = useState({});
+ // State to track if the form is currently being submitted
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ // State to store the result of the form submission (success or error)
+ const [submissionStatus, setSubmissionStatus] = useState(null);
+ // State to control the visibility of the toast notification
+ const [showToast, setShowToast] = useState(false);
+
+ // Effect to trigger the initial fade-in animation for the content card
+ useEffect(() => {
+ const timer = setTimeout(() => setIsVisible(true), 100);
+ return () => clearTimeout(timer); // Cleanup timer on unmount
+ }, []);
+
+ // Effect to dynamically load the emailjs library as a global script.
+ // This resolves "Dynamic require" errors often seen in certain environments.
+ useEffect(() => {
+ const script = document.createElement('script');
+ script.src = 'https://cdn.jsdelivr.net/npm/@emailjs/browser@3/dist/email.min.js';
+ script.async = true; // Load script asynchronously to not block parsing
+
+ script.onload = () => {
+ console.log('emailjs script loaded successfully.');
+ // EmailJS library initializes itself when loaded, no explicit init needed here
+ // if you're passing the public key directly in the send method.
+ };
+
+ script.onerror = (error) => {
+ console.error('Failed to load emailjs script:', error);
+ };
+
+ document.body.appendChild(script); // Append the script to the document body
+
+ // Cleanup function: remove the script from the DOM when the component unmounts
+ return () => {
+ // Check if the script exists before trying to remove it
+ if (document.body.contains(script)) {
+ document.body.removeChild(script);
+ }
+ };
+ }, []); // Empty dependency array ensures this effect runs only once on mount
+
+ // Effect to manage the auto-hiding of the toast notification
+ useEffect(() => {
+ if (showToast) {
+ const toastTimer = setTimeout(() => {
+ setShowToast(false);
+ setSubmissionStatus(null); // Reset submission status after toast hides
+ }, 5000); // Toast will be visible for 5 seconds
+ return () => clearTimeout(toastTimer); // Cleanup timer on unmount or when toast hides
+ }
+ }, [showToast]); // Re-run this effect whenever showToast changes
+
+ // Handles changes in form input fields (for controlled components)
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setFormData((prevData) => ({
+ ...prevData,
+ [name]: value, // Update the specific field
+ }));
+
+ // Clear any previous validation error for the current field as the user types
+ setErrors((prevErrors) => ({
+ ...prevErrors,
+ [name]: null,
+ }));
+ };
+
+ // Validates the form fields before submission
+ const validateForm = () => {
+ let newErrors = {};
+ // Check if name is empty
+ if (!formData.name.trim()) {
+ newErrors.name = 'Name is required';
+ }
+ // Check if email is empty or invalid format
+ if (!formData.email.trim()) {
+ newErrors.email = 'Email is required';
+ } else if (!/\S+@\S+\.\S+/.test(formData.email)) {
+ newErrors.email = 'Email address is invalid';
+ }
+ // Check if message is empty
+ if (!formData.message.trim()) {
+ newErrors.message = 'Message is required';
+ }
+
+ setErrors(newErrors); // Update the errors state
+ // Return true if there are no errors, false otherwise
+ return Object.keys(newErrors).length === 0;
+ };
+
+ // Handles the form submission event
+ const handleSubmit = (e) => {
+ e.preventDefault(); // Prevent default browser form submission behavior (page reload)
+ setSubmissionStatus(null); // Clear previous submission status
+ setShowToast(false); // Hide any currently visible toast
+
+ // Run form validation
+ if (!validateForm()) {
+ return; // If validation fails, stop the submission process
+ }
+
+ setIsSubmitting(true); // Set submitting state to true to show loading indicator
+
+ // EmailJS service credentials (replace with your actual credentials if different)
+ const serviceID = 'service_sc9xokh';
+ const templateID = 'template_22c3a2a';
+ const publicKey = 'bcz_108RDETTP_XP4'; // Your EmailJS Public Key
+
+ // Check if window.emailjs is available (meaning the script has loaded)
+ if (window.emailjs) {
+ // Send the email using EmailJS
+ window.emailjs.send(serviceID, templateID, formData, publicKey)
+ .then((response) => {
+ console.log('Email sent successfully!', response.status, response.text);
+ setSubmissionStatus('success'); // Set success status
+ setFormData({ name: '', email: '', subject: '', message: '' }); // Clear the form fields
+ })
+ .catch((err) => {
+ console.error('Failed to send email:', err);
+ setSubmissionStatus('error'); // Set error status
+ })
+ .finally(() => {
+ setIsSubmitting(false); // Reset submitting state regardless of success/failure
+ setShowToast(true); // Show the toast notification
+ });
+ } else {
+ // Handle case where EmailJS library hasn't loaded (e.g., network issue)
+ console.error('EmailJS library is not loaded. Cannot send email.');
+ setSubmissionStatus('error');
+ setIsSubmitting(false);
+ setShowToast(true);
+ }
+ };
+
+ return (
+ // Main container div with dynamic background color and font based on dark mode
+
+ {/* Background gradient overlay, transitions with isVisible for a soft entrance */}
+
+
+
- {/* Animated Description */}
-
- Have a question or feedback? We'd love to hear from you.
-
-
- {/* Clickable Mailto Link, styled as a button */}
-
- {/* Stylish Heading */}
-
- Get In Touch
-
-
- {/* Subheading */}
-
- Whether it's a question, suggestion, or feedback—drop us a line!
-
-
- {/* Button with icon before text */}
-
-
-
-
-
-
-
- {/* Developer Details */}
-
-
- This project is maintained by:
-
-
-
- Tanmay Kalra
-
+ {/* Dark Mode Toggle button: Positioned at the top right */}
+
+
-
+ {/* Main Content Area: Centered horizontally and vertically */}
+
+
+ {/* Main Content Card: Animated with shadow, border, and blur effect */}
+
+ {/* Left Section: Contact Information */}
+
{/* Dynamic background for left panel */}
+
+
Contact Us
+
Feel free to reach out to us through any of these channels.
+
+
+ {/* Location Info */}
+
+
+
123 Main Street, Anytown, USA
+
+ {/* Email Info */}
+
+
+
info@smartlog.com
+
+ {/* Phone Info */}
+
+
+
+1 (555) 123-4567
+
+
+
+
+ {/* Social Media Icons */}
+
+
+
+
+
+
+
+ {/* Right Section: Get In Touch Form */}
+
{/* Dynamic background for right panel */}
+
+ Get In Touch
+
+
+
+ Have a question or feedback? We'd love to hear from you.
+
+
+
+
+ {/* Project Maintainer Info */}
+
+
+ This project is maintained by:
+
+
+
+ Tanmay Kalra
+
+
+
+
+
+
+
+ {/* Confirmation Toast Notification: Appears at the bottom right */}
+ {showToast && (
+