diff --git a/client/package-lock.json b/client/package-lock.json index 165d073..6ef5bd4 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -18,6 +18,7 @@ "react": "^19.1.0", "react-chartjs-2": "^5.3.0", "react-dom": "^19.1.0", + "react-hot-toast": "^2.6.0", "react-icons": "^5.5.0", "react-router-dom": "^6.30.1", "recharts": "^3.0.2", @@ -2727,8 +2728,7 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/d3-array": { "version": "3.2.4", @@ -3468,6 +3468,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/goober": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", + "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -4342,6 +4351,23 @@ "react": "^19.1.0" } }, + "node_modules/react-hot-toast": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.0.tgz", + "integrity": "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.3", + "goober": "^2.1.16" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/react-icons": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", diff --git a/client/package.json b/client/package.json index 9ef6783..eb54292 100644 --- a/client/package.json +++ b/client/package.json @@ -20,6 +20,7 @@ "react": "^19.1.0", "react-chartjs-2": "^5.3.0", "react-dom": "^19.1.0", + "react-hot-toast": "^2.6.0", "react-icons": "^5.5.0", "react-router-dom": "^6.30.1", "recharts": "^3.0.2", diff --git a/client/src/App.jsx b/client/src/App.jsx index 7ebc50c..8e4b4fe 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -1,31 +1,70 @@ -// import Header from "./components/Header"; -// import Home from "./pages/Home"; -// import Footer from "./components/Footer"; - -// function App() { -// return ( -//
-//
-// -//
-// ); -// } -// export default App; import { Outlet } from "react-router-dom"; import Header from "./components/Header"; import Footer from "./components/Footer"; import ScrollToTop from "./components/ScrollToTop"; +import { Toaster } from "react-hot-toast"; function App() { return (
+
{/* This will render the current page */}
+
); } diff --git a/client/src/components/ContactForm.jsx b/client/src/components/ContactForm.jsx index be022ad..a6e7e0d 100644 --- a/client/src/components/ContactForm.jsx +++ b/client/src/components/ContactForm.jsx @@ -3,209 +3,184 @@ import axios from "axios"; import { FaPaperPlane } from "react-icons/fa"; export default function ContactForm() { - const [formData, setFormData] = useState({ - name: "", - email: "", - subject: "", - category: "general", - message: "", - }); + const [formData, setFormData] = useState({ + name: "", + email: "", + subject: "", + category: "general", + message: "", + }); - const [isSubmitting, setIsSubmitting] = useState(false); - const [isSubmitted, setIsSubmitted] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); - const categories = [ - { value: "general", label: "General Inquiry" }, - { value: "feature", label: "Feature Request" }, - { value: "bug", label: "Bug Report" }, - { value: "collaboration", label: "Collaboration" }, - ]; + const categories = [ + { value: "general", label: "General Inquiry" }, + { value: "feature", label: "Feature Request" }, + { value: "bug", label: "Bug Report" }, + { value: "collaboration", label: "Collaboration" }, + ]; - const handleChange = (e) => { - const { name, value } = e.target; - setFormData((prev) => ({ ...prev, [name]: value })); - }; + const handleChange = (e) => { + const { name, value } = e.target; + setFormData((prev) => ({ ...prev, [name]: value })); + }; - const handleSubmit = async (e) => { - e.preventDefault(); - setIsSubmitting(true); + const handleSubmit = async (e) => { + e.preventDefault(); + setIsSubmitting(true); - try { - const response = await axios.post( - `${import.meta.env.VITE_API_URL}/api/contact`, - formData, - { - headers: { - "Content-Type": "application/json", - }, - } - ); + try { + await axios.post( + `${import.meta.env.VITE_API_URL}/api/contact`, + formData, + { headers: { "Content-Type": "application/json" } } + ); - setIsSubmitted(true); - setTimeout(() => { - setIsSubmitted(false); - setFormData({ - name: "", - email: "", - subject: "", - category: "general", - message: "", - }); - }, 5000); - } catch (error) { - console.error("Error submitting contact form:", error); - alert( - "There was an error submitting your message. Please try again later." - ); - } finally { - setIsSubmitting(false); - } - }; + alert("Message sent successfully ✅"); + setFormData({ + name: "", + email: "", + subject: "", + category: "general", + message: "", + }); + } catch (error) { + console.error("Error submitting contact form:", error); + alert("❌ There was an error submitting your message."); + } finally { + setIsSubmitting(false); + } + }; - if (isSubmitted) { - return ( -
-
- -
-

- Message Sent! -

-

- Thank you for reaching out. We'll get back to you within 24 - hours. -

-
- ); - } + return ( +
+

+ Send us a Message +

- return ( -
-

- Send us a Message -

+
+ {/* Name + Email */} +
+
+ + +
+
+ + +
+
- -
-
- - -
-
- - -
-
+ {/* Category + Subject */} +
+
+ + +
+
+ + +
+
-
-
- - -
-
- - -
-
-
- -