Skip to content

Commit

Permalink
ft(#630): Implement the contact us page
Browse files Browse the repository at this point in the history
  • Loading branch information
Oliviier-dev committed Nov 19, 2024
1 parent 4e1afad commit b3b9714
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 1 deletion.
12 changes: 12 additions & 0 deletions src/Mutations/contactUs.mutation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { gql } from '@apollo/client';

export const SEND_MESSAGE_MUTATION = gql`
mutation sendMessage(
$name: String!
$email: String!
$phone: String
$message: String!
) {
sendMessage(name: $name, email: $email, phone: $phone, message: $message)
}
`;
4 changes: 3 additions & 1 deletion src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ function Footer({ styles }: any) {
<h3 className="font-bold mb-2">{t('Dev Pulse')}</h3>
<ul>
<li className="mb-1">{t('About us')}</li>
<li className="mb-1">{t('Contact us')}</li>
<li className="mb-1">
<Link to="/contact-us">{t('Contact us')} </Link>
</li>
</ul>
</div>
<div className="w-full sm:w-1/2 md:w-1/4 p-4 text-center lg:text-left">
Expand Down
9 changes: 9 additions & 0 deletions src/containers/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const About = React.lazy(() => import('../pages/Comingsoon'));
const Community = React.lazy(() => import('../pages/Community'));
/* istanbul ignore next */
const Product = React.lazy(() => import('../pages/Comingsoon'));
const ContactUs = React.lazy(() => import('../pages/ContactUs'));
/* istanbul ignore next */
const SignupOrgDocs = React.lazy(
() => import('../components/Docs/SignupOrgDocs'),
Expand Down Expand Up @@ -162,6 +163,14 @@ function MainRoutes() {
</Suspense>
}
/>
<Route
path="/contact-us"
element={
<Suspense fallback={<Skeleton />}>
<ContactUs />
</Suspense>
}
/>
<Route path="/docs/org-signup" element={<SignupOrgDocs />} />
<Route path="/docs/org-signin" element={<SigninOrgDocs />} />
<Route
Expand Down
194 changes: 194 additions & 0 deletions src/pages/ContactUs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import React, { useState } from 'react';
import { toast } from 'react-toastify';
import { useMutation } from '@apollo/client';
import { SEND_MESSAGE_MUTATION } from '../Mutations/contactUs.mutation';

interface FormData {
name: string;
email: string;
phone: string;
message: string;
}

export default function ContactUs() {
const [formData, setFormData] = useState<FormData>({
name: '',
email: '',
phone: '',
message: '',
});
const [sendMessage, { loading, error }] = useMutation(SEND_MESSAGE_MUTATION);

const [errors, setErrors] = useState<{ [key: string]: string }>({});

// Handle form input changes
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
const { name, value } = e.target;
setFormData({
...formData,
[name]: value,
});

if (errors[name]) {
setErrors({
...errors,
[name]: '',
});
}
};

// Validation function
const validateForm = () => {
const newErrors: { [key: string]: string } = {};

if (!formData.name) {
newErrors.name = 'Name is required';
}

// Email validation with regex
const emailPattern = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i;
if (!formData.email) {
newErrors.email = 'Email is required';
} else if (!emailPattern.test(formData.email)) {
newErrors.email = 'Invalid email address';
}

if (!formData.message) {
newErrors.message = 'Message is required';
}

setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};

// Handle form submission
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();

if (!validateForm()) {
return;
}

try {
const { data } = await sendMessage({
variables: {
name: formData.name,
email: formData.email,
phone: formData.phone,
message: formData.message,
},
});
toast.success('Your message has been sent successfully!');
setFormData({ name: '', email: '', phone: '', message: '' });
} catch (err) {
toast.error('Error submitting the form, Try again');
}
};

return (
<div className="flex items-center justify-center min-h-screen bg-gray-100 dark:bg-gray-800">
<div className="w-full max-w-lg p-6 rounded-lg shadow-none xmd:shadow-lg dark:bg-gray-800 xmd:dark:bg-gray-900 bg-gray-100 xmd:bg-white">
<h2 className="text-center text-3xl font-bold text-gray-900 dark:text-white mb-4">
Contact Us
</h2>
<p className="text-center text-gray-600 dark:text-gray-300 mb-6">
We would love to hear from you. Please fill out the form below to get
in touch.
</p>

<form onSubmit={handleSubmit} className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="flex flex-col">
<label
htmlFor="name"
className="text-gray-700 dark:text-gray-300 font-semibold"
>
Name <span className="text-red-500">*</span>
</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
className="mt-2 p-2 border rounded-md border-gray-300 dark:text-black dark:border-gray-600"
/>
{errors.name && (
<small className="text-red-600">{errors.name}</small>
)}
</div>

<div className="flex flex-col">
<label
htmlFor="email"
className="text-gray-700 dark:text-gray-300 font-semibold"
>
Email <span className="text-red-500">*</span>
</label>
<input
type="text"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
className="mt-2 p-2 border rounded-md border-gray-300 dark:text-black dark:border-gray-600"
/>
{errors.email && (
<small className="text-red-600">{errors.email}</small>
)}
</div>
</div>

<div className="flex flex-col">
<label
htmlFor="phone"
className="text-gray-700 dark:text-gray-300 font-semibold"
>
Phone Number
</label>
<input
type="tel"
id="phone"
name="phone"
value={formData.phone}
onChange={handleChange}
className="mt-2 p-2 border rounded-md border-gray-300 dark:text-black dark:border-gray-600"
/>
</div>

<div className="flex flex-col">
<label
htmlFor="message"
className="text-gray-700 dark:text-gray-300 font-semibold"
>
Message <span className="text-red-500">*</span>
</label>
<textarea
id="message"
name="message"
value={formData.message}
onChange={handleChange}
className="mt-2 p-2 border rounded-md border-gray-300 dark:text-black dark:border-gray-600"
rows={4}
/>
{errors.message && (
<small className="text-red-600">{errors.message}</small>
)}
</div>

<div className="text-center">
<button
type="submit"
disabled={loading}
className="w-full mt-4 py-2 bg-primary text-white font-semibold rounded-lg focus:outline-none"
>
{loading ? 'Submitting...' : 'Submit'}
</button>
</div>
</form>
</div>
</div>
);
}

0 comments on commit b3b9714

Please sign in to comment.