2025-06-22 20:49:49 +00:00
|
|
|
|
import React, { useEffect, useState } from "react";
|
|
|
|
|
|
import { useLanguage } from "../context/LanguageContext";
|
2025-07-28 20:20:06 +00:00
|
|
|
|
import { demoService } from "../services/demo.service";
|
2025-06-22 20:49:49 +00:00
|
|
|
|
import {
|
|
|
|
|
|
Building2,
|
|
|
|
|
|
User,
|
|
|
|
|
|
Mail,
|
|
|
|
|
|
Phone,
|
|
|
|
|
|
MapPin,
|
|
|
|
|
|
Users,
|
|
|
|
|
|
MessageSquare,
|
|
|
|
|
|
Send,
|
|
|
|
|
|
CheckCircle,
|
|
|
|
|
|
} from "lucide-react";
|
|
|
|
|
|
|
|
|
|
|
|
interface DemoModalProps {
|
|
|
|
|
|
isOpen: boolean;
|
|
|
|
|
|
onClose: () => void;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface FormData {
|
|
|
|
|
|
organizationName: string;
|
|
|
|
|
|
fullName: string;
|
|
|
|
|
|
email: string;
|
|
|
|
|
|
phone: string;
|
|
|
|
|
|
address: string;
|
|
|
|
|
|
numberOfBranches: string;
|
|
|
|
|
|
numberOfUsers: string;
|
|
|
|
|
|
message: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const Demo: React.FC<DemoModalProps> = ({ isOpen, onClose }) => {
|
|
|
|
|
|
const { t } = useLanguage();
|
|
|
|
|
|
|
|
|
|
|
|
const [formData, setFormData] = useState<FormData>({
|
|
|
|
|
|
organizationName: "",
|
|
|
|
|
|
fullName: "",
|
|
|
|
|
|
email: "",
|
|
|
|
|
|
phone: "",
|
|
|
|
|
|
address: "",
|
|
|
|
|
|
numberOfBranches: "",
|
|
|
|
|
|
numberOfUsers: "",
|
|
|
|
|
|
message: "",
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const [errors, setErrors] = useState<Partial<FormData>>({});
|
|
|
|
|
|
const [isSubmitted, setIsSubmitted] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
const handleInputChange = (
|
|
|
|
|
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
|
|
|
|
|
) => {
|
|
|
|
|
|
const { name, value } = e.target;
|
|
|
|
|
|
setFormData((prev) => ({
|
|
|
|
|
|
...prev,
|
|
|
|
|
|
[name]: value,
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
if (errors[name as keyof FormData]) {
|
|
|
|
|
|
setErrors((prev) => ({
|
|
|
|
|
|
...prev,
|
|
|
|
|
|
[name]: "",
|
|
|
|
|
|
}));
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const validateForm = (): boolean => {
|
|
|
|
|
|
const newErrors: Partial<FormData> = {};
|
|
|
|
|
|
|
|
|
|
|
|
if (!formData.organizationName.trim())
|
|
|
|
|
|
newErrors.organizationName = "Organization name is required";
|
|
|
|
|
|
if (!formData.fullName.trim()) newErrors.fullName = "Full name is required";
|
|
|
|
|
|
if (!formData.email.trim()) {
|
|
|
|
|
|
newErrors.email = "Email is required";
|
|
|
|
|
|
} else if (!/\S+@\S+\.\S+/.test(formData.email)) {
|
|
|
|
|
|
newErrors.email = "Please enter a valid email";
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!formData.phone.trim()) newErrors.phone = "Phone number is required";
|
|
|
|
|
|
if (!formData.address.trim()) newErrors.address = "Address is required";
|
|
|
|
|
|
if (!formData.numberOfBranches.trim())
|
|
|
|
|
|
newErrors.numberOfBranches = "Number of branches is required";
|
|
|
|
|
|
if (!formData.numberOfUsers.trim())
|
|
|
|
|
|
newErrors.numberOfUsers = "Number of users is required";
|
|
|
|
|
|
if (!formData.message.trim()) newErrors.message = "Message is required";
|
|
|
|
|
|
|
|
|
|
|
|
setErrors(newErrors);
|
|
|
|
|
|
return Object.keys(newErrors).length === 0;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
|
|
|
|
if (!validateForm()) return;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
await demoService.createDemoForm(formData);
|
|
|
|
|
|
setIsSubmitted(true);
|
|
|
|
|
|
onClose(); // modal'ı otomatik kapat
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error("Gönderim hatası:", error);
|
|
|
|
|
|
alert("Sunucuya ulaşılamıyor.");
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
|
|
|
|
if (e.key === "Escape") {
|
|
|
|
|
|
onClose();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (isOpen) {
|
|
|
|
|
|
window.addEventListener("keydown", handleKeyDown);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
|
window.removeEventListener("keydown", handleKeyDown);
|
|
|
|
|
|
};
|
|
|
|
|
|
}, [isOpen, onClose]);
|
|
|
|
|
|
|
|
|
|
|
|
// 🎉 Gönderim sonrası teşekkür ekranı
|
|
|
|
|
|
if (isSubmitted) {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto py-5 z-50">
|
|
|
|
|
|
<div className="mx-auto bg-white rounded-xl shadow-lg max-w-md w-full relative">
|
|
|
|
|
|
<div className="max-w-md w-full bg-gradient-to-br from-blue-50 to-indigo-100 rounded-3xl p-8 text-center border border-blue-200 shadow-xl">
|
|
|
|
|
|
{/* Kapat Butonu */}
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={() => setIsSubmitted(false)}
|
|
|
|
|
|
className="absolute top-4 right-4 text-gray-500 hover:text-gray-800 text-2xl"
|
|
|
|
|
|
>
|
|
|
|
|
|
×
|
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="w-16 h-16 bg-green-500 rounded-full flex items-center justify-center mx-auto mb-6">
|
|
|
|
|
|
<CheckCircle className="w-8 h-8 text-white" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<h2 className="text-2xl font-bold text-gray-800 mb-4">
|
|
|
|
|
|
Teşekkürler!
|
|
|
|
|
|
</h2>
|
|
|
|
|
|
<p className="text-gray-600 mb-6">
|
|
|
|
|
|
Demo talebiniz başarıyla gönderildi. 24 saat içinde size geri
|
|
|
|
|
|
dönüş yapacağız.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
setIsSubmitted(false);
|
|
|
|
|
|
setFormData({
|
|
|
|
|
|
organizationName: "",
|
|
|
|
|
|
fullName: "",
|
|
|
|
|
|
email: "",
|
|
|
|
|
|
phone: "",
|
|
|
|
|
|
address: "",
|
|
|
|
|
|
numberOfBranches: "",
|
|
|
|
|
|
numberOfUsers: "",
|
|
|
|
|
|
message: "",
|
|
|
|
|
|
});
|
|
|
|
|
|
}}
|
|
|
|
|
|
className="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white rounded-xl transition-all duration-300"
|
|
|
|
|
|
>
|
|
|
|
|
|
Yeni Talep Gönder
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Modal kapalıysa render etme
|
|
|
|
|
|
if (!isOpen) return null;
|
|
|
|
|
|
|
|
|
|
|
|
// 🎯 Normal form ekranı
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto py-5 z-50">
|
|
|
|
|
|
<div className="mx-auto bg-white rounded-xl shadow-lg max-w-2xl w-full relative">
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
|
className="absolute top-4 right-4 text-gray-500 hover:text-gray-800 text-2xl"
|
|
|
|
|
|
>
|
|
|
|
|
|
×
|
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
|
|
<form
|
|
|
|
|
|
onSubmit={handleSubmit}
|
|
|
|
|
|
className="bg-white rounded-3xl p-6 lg:p-8 shadow-xl border border-gray-100"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div className="space-y-3">
|
|
|
|
|
|
{/* Organization Name */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-gray-700 text-sm font-medium mb-2">
|
|
|
|
|
|
{t('common.company')} *
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<div className="relative">
|
|
|
|
|
|
<Building2 className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
autoFocus
|
|
|
|
|
|
name="organizationName"
|
|
|
|
|
|
value={formData.organizationName}
|
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
|
className={`w-full pl-11 pr-4 py-2.5 bg-gray-50 border ${
|
|
|
|
|
|
errors.organizationName
|
|
|
|
|
|
? "border-red-500 focus:border-red-500 focus:ring-red-500/20"
|
|
|
|
|
|
: "border-gray-200 focus:border-blue-500 focus:ring-blue-500/20"
|
|
|
|
|
|
} rounded-xl text-gray-800 placeholder-gray-500 focus:outline-none transition-all duration-300`}
|
|
|
|
|
|
placeholder={t('demo.organizationName')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Full Name */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-gray-700 text-sm font-medium mb-2">
|
|
|
|
|
|
{t('common.fullName')} *
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<div className="relative">
|
|
|
|
|
|
<User className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
name="fullName"
|
|
|
|
|
|
value={formData.fullName}
|
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
|
className={`w-full pl-11 pr-4 py-2.5 bg-gray-50 border ${
|
|
|
|
|
|
errors.fullName
|
|
|
|
|
|
? "border-red-500 focus:border-red-500 focus:ring-red-500/20"
|
|
|
|
|
|
: "border-gray-200 focus:border-blue-500 focus:ring-blue-500/20"
|
|
|
|
|
|
} rounded-xl text-gray-800 placeholder-gray-500 focus:outline-none transition-all duration-300`}
|
|
|
|
|
|
placeholder={t('demo.fullName')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Email & Phone Row */}
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-gray-700 text-sm font-medium mb-2">
|
|
|
|
|
|
{t('common.email')} *
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<div className="relative">
|
|
|
|
|
|
<Mail className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="email"
|
|
|
|
|
|
name="email"
|
|
|
|
|
|
value={formData.email}
|
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
|
className={`w-full pl-11 pr-4 py-2.5 bg-gray-50 border ${
|
|
|
|
|
|
errors.email
|
|
|
|
|
|
? "border-red-500 focus:border-red-500 focus:ring-red-500/20"
|
|
|
|
|
|
: "border-gray-200 focus:border-blue-500 focus:ring-blue-500/20"
|
|
|
|
|
|
} rounded-xl text-gray-800 placeholder-gray-500 focus:outline-none transition-all duration-300`}
|
|
|
|
|
|
placeholder={t('demo.email')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-gray-700 text-sm font-medium mb-2">
|
|
|
|
|
|
{t('common.phone')} *
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<div className="relative">
|
|
|
|
|
|
<Phone className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="tel"
|
|
|
|
|
|
name="phone"
|
|
|
|
|
|
value={formData.phone}
|
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
|
className={`w-full pl-11 pr-4 py-2.5 bg-gray-50 border ${
|
|
|
|
|
|
errors.phone
|
|
|
|
|
|
? "border-red-500 focus:border-red-500 focus:ring-red-500/20"
|
|
|
|
|
|
: "border-gray-200 focus:border-blue-500 focus:ring-blue-500/20"
|
|
|
|
|
|
} rounded-xl text-gray-800 placeholder-gray-500 focus:outline-none transition-all duration-300`}
|
|
|
|
|
|
placeholder={t('demo.phone')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Address */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-gray-700 text-sm font-medium mb-2">
|
|
|
|
|
|
{t('common.address')} *
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<div className="relative">
|
|
|
|
|
|
<MapPin className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
name="address"
|
|
|
|
|
|
value={formData.address}
|
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
|
className={`w-full pl-11 pr-4 py-2.5 bg-gray-50 border ${
|
|
|
|
|
|
errors.address
|
|
|
|
|
|
? "border-red-500 focus:border-red-500 focus:ring-red-500/20"
|
|
|
|
|
|
: "border-gray-200 focus:border-blue-500 focus:ring-blue-500/20"
|
|
|
|
|
|
} rounded-xl text-gray-800 placeholder-gray-500 focus:outline-none transition-all duration-300`}
|
|
|
|
|
|
placeholder={t('demo.address')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Branches & Users Row */}
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-gray-700 text-sm font-medium mb-2">
|
|
|
|
|
|
{t('common.branchCount')} *
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<div className="relative">
|
|
|
|
|
|
<Building2 className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
name="numberOfBranches"
|
|
|
|
|
|
value={formData.numberOfBranches}
|
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
|
className={`w-full pl-11 pr-4 py-2.5 bg-gray-50 border ${
|
|
|
|
|
|
errors.numberOfBranches
|
|
|
|
|
|
? "border-red-500 focus:border-red-500 focus:ring-red-500/20"
|
|
|
|
|
|
: "border-gray-200 focus:border-blue-500 focus:ring-blue-500/20"
|
|
|
|
|
|
} rounded-xl text-gray-800 placeholder-gray-500 focus:outline-none transition-all duration-300`}
|
|
|
|
|
|
placeholder={t('demo.branches')}
|
|
|
|
|
|
min="1"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-gray-700 text-sm font-medium mb-2">
|
|
|
|
|
|
{t('common.userCount')} *
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<div className="relative">
|
|
|
|
|
|
<Users className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
name="numberOfUsers"
|
|
|
|
|
|
value={formData.numberOfUsers}
|
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
|
className={`w-full pl-11 pr-4 py-2.5 bg-gray-50 border ${
|
|
|
|
|
|
errors.numberOfUsers
|
|
|
|
|
|
? "border-red-500 focus:border-red-500 focus:ring-red-500/20"
|
|
|
|
|
|
: "border-gray-200 focus:border-blue-500 focus:ring-blue-500/20"
|
|
|
|
|
|
} rounded-xl text-gray-800 placeholder-gray-500 focus:outline-none transition-all duration-300`}
|
|
|
|
|
|
placeholder={t('demo.users')}
|
|
|
|
|
|
min="1"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Message */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-gray-700 text-sm font-medium mb-2">
|
|
|
|
|
|
{t('common.message')} *
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<div className="relative">
|
|
|
|
|
|
<MessageSquare className="absolute left-3 top-3 w-5 h-5 text-gray-400" />
|
|
|
|
|
|
<textarea
|
|
|
|
|
|
name="message"
|
|
|
|
|
|
value={formData.message}
|
|
|
|
|
|
onChange={handleInputChange}
|
|
|
|
|
|
rows={4}
|
|
|
|
|
|
className={`w-full pl-11 pr-4 py-2.5 bg-gray-50 border ${
|
|
|
|
|
|
errors.message
|
|
|
|
|
|
? "border-red-500 focus:border-red-500 focus:ring-red-500/20"
|
|
|
|
|
|
: "border-gray-200 focus:border-blue-500 focus:ring-blue-500/20"
|
|
|
|
|
|
} rounded-xl text-gray-800 placeholder-gray-500 focus:outline-none transition-all duration-300 resize-none`}
|
|
|
|
|
|
placeholder={t('demo.message')}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Submit Button */}
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="submit"
|
|
|
|
|
|
className="w-full bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white font-semibold py-4 px-6 rounded-xl transition-all duration-300 transform hover:scale-[1.02] hover:shadow-lg flex items-center justify-center gap-2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<Send className="w-5 h-5" />
|
|
|
|
|
|
{t('demo.send')}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export default Demo;
|