Skip to content
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

Contact Us Mobile #48

Merged
merged 11 commits into from
Mar 25, 2025
182 changes: 182 additions & 0 deletions app/(pages)/_components/ContactForm/ContactForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
"use client";

import { useState } from "react";
import styles from "./ContactForm.module.scss";

export default function ContactForm() {
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [email, setEmail] = useState("");
const [subject, setSubject] = useState("");
const [message, setMessage] = useState("");

// Error handling
const [firstNameError, setFirstNameError] = useState("");
const [lastNameError, setLastNameError] = useState("");
const [emailError, setEmailError] = useState("");
const [subjectError, setSubjectError] = useState("");
const [messageError, setMessageError] = useState("");

// Prevent multiple submissions while loading
const [loading, setLoading] = useState(false);

const handleSubmit = async (e) => {
console.log("submit");
e.preventDefault(); // Prevent automatic page reload

// Prevent multiple submissions while loading
if (loading) return;

setLoading(true);

// Input Validation
let valid = true;

if (!firstName.trim()) {
setFirstNameError("Please provide a first name");
valid = false;
} else {
setFirstNameError("");
}

if (!lastName.trim()) {
setLastNameError("Please provide a last name");
valid = false;
} else {
setLastNameError("");
}

if (!email.trim()) {
setEmailError("Please provide an email");
valid = false;
} else if (!/\S+@\S+\.\S+/.test(email)) {
setEmailError("Please provide a valid email");
valid = false;
} else {
setEmailError("");
}

if (!subject.trim()) {
setSubjectError("Please provide a subject");
valid = false;
} else {
setSubjectError("");
}

if (!message.trim()) {
setMessageError("Please provide a message");
valid = false;
} else {
setMessageError("");
}

if (!valid) {
setLoading(false); // Reset loading state if validation fails
// return;
}

const contactData = {
firstName,
lastName,
email,
subject,
message,
};

// Send to API
try {
const res = await fetch("/api/sendEmail", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(contactData),
});

if (!res.ok) throw new Error("Failed to send email");

const data = await res.json();
alert(data.message || "Email sent successfully!");

// Reset form fields after successful submission
setFirstName("");
setLastName("");
setEmail("");
setSubject("");
setMessage("");
} catch (error) {
alert("Something went wrong. Try again.");
} finally {
setLoading(false);
}
};

return (
<form className={styles.form} onSubmit={handleSubmit}>
<div className={styles.formField}>
<div className={styles.formInput}>
<label>First Name*</label>
<input
type="text"
className={`${styles.formInputText} ${firstNameError && styles.error}`}
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
{firstNameError && (
<p className={styles.errorText}>{firstNameError}</p>
)}
</div>
<div className={styles.formInput}>
<label>Last Name*</label>
<input
type="text"
className={`${styles.formInputText} ${lastNameError && styles.error}`}
value={lastName}
onChange={(e) => setLastName(e.target.value)}
/>
{lastNameError && <p className={styles.errorText}>{lastNameError}</p>}
</div>
</div>
<div className={styles.formField}>
<div className={styles.formInput}>
<label>Email*</label>
<input
type="text"
className={`${styles.formInputText} ${emailError && styles.error}`}
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
{emailError && <p className={styles.errorText}>{emailError}</p>}
</div>
<div className={styles.formInput}>
<label>Subject*</label>
<input
type="text"
className={`${styles.formInputText} ${subjectError && styles.error}`}
value={subject}
onChange={(e) => setSubject(e.target.value)}
/>
{subjectError && <p className={styles.errorText}>{subjectError}</p>}
</div>
</div>
<div className={styles.formMessage}>
<label>Message</label>
<textarea
type="text"
className={`${styles.message} ${messageError && styles.error}`}
placeholder="Type Message Here..."
value={message}
onChange={(e) => setMessage(e.target.value)}
/>
{messageError && <p className={styles.errorText}>{messageError}</p>}
</div>
<div className={styles.buttonArea}>
<button
type="submit"
disabled={loading}
className={`btn ${styles.sendButton}`}
>
Send
</button>
</div>
</form>
);
}
134 changes: 134 additions & 0 deletions app/(pages)/_components/ContactForm/ContactForm.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
@use "@/app/(pages)/_globals/mixins.scss";

.form {
display: flex;
flex-direction: column;
align-items: center;
width: 72.22%;
color: var(--dark-grey);
z-index: 1;

@include mixins.phone {
width: 361px;
}
}

.formField {
display: flex;
justify-content: space-between;
width: 100%;

@include mixins.phone {
flex-direction: column;
justify-content: center;
align-items: center;
// gap: 30px;
}
}

.formInput {
width: 44.92%;
margin-bottom: 20px;
text-align: left;

@include mixins.phone {
width: 100%;
// margin: 0;
}
}

.formInput label {
display: block;
font-size: 1rem;
font-family: var(--font2);
font-weight: 400;
line-height: 150%;
}

.formInputText {
width: 100%;
padding: 12px;
border-radius: 10px;
border: 1px solid var(--dark-grey);
background-color: var(--white);
font-size: 1rem;
color: var(--dark-grey);
transition:
border 0.3s ease,
box-shadow 0.3s ease;
}

.formInputText.error {
border-color: red;
}

.formInputText:focus {
border-color: var(--light-blue);
box-shadow: var(--drop-shadow-small);
outline: none;
}

.formMessage {
width: 100%;
border-radius: var(--card-border-radius);
}

.formMessage label {
display: none;
}

.message {
@include mixins.fontStyle(1rem, 400, 150%, var(--font2));
border-radius: var(--card-border-radius);
border: solid 1px var(--dark-grey);
resize: none;
min-height: 112px;
width: 100%;
padding-top: 12px;
padding-left: 32px;
transition:
border 0.3s ease,
box-shadow 0.3s ease;
}

.message.error {
border-color: red;
}

.message:focus {
border-color: var(--light-blue);
box-shadow: var(--drop-shadow-small);
outline: none;
}

.buttonArea {
display: flex;
flex-direction: row-reverse;
width: 100%;
padding-top: 50px;

@include mixins.phone {
padding-top: 30px;
}
}

.sendButton {
outline: none !important;
border: none !important;
font-weight: var(--bold);
font-family: var(--font2);
width: 6rem;
font-size: 1rem;

@include mixins.phone {
width: 100%;
}
}

/* Error messages */
.errorText {
color: red;
font-size: 0.9rem;
margin-bottom: 0.5rem;
text-align: left;
}
Loading