-
Notifications
You must be signed in to change notification settings - Fork 63
integrated emailjs #208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
integrated emailjs #208
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,30 +1,57 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useState, useContext } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import emailjs from "@emailjs/browser"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CheckCircle, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Github, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Mail, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Phone, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Send, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| X, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CheckCircle, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from "lucide-react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ThemeContext } from "../../context/ThemeContext"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useContext, useRef, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { ThemeContextType } from "../../context/ThemeContext"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ThemeContext } from "../../context/ThemeContext"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function Contact() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [showPopup, setShowPopup] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [isSubmitting, setIsSubmitting] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const themeContext = useContext(ThemeContext) as ThemeContextType; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { mode } = themeContext; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleSubmit = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Refs for form fields | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const nameRef = useRef<HTMLInputElement>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const emailRef = useRef<HTMLInputElement>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const subjectRef = useRef<HTMLSelectElement>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const messageRef = useRef<HTMLTextAreaElement>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleSubmit = async (e?: React.MouseEvent<HTMLButtonElement>) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (e) e.preventDefault(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsSubmitting(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+27
to
29
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Submit via form onSubmit to leverage native required-field validation. Right now required attributes won’t prevent the button click. Hook the handler to the form’s onSubmit and make the button type="submit". Apply this diff: - const handleSubmit = async (e?: React.MouseEvent<HTMLButtonElement>) => {
- if (e) e.preventDefault();
+ const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
+ e.preventDefault();- <div className="space-y-3 sm:space-y-4 flex-1 flex flex-col">
+ <form onSubmit={handleSubmit} className="space-y-3 sm:space-y-4 flex-1 flex flex-col" noValidate>- <button
- onClick={handleSubmit}
- disabled={isSubmitting}
+ <button
+ type="submit"
+ disabled={isSubmitting}Also applies to: 221-221, 318-324 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Simulate API call | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await new Promise((resolve) => setTimeout(resolve, 1500)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // EmailJS config (replace with your own) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const serviceId = import.meta.env.VITE_EMAILJS_SERVICE_ID; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const templateId = import.meta.env.VITE_EMAILJS_TEMPLATE_ID | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const publicKey = import.meta.env.VITE_EMAILJS_USER_ID; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+31
to
35
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainFix env var name for EmailJS public key and guard missing config. Use VITE_EMAILJS_PUBLIC_KEY (per your PR docs) instead of VITE_EMAILJS_USER_ID. Also bail out early if any config is missing to avoid silent failures. Apply this diff: - const serviceId = import.meta.env.VITE_EMAILJS_SERVICE_ID;
- const templateId = import.meta.env.VITE_EMAILJS_TEMPLATE_ID
- const publicKey = import.meta.env.VITE_EMAILJS_USER_ID;
+ const serviceId = import.meta.env.VITE_EMAILJS_SERVICE_ID;
+ const templateId = import.meta.env.VITE_EMAILJS_TEMPLATE_ID;
+ const publicKey = import.meta.env.VITE_EMAILJS_PUBLIC_KEY;
+
+ if (!serviceId || !templateId || !publicKey) {
+ // Surface a clear signal in dev and prevent the send call
+ console.error("Missing EmailJS configuration (serviceId/templateId/publicKey).");
+ setIsSubmitting(false);
+ return;
+ }Run to find inconsistent usages across the repo (and docs): 🏁 Script executed: #!/bin/bash
rg -nP 'VITE_EMAILJS_(SERVICE_ID|TEMPLATE_ID|PUBLIC_KEY|USER_ID)'Length of output: 285 Fix EmailJS env var and guard missing config Replace the src/pages/Contact/Contact.tsx
@@ -31,3 +31,9 @@
const serviceId = import.meta.env.VITE_EMAILJS_SERVICE_ID;
const templateId = import.meta.env.VITE_EMAILJS_TEMPLATE_ID;
- const publicKey = import.meta.env.VITE_EMAILJS_USER_ID;
+ const publicKey = import.meta.env.VITE_EMAILJS_PUBLIC_KEY;
+
+ if (!serviceId || !templateId || !publicKey) {
+ console.error("Missing EmailJS configuration (serviceId/templateId/publicKey).");
+ setIsSubmitting(false);
+ return;
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsSubmitting(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setShowPopup(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const templateParams = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from_name: nameRef.current?.value || "", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from_email: emailRef.current?.value || "", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| subject: subjectRef.current?.value || "", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: messageRef.current?.value || "", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await emailjs.send(serviceId, templateId, templateParams, publicKey); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setShowPopup(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Optionally clear fields | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (nameRef.current) nameRef.current.value = ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (emailRef.current) emailRef.current.value = ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (subjectRef.current) subjectRef.current.value = ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (messageRef.current) messageRef.current.value = ""; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Optionally handle error (show error popup, etc.) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsSubmitting(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Auto-close popup after 5 seconds | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+43
to
55
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Show user-facing errors and always reset submitting state in finally. Errors are swallowed; users won’t know a send failed. Also prefer finally for resetting the loading flag. Apply this diff: - try {
- await emailjs.send(serviceId, templateId, templateParams, publicKey);
- setShowPopup(true);
- // Optionally clear fields
- if (nameRef.current) nameRef.current.value = "";
- if (emailRef.current) emailRef.current.value = "";
- if (subjectRef.current) subjectRef.current.value = "";
- if (messageRef.current) messageRef.current.value = "";
- } catch (error) {
- // Optionally handle error (show error popup, etc.)
- }
- setIsSubmitting(false);
+ try {
+ await emailjs.send(serviceId, templateId, templateParams, publicKey);
+ setShowPopup(true);
+ // Optionally clear fields
+ if (nameRef.current) nameRef.current.value = "";
+ if (emailRef.current) emailRef.current.value = "";
+ if (subjectRef.current) subjectRef.current.value = "";
+ if (messageRef.current) messageRef.current.value = "";
+ } catch (error) {
+ // Provide a user-visible notification
+ // (see import addition below)
+ toast.error("Failed to send your message. Please try again.");
+ console.error("EmailJS send failed:", error);
+ } finally {
+ setIsSubmitting(false);
+ }Add this import (top of file): +import { toast } from "react-hot-toast";📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setShowPopup(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -37,11 +64,10 @@ function Contact() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`min-h-screen w-screen relative overflow-y-auto ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-gradient-to-br from-slate-900 via-purple-900 to-slate-900" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-gradient-to-br from-indigo-100 via-purple-100 to-indigo-100" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`min-h-screen w-screen relative overflow-y-auto ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-gradient-to-br from-slate-900 via-purple-900 to-slate-900" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-gradient-to-br from-indigo-100 via-purple-100 to-indigo-100" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* Animated background elements */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="absolute inset-0"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -55,9 +81,8 @@ function Contact() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="text-center mb-8 flex-shrink-0"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="flex flex-col sm:flex-row justify-center items-center gap-2 sm:gap-3 mb-4"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`inline-flex items-center justify-center w-14 h-14 sm:w-20 sm:h-20 shadow-2xl transition-transform transform hover:scale-105 overflow-hidden rounded-2xl sm:rounded-3xl ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" ? "bg-white" : "bg-purple-200" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`inline-flex items-center justify-center w-14 h-14 sm:w-20 sm:h-20 shadow-2xl transition-transform transform hover:scale-105 overflow-hidden rounded-2xl sm:rounded-3xl ${mode === "dark" ? "bg-white" : "bg-purple-200" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <img | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| src="/crl-icon.png" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -73,9 +98,8 @@ function Contact() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </h1> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <p | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-sm sm:text-lg max-w-xl md:max-w-2xl mx-auto leading-relaxed ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" ? "text-gray-300" : "text-gray-700" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-sm sm:text-lg max-w-xl md:max-w-2xl mx-auto leading-relaxed ${mode === "dark" ? "text-gray-300" : "text-gray-700" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Get in touch with us to discuss your project tracking needs or | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| report any issues | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -87,16 +111,14 @@ function Contact() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="space-y-4 sm:space-y-6 h-full flex flex-col"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="text-center lg:text-left flex-shrink-0"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <h2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-lg sm:text-2xl font-bold mb-2 sm:mb-3 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" ? "text-white" : "text-gray-800" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-lg sm:text-2xl font-bold mb-2 sm:mb-3 ${mode === "dark" ? "text-white" : "text-gray-800" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Let's Connect | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </h2> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <p | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-xs sm:text-base ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" ? "text-gray-400" : "text-gray-600" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-xs sm:text-base ${mode === "dark" ? "text-gray-400" : "text-gray-600" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| We're here to help you track and manage your GitHub | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| repositories more effectively | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -133,49 +155,44 @@ function Contact() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key={title} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`group p-3 sm:p-5 rounded-xl sm:rounded-2xl backdrop-blur-lg transition-all duration-300 hover:scale-105 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-white/10 border border-white/20 hover:bg-white/20" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-white border border-gray-300 hover:bg-gray-100" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`group p-3 sm:p-5 rounded-xl sm:rounded-2xl backdrop-blur-lg transition-all duration-300 hover:scale-105 ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-white/10 border border-white/20 hover:bg-white/20" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-white border border-gray-300 hover:bg-gray-100" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="flex items-center gap-3 sm:gap-4"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`p-2 sm:p-2.5 rounded-full transition-transform duration-300 group-hover:scale-110 bg-gradient-to-r ${iconBg}`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Icon | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`w-4 h-4 sm:w-5 sm:h-5 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-white" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-800" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`w-4 h-4 sm:w-5 sm:h-5 ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-white" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-800" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <h3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-sm sm:text-base font-semibold ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-white" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-800" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-sm sm:text-base font-semibold ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-white" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-800" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {title} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </h3> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <p | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-xs sm:text-sm ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-gray-300" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-600" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-xs sm:text-sm ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-gray-300" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-600" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {detail} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <p | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-xs ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-gray-400" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-500" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-xs ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-gray-400" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-500" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {sub} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </p> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -189,16 +206,14 @@ function Contact() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* Contact Form */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`p-4 sm:p-6 rounded-xl sm:rounded-3xl shadow-2xl h-full flex flex-col backdrop-blur-lg ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-white/10 border border-white/20" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-white border border-gray-300" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`p-4 sm:p-6 rounded-xl sm:rounded-3xl shadow-2xl h-full flex flex-col backdrop-blur-lg ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-white/10 border border-white/20" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-white border border-gray-300" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <h2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-base sm:text-xl font-bold mb-4 text-center flex-shrink-0 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" ? "text-white" : "text-gray-800" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`text-base sm:text-xl font-bold mb-4 text-center flex-shrink-0 ${mode === "dark" ? "text-white" : "text-gray-800" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Send us a Message | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </h2> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -208,68 +223,65 @@ function Contact() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* Full Name */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <label | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`block text-xs font-medium mb-1 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-gray-300" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-700" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`block text-xs font-medium mb-1 ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-gray-300" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-700" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Full Name | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <input | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type="text" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| placeholder="Enter your full name" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| required | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`w-full p-2 sm:p-3 rounded-lg sm:rounded-xl text-sm sm:text-base transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-purple-500 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-white/5 border border-white/20 text-white placeholder-gray-400" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-gray-50 border border-gray-300 text-gray-800 placeholder-gray-500" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ref={nameRef} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`w-full p-2 sm:p-3 rounded-lg sm:rounded-xl text-sm sm:text-base transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-purple-500 ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-white/5 border border-white/20 text-white placeholder-gray-400" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-gray-50 border border-gray-300 text-gray-800 placeholder-gray-500" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* Email */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <label | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`block text-xs font-medium mb-1 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-gray-300" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-700" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`block text-xs font-medium mb-1 ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-gray-300" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-700" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Email Address | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <input | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type="email" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| placeholder="your.email@example.com" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| required | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`w-full p-2 sm:p-3 rounded-lg sm:rounded-xl text-sm sm:text-base transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-purple-500 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-white/5 border border-white/20 text-white placeholder-gray-400" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-gray-50 border border-gray-300 text-gray-800 placeholder-gray-500" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ref={emailRef} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`w-full p-2 sm:p-3 rounded-lg sm:rounded-xl text-sm sm:text-base transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-purple-500 ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-white/5 border border-white/20 text-white placeholder-gray-400" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-gray-50 border border-gray-300 text-gray-800 placeholder-gray-500" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* Subject */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <label | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`block text-xs font-medium mb-1 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-gray-300" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-700" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`block text-xs font-medium mb-1 ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-gray-300" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-700" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Subject | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <select | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`w-full p-2 sm:p-3 rounded-lg sm:rounded-xl text-sm sm:text-base transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-purple-500 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-white/5 border border-white/20 text-white placeholder-gray-400" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-gray-50 border border-gray-300 text-gray-800 placeholder-gray-500" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`w-full p-2 sm:p-3 rounded-lg sm:rounded-xl text-sm sm:text-base transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-purple-500 ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-white/5 border border-white/20 text-white placeholder-gray-400" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-gray-50 border border-gray-300 text-gray-800 placeholder-gray-500" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| required | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defaultValue="" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ref={subjectRef} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <option value="" disabled> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Select a subject | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -284,33 +296,32 @@ function Contact() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* Message */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="relative"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <label | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`block text-xs font-medium mb-1 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-gray-300" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-700" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`block text-xs font-medium mb-1 ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "text-gray-300" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "text-gray-700" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Message | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </label> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <textarea | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| placeholder="Type your message here..." | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| required | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rows={4} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`w-full p-2 sm:p-3 rounded-lg sm:rounded-xl text-sm sm:text-base resize-none transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-purple-500 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-white/5 border border-white/20 text-white placeholder-gray-400" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-gray-50 border border-gray-300 text-gray-800 placeholder-gray-500" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ref={messageRef} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`w-full p-2 sm:p-3 rounded-lg sm:rounded-xl text-sm sm:text-base resize-none transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-purple-500 ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-white/5 border border-white/20 text-white placeholder-gray-400" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-gray-50 border border-gray-300 text-gray-800 placeholder-gray-500" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ></textarea> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={handleSubmit} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disabled={isSubmitting} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`absolute bottom-2 sm:bottom-3 right-2 sm:right-3 flex items-center gap-1.5 sm:gap-2 rounded-full px-3 sm:px-4 py-1.5 sm:py-2 text-xs sm:text-sm font-semibold transition-all duration-300 hover:scale-105 focus:outline-none focus:ring-2 focus:ring-purple-500 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isSubmitting | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-purple-400 cursor-wait text-white" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-purple-600 hover:bg-purple-700 text-white" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`absolute bottom-2 sm:bottom-3 right-2 sm:right-3 flex items-center gap-1.5 sm:gap-2 rounded-full px-3 sm:px-4 py-1.5 sm:py-2 text-xs sm:text-sm font-semibold transition-all duration-300 hover:scale-105 focus:outline-none focus:ring-2 focus:ring-purple-500 ${isSubmitting | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-purple-400 cursor-wait text-white" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-purple-600 hover:bg-purple-700 text-white" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {isSubmitting ? "Sending..." : "Send"} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Send className="w-4 h-4" /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -325,11 +336,10 @@ function Contact() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* Success Popup */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {showPopup && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`fixed top-4 sm:top-6 left-1/2 transform -translate-x-1/2 z-50 w-[90%] sm:w-auto max-w-sm sm:max-w-md px-4 sm:px-6 py-3 sm:py-4 rounded-xl sm:rounded-2xl shadow-lg flex items-center gap-3 sm:gap-4 ${ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-green-900 border border-green-700 text-green-100" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-green-100 border border-green-400 text-green-900" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className={`fixed top-4 sm:top-6 left-1/2 transform -translate-x-1/2 z-50 w-[90%] sm:w-auto max-w-sm sm:max-w-md px-4 sm:px-6 py-3 sm:py-4 rounded-xl sm:rounded-2xl shadow-lg flex items-center gap-3 sm:gap-4 ${mode === "dark" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? "bg-green-900 border border-green-700 text-green-100" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : "bg-green-100 border border-green-400 text-green-900" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <CheckCircle className="w-6 h-6 sm:w-7 sm:h-7" /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div className="flex-1 text-xs sm:text-sm font-semibold"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Inputs are uncontrolled; Issue #203 requests controlled components.
The linked issue explicitly calls for useState-managed, controlled inputs with validation. Consider switching refs to state for consistency and easier validation UX.
Example (sketch, not a full diff):
If you want, I can generate a complete patch converting all four fields.
Also applies to: 234-242, 259-263, 278-285, 311-315, 36-41, 47-51
🤖 Prompt for AI Agents