Newer
Older
My-Portfolio / frontend / src / components / sections / Contact.jsx
//React
import { useState, useEffect, useContext } from "react";

//Framer Motion
import { motion } from "framer-motion";

//API
import { postData } from "../../api";

//Utils
import { LoadingContext } from "../utils/LoadingContext";
import Heading from "../Heading";
import NavigationDots from "../utils/NavigationDots";

//CSS
import styles from "./Contact.module.css";

const Contact = ({ isVisible, contactData }) => {
  const [formData, setFormData] = useState({
    name: "",
    email: "",
    message: "",
  });

  const [error, setError] = useState("");
  const [success, setSuccess] = useState("");
  const { isLoading } = useContext(LoadingContext); // Use the global loading state

  if (isLoading) return <div>Loading...</div>;

  // Automatically clear success/error message after 5 seconds
  useEffect(() => {
    if (success || error) {
      const timer = setTimeout(() => {
        setSuccess("");
        setError("");
      }, 5000);

      return () => clearTimeout(timer); // Cleanup on unmount
    }
  }, [success, error]);

  const handleChange = (e) => {
    setFormData({ ...formData, [e.target.name]: e.target.value });
    setError("");
  };

  const handleSubmit = async (e) => {
    e.preventDefault();

    if (!formData.name || !formData.email || !formData.message) {
      setError("All fields are required.");
      return;
    }

    if (!/\S+@\S+\.\S+/.test(formData.email)) {
      setError("Please enter a valid email.");
      return;
    }

    try {
      const response = await postData("send", formData);
      setSuccess(response.success);
      setFormData({ name: "", email: "", message: "" });
    } catch (error) {
      setError(error.message || "Failed to send message.");
    }
  };

  return (
    <motion.div
      id="contact"
      className="pt-2 sm:pt-10"
      initial={{ opacity: 0, y: 100 }} // Start off-screen
      animate={isVisible ? { opacity: 1, y: 0 } : { opacity: 0, y: 100 }} // Slide-in when visible
      transition={{ duration: 0.2, ease: "easeOut" }}
    >
      <div className="relative rounded-lg z-10 min-h-screen">
        <Heading
          title="Contact Me Anytime!"
          highlightWords={[{ word: "Contact Me", color: "text-orange-500" }]}
        />
        <NavigationDots currentSectionId="contact" />

        <div className="sm:max-w-lg md:max-w-2xl lg:max-w-4xl xl:max-w-6xl 2xl:max-w-full 2xl:px-60 mx-auto px-8">
          {/* Social Media Buttons */}
          <div className="flex justify-center gap-6 lg:gap-12 flex-wrap mb-8">
            {contactData.map((contact) => (
              <a
                key={contact.id}
                href={
                  contact.name === "gmail"
                    ? `mailto:${contact.username}`
                    : contact.url
                }
                target={contact.name === "gmail" ? "_self" : "_blank"}
                rel="noopener noreferrer"
                className={`${styles["social-button"]} flex items-center justify-center gap-2.5`}
              >
                <img
                  src={contact.logo}
                  alt={contact.name}
                  className="w-8 h-8 rounded-full"
                />
                <span className="text-md md:text-base lg:text-lg xl:text-xl font-bold">
                  {contact.username}
                </span>
              </a>
            ))}
          </div>

          <form onSubmit={handleSubmit} className="flex flex-col space-y-4">
            <input
              type="text"
              name="name"
              placeholder="Your Name"
              value={formData.name}
              onChange={handleChange}
              className={`${styles["input-field"]} p-2 rounded-md`}
              required
            />
            <input
              type="email"
              name="email"
              placeholder="Your Email"
              value={formData.email}
              onChange={handleChange}
              className={`${styles["input-field"]} p-2 rounded-md`}
              required
            />
            <textarea
              name="message"
              placeholder="Your Message"
              value={formData.message}
              onChange={handleChange}
              className={`${styles["input-field"]} p-2 rounded-md`}
              rows="4"
              required
            ></textarea>

            {/* Success/Error Message Below Message Field */}
            <div className="h-4 flex items-center">
              {error && <p className="text-red-500 text-sm">{error}</p>}
              {success && <p className="text-green-500 text-sm">{success}</p>}
            </div>

            <div className="flex justify-center">
              <button
                type="submit"
                className={`${styles["submit-button"]} px-4 py-2 rounded-lg`}
              >
                Send Message
              </button>
            </div>
          </form>

          {/* Disclaimer */}
          <p className="text-sm text-gray-400 text-center mt-4">
            Disclaimer: Please avoid sharing sensitive or confidential
            information in your message.
          </p>
        </div>
      </div>

      {/* Rights */}
      <p className="text-md text-gray-400 text-center mt-10">
        @2025 Nuno Teixeira <br />
        All rights reserved
      </p>
    </motion.div>
  );
};

export default Contact;