473 lines
21 KiB
TypeScript
473 lines
21 KiB
TypeScript
"use client";
|
||
import React, { useEffect, useState } from 'react';
|
||
import { createPortal } from 'react-dom';
|
||
import ReCAPTCHA from "react-google-recaptcha";
|
||
import axios from "axios";
|
||
|
||
interface ContactPopupProps {
|
||
isOpen: boolean;
|
||
onClose: () => void;
|
||
}
|
||
|
||
const ContactPopup: React.FC<ContactPopupProps> = ({ isOpen, onClose }) => {
|
||
const [formData, setFormData] = useState({
|
||
name: "",
|
||
phone: "",
|
||
email: "",
|
||
businessName: "",
|
||
projectRequirement: "",
|
||
budgetRange: "",
|
||
});
|
||
|
||
const [formErrors, setFormErrors] = useState<any>({});
|
||
const [captchaToken, setCaptchaToken] = useState<string | null>(null);
|
||
const [alert, setAlert] = useState({ show: false, type: "", message: "" });
|
||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||
const [mounted, setMounted] = useState(false);
|
||
|
||
useEffect(() => {
|
||
setMounted(true);
|
||
}, []);
|
||
|
||
// Close on ESC key
|
||
useEffect(() => {
|
||
const handleEsc = (e: KeyboardEvent) => {
|
||
if (e.key === 'Escape') onClose();
|
||
};
|
||
window.addEventListener('keydown', handleEsc);
|
||
return () => window.removeEventListener('keydown', handleEsc);
|
||
}, [onClose]);
|
||
|
||
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
|
||
const { name, value } = e.target;
|
||
setFormData((prev) => ({ ...prev, [name]: value }));
|
||
};
|
||
|
||
const handleCaptchaChange = (token: string | null) => {
|
||
setCaptchaToken(token);
|
||
};
|
||
|
||
const handleSubmit = async (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
|
||
const errors: any = {};
|
||
if (!formData.name.trim()) errors.name = "Name is required.";
|
||
if (!formData.phone.trim()) errors.phone = "Phone is required.";
|
||
if (!formData.email.trim()) errors.email = "Email is required.";
|
||
if (!formData.businessName.trim()) errors.businessName = "Business name requested.";
|
||
if (!formData.projectRequirement.trim()) errors.projectRequirement = "Requirement details needed.";
|
||
if (!formData.budgetRange) errors.budgetRange = "Please select a budget range.";
|
||
// if (!captchaToken) errors.captcha = "Please verify the CAPTCHA.";
|
||
|
||
setFormErrors(errors);
|
||
if (Object.keys(errors).length > 0) return;
|
||
|
||
setIsSubmitting(true);
|
||
|
||
const emailData = {
|
||
...formData,
|
||
message: `Business: ${formData.businessName}<br />Budget: ${formData.budgetRange}<br /><br />Requirement: ${formData.projectRequirement}`,
|
||
to: "selvipalanikumarn@gmail.com",
|
||
senderName: "Metatroncube Contact Popup",
|
||
recaptchaToken: captchaToken,
|
||
};
|
||
|
||
try {
|
||
const res = await axios.post("https://mailserver.metatronnest.com/send", emailData, {
|
||
headers: { "Content-Type": "application/json" },
|
||
});
|
||
|
||
setAlert({
|
||
show: true,
|
||
type: "success",
|
||
message: res?.data?.message || "Message sent successfully!",
|
||
});
|
||
|
||
setFormData({
|
||
name: "",
|
||
phone: "",
|
||
email: "",
|
||
businessName: "",
|
||
projectRequirement: "",
|
||
budgetRange: "",
|
||
});
|
||
setCaptchaToken(null);
|
||
setFormErrors({});
|
||
// Close after delay
|
||
setTimeout(onClose, 2000);
|
||
} catch (error) {
|
||
console.error("❌ Error sending email:", error);
|
||
setAlert({
|
||
show: true,
|
||
type: "danger",
|
||
message: "Failed to send message. Please try again later.",
|
||
});
|
||
} finally {
|
||
setIsSubmitting(false);
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
if (alert.show) {
|
||
const timer = setTimeout(() => {
|
||
setAlert((prev) => ({ ...prev, show: false }));
|
||
}, 5000);
|
||
return () => clearTimeout(timer);
|
||
}
|
||
}, [alert.show]);
|
||
|
||
if (!mounted || !isOpen) return null;
|
||
|
||
const modalContent = (
|
||
<div className={`contact-popup-overlay ${isOpen ? 'active' : ''}`} onClick={onClose}>
|
||
<div className="contact-popup-content" onClick={(e) => e.stopPropagation()}>
|
||
<div className="row g-0 h-100">
|
||
{/* Left Side: Info */}
|
||
<div className="col-lg-5 info-panel" style={{ color: '#fff', position: 'relative' }}>
|
||
<div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', background: 'linear-gradient(135deg, #1a1f2b 0%, #3779b9 100%)', zIndex: 0 }}></div>
|
||
<div className="info-inner" style={{ position: 'relative', zIndex: 1 }}>
|
||
<h2 className="title">Let’s Discuss Your App Idea</h2>
|
||
<p className="desc">Fill out the form and our team will contact you within 24 hours.</p>
|
||
|
||
<div className="contact-details">
|
||
<div className="detail-item">
|
||
<div className="icon"><i className="fa-solid fa-envelope"></i></div>
|
||
<div className="text">
|
||
<p>Email Us</p>
|
||
<h5>info@metatroncubesolutions.com</h5>
|
||
</div>
|
||
</div>
|
||
<div className="detail-item">
|
||
<div className="icon"><i className="fa-solid fa-phone"></i></div>
|
||
<div className="text">
|
||
<p>Call Us Free</p>
|
||
<h5><a href="tel:+16476797651" style={{ color: 'inherit', textDecoration: 'none' }}>+1-647-679-7651</a></h5>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="social-links">
|
||
<a href="https://www.facebook.com/metatroncubecanada" target="_blank" rel="noopener noreferrer" className="social-icon"><i className="fa-brands fa-facebook-f"></i></a>
|
||
<a href="https://x.com/MetatroncubeDA" target="_blank" rel="noopener noreferrer" className="social-icon"><i className="fa-brands fa-x-twitter"></i></a>
|
||
<a href="https://www.linkedin.com/company/metatroncube-software-solutions/posts/?feedView=all" target="_blank" rel="noopener noreferrer" className="social-icon"><i className="fa-brands fa-linkedin-in"></i></a>
|
||
<a href="https://www.instagram.com/metatron_digitalagency" target="_blank" rel="noopener noreferrer" className="social-icon"><i className="fa-brands fa-instagram"></i></a>
|
||
<a href="https://www.youtube.com/@metatron_digitalagency" target="_blank" rel="noopener noreferrer" className="social-icon"><i className="fa-brands fa-youtube"></i></a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Right Side: Form */}
|
||
<div className="col-lg-7 form-panel">
|
||
<button onClick={onClose} className="close-btn">
|
||
<i className="fa-solid fa-xmark"></i>
|
||
</button>
|
||
|
||
<h3 className="form-title">Start Your Project</h3>
|
||
|
||
{alert.show && (
|
||
<div className={`alert alert-${alert.type === 'danger' ? 'danger' : 'success'} mb-4`}>
|
||
{alert.message}
|
||
</div>
|
||
)}
|
||
|
||
<form className="contact-form" onSubmit={handleSubmit}>
|
||
<div className="row g-3">
|
||
<div className="col-md-6">
|
||
<input type="text" name="name" placeholder="Full Name" value={formData.name} onChange={handleChange} className="form-input" />
|
||
{formErrors.name && <small className="text-danger">{formErrors.name}</small>}
|
||
</div>
|
||
<div className="col-md-6">
|
||
<input type="email" name="email" placeholder="Email Address" value={formData.email} onChange={handleChange} className="form-input" />
|
||
{formErrors.email && <small className="text-danger">{formErrors.email}</small>}
|
||
</div>
|
||
<div className="col-md-6">
|
||
<input type="text" name="phone" placeholder="Phone Number" value={formData.phone} onChange={handleChange} className="form-input" />
|
||
{formErrors.phone && <small className="text-danger">{formErrors.phone}</small>}
|
||
</div>
|
||
<div className="col-md-6">
|
||
<input type="text" name="businessName" placeholder="Business Name" value={formData.businessName} onChange={handleChange} className="form-input" />
|
||
{formErrors.businessName && <small className="text-danger">{formErrors.businessName}</small>}
|
||
</div>
|
||
<div className="col-12">
|
||
<select name="budgetRange" value={formData.budgetRange} onChange={handleChange} className="form-input form-select">
|
||
<option value="">App Type</option>
|
||
<option value="Android">Android</option>
|
||
<option value=" iOS"> iOS</option>
|
||
<option value="Both">Both</option>
|
||
</select>
|
||
{formErrors.budgetRange && <small className="text-danger">{formErrors.budgetRange}</small>}
|
||
</div>
|
||
<div className="col-12">
|
||
<select name="budgetRange" value={formData.budgetRange} onChange={handleChange} className="form-input form-select">
|
||
<option value="">Select Budget Range</option>
|
||
<option value="$1,000 - $5,000">$1,000 - $5,000</option>
|
||
<option value="$5,000 - $10,000">$5,000 - $10,000</option>
|
||
<option value="$10,000 - $25,000">$10,000 - $25,000</option>
|
||
<option value="$25,000+">$25,000+</option>
|
||
</select>
|
||
{formErrors.budgetRange && <small className="text-danger">{formErrors.budgetRange}</small>}
|
||
</div>
|
||
</div>
|
||
|
||
<textarea
|
||
name="projectRequirement"
|
||
placeholder="Your Project Requirements"
|
||
rows={3}
|
||
value={formData.projectRequirement}
|
||
onChange={handleChange}
|
||
className="form-textarea mt-3"
|
||
></textarea>
|
||
{formErrors.projectRequirement && <small className="text-danger">{formErrors.projectRequirement}</small>}
|
||
|
||
<div className="mt-3 g-recaptcha-container">
|
||
<div className="g-recaptcha">
|
||
<ReCAPTCHA
|
||
sitekey="6LekfpwrAAAAAOTwuP1d2gg-Fv9UEsAjE2gjOQJl"
|
||
onChange={handleCaptchaChange}
|
||
/>
|
||
</div>
|
||
{formErrors.captcha && <small className="text-danger d-block mt-1">{formErrors.captcha}</small>}
|
||
</div>
|
||
|
||
<button type="submit" className="vl-btn1 submit-btn" disabled={isSubmitting}>
|
||
{isSubmitting ? 'Sending...' : 'Submit & Get Free Proposal'} <i className="fa-solid fa-angle-right"></i>
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<style jsx>{`
|
||
.contact-popup-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(2, 6, 11, 0.85);
|
||
backdrop-filter: blur(8px);
|
||
z-index: 9999;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 15px;
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transition: all 0.4s cubic-bezier(0.165, 0.84, 0.44, 1);
|
||
}
|
||
.contact-popup-overlay.active {
|
||
opacity: 1;
|
||
visibility: visible;
|
||
}
|
||
.contact-popup-content {
|
||
background: #fff;
|
||
width: 100%;
|
||
max-width: 1000px;
|
||
max-height: 95vh;
|
||
border-radius: 20px;
|
||
overflow: hidden;
|
||
box-shadow: 0 40px 100px rgba(0,0,0,0.4);
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.info-panel {
|
||
padding: 50px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
}
|
||
.info-inner {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
.title {
|
||
font-size: 28px;
|
||
font-weight: 800;
|
||
margin-bottom: 15px;
|
||
line-height: 1.2;
|
||
}
|
||
.desc {
|
||
font-size: 15px;
|
||
opacity: 0.9;
|
||
line-height: 1.5;
|
||
}
|
||
.contact-details {
|
||
margin-top: 30px;
|
||
margin-bottom: 25px;
|
||
}
|
||
.detail-item {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 15px;
|
||
gap: 12px;
|
||
}
|
||
.icon {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
background: rgba(255,255,255,0.1);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 14px;
|
||
}
|
||
.text p {
|
||
margin: 0;
|
||
opacity: 0.7;
|
||
font-size: 12px;
|
||
}
|
||
.text h5 {
|
||
margin: 0;
|
||
font-size: 15px;
|
||
}
|
||
.social-links {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
.social-icon {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 50%;
|
||
background: rgba(255,255,255,0.1);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #fff;
|
||
transition: 0.3s;
|
||
font-size: 13px;
|
||
}
|
||
.social-icon:hover {
|
||
background: #fff;
|
||
color: #3779b9;
|
||
}
|
||
|
||
.form-panel {
|
||
padding: 40px 50px;
|
||
position: relative;
|
||
background: #fff;
|
||
overflow-y: auto;
|
||
scrollbar-width: thin;
|
||
scrollbar-color: #3779b9 #f1f1f1;
|
||
}
|
||
.form-panel::-webkit-scrollbar { width: 6px; }
|
||
.form-panel::-webkit-scrollbar-track { background: #f1f1f1; }
|
||
.form-panel::-webkit-scrollbar-thumb { background: #3779b9; border-radius: 10px; }
|
||
|
||
.close-btn {
|
||
position: absolute;
|
||
top: 20px;
|
||
right: 20px;
|
||
background: #f3f4f6;
|
||
border: none;
|
||
width: 35px;
|
||
height: 35px;
|
||
border-radius: 50%;
|
||
font-size: 18px;
|
||
cursor: pointer;
|
||
color: #1a1f2b;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.3s;
|
||
z-index: 100;
|
||
}
|
||
.close-btn:hover {
|
||
background: #3779b9;
|
||
color: #fff;
|
||
transform: rotate(90deg);
|
||
}
|
||
.form-title {
|
||
font-size: 24px;
|
||
font-weight: 700;
|
||
margin-bottom: 20px;
|
||
color: #1a1f2b;
|
||
}
|
||
.form-input, .form-textarea, .form-select {
|
||
width: 100%;
|
||
padding: 10px 15px;
|
||
border-radius: 8px;
|
||
border: 1px solid #e2e8f0;
|
||
outline: none;
|
||
background: #f8fafc;
|
||
transition: 0.2s;
|
||
font-size: 13.5px;
|
||
}
|
||
.form-input:focus, .form-textarea:focus, .form-select:focus {
|
||
border-color: #3779b9;
|
||
background: #fff;
|
||
box-shadow: 0 0 0 3px rgba(55,121,185,0.1);
|
||
}
|
||
.form-textarea { resize: none; }
|
||
.submit-btn {
|
||
width: 100%;
|
||
border: none;
|
||
padding: 14px;
|
||
border-radius: 8px;
|
||
margin-top: 15px;
|
||
background: #3779b9;
|
||
color: #fff;
|
||
font-weight: 700;
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
}
|
||
.submit-btn:hover:not(:disabled) {
|
||
background: #1a1f2b;
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
/* Mobile Optimizations */
|
||
@media (max-width: 991px) {
|
||
.info-panel { display: none; }
|
||
.form-panel { padding: 40px 30px; }
|
||
.contact-popup-content { max-width: 550px; }
|
||
}
|
||
|
||
@media (max-width: 575px) {
|
||
.contact-popup-overlay { padding: 10px; }
|
||
.contact-popup-content { border-radius: 15px; }
|
||
.form-panel { padding: 30px 20px; }
|
||
.form-title { font-size: 20px; margin-bottom: 15px; }
|
||
.form-input, .form-textarea, .form-select { font-size: 13px; padding: 8px 12px; }
|
||
|
||
/* Scale ReCAPTCHA for small screens */
|
||
.g-recaptcha {
|
||
transform: scale(0.85);
|
||
-webkit-transform: scale(0.85);
|
||
transform-origin: 0 0;
|
||
-webkit-transform-origin: 0 0;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 375px) {
|
||
.form-panel { padding: 25px 15px; }
|
||
.g-recaptcha {
|
||
transform: scale(0.77);
|
||
-webkit-transform: scale(0.77);
|
||
}
|
||
}
|
||
|
||
@media (max-width: 320px) {
|
||
.form-panel { padding: 15px 10px; }
|
||
.form-title { font-size: 16px; margin-bottom: 8px; }
|
||
.form-input, .form-textarea, .form-select { font-size: 12px; padding: 6px 10px; }
|
||
.submit-btn { padding: 10px; font-size: 12px; margin-top: 10px; }
|
||
.row.g-3 { --bs-gutter-y: 0.5rem; --bs-gutter-x: 0.5rem; }
|
||
.mt-3 { margin-top: 0.5rem !important; }
|
||
.g-recaptcha {
|
||
transform: scale(0.68);
|
||
-webkit-transform: scale(0.68);
|
||
}
|
||
}
|
||
`}</style>
|
||
</div>
|
||
);
|
||
|
||
return typeof document !== 'undefined'
|
||
? createPortal(modalContent, document.body)
|
||
: null;
|
||
};
|
||
|
||
export default ContactPopup;
|