sozsoft-platform/ui/src/views/public/Demo.tsx

372 lines
14 KiB
TypeScript
Raw Normal View History

2026-02-24 20:44:16 +00:00
import React, { useEffect, useState } from "react";
import {
FaBuilding,
FaUser,
FaEnvelope,
FaPhone,
FaMapPin,
FaUsers,
FaRegComment,
FaPaperPlane,
FaCheckCircle
} from 'react-icons/fa';
import { useLocalization } from "@/utils/hooks/useLocalization";
import { createDemoAsync } from "@/services/demo.service";
import { DemoDto } from "@/proxy/demo/models";
interface DemoModalProps {
isOpen: boolean;
onClose: () => void;
}
const Demo: React.FC<DemoModalProps> = ({ isOpen, onClose }) => {
const { translate } = useLocalization()
const [formData, setFormData] = useState<DemoDto>({
id: crypto.randomUUID(),
organizationName: "",
name: "",
email: "",
phoneNumber: "",
address: "",
numberOfBranches: 0,
numberOfUsers: 0,
message: "",
});
const [errors, setErrors] = useState<Partial<DemoDto>>({});
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 DemoDto]) {
setErrors((prev) => ({
...prev,
[name]: "",
}));
}
};
const validateForm = (): boolean => {
const newErrors: Partial<DemoDto> = {};
if (!formData.organizationName.trim())
newErrors.organizationName = "Organization name is required";
if (!formData.name.trim()) newErrors.name = "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.phoneNumber.trim()) newErrors.phoneNumber = "Phone number is required";
if (!formData.address.trim()) newErrors.address = "Address 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 createDemoAsync(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"
>
&times;
</button>
<div className="w-16 h-16 bg-green-500 rounded-full flex items-center justify-center mx-auto mb-6">
<FaCheckCircle 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({
id: crypto.randomUUID(),
organizationName: "",
name: "",
email: "",
phoneNumber: "",
address: "",
numberOfBranches: 0,
numberOfUsers: 0,
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"
>
&times;
</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">
{translate('::Public.common.company')} *
</label>
<div className="relative">
<FaBuilding 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={translate('::Public.demo.organizationName')}
/>
</div>
</div>
{/* Full Name */}
<div>
<label className="block text-gray-700 text-sm font-medium mb-2">
{translate('::Public.common.fullName')} *
</label>
<div className="relative">
<FaUser 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.name}
onChange={handleInputChange}
className={`w-full pl-11 pr-4 py-2.5 bg-gray-50 border ${
errors.name
? "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={translate('::Public.demo.fullName')}
/>
</div>
</div>
<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">
{translate('::Abp.Account.EmailAddress')} *
</label>
<div className="relative">
<FaEnvelope 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={translate('::Public.demo.email')}
/>
</div>
</div>
<div>
<label className="block text-gray-700 text-sm font-medium mb-2">
{translate('::Abp.Identity.User.UserInformation.PhoneNumber')} *
</label>
<div className="relative">
<FaPhone className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
<input
type="tel"
name="phoneNumber"
value={formData.phoneNumber}
onChange={handleInputChange}
className={`w-full pl-11 pr-4 py-2.5 bg-gray-50 border ${
errors.phoneNumber
? "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={translate('::Public.demo.phoneNumber')}
/>
</div>
</div>
</div>
{/* Address */}
<div>
<label className="block text-gray-700 text-sm font-medium mb-2">
{translate('::App.Address')} *
</label>
<div className="relative">
<FaMapPin 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={translate('::Public.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">
{translate('::Public.common.branchCount')} *
</label>
<div className="relative">
<FaBuilding 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={translate('::Public.demo.branches')}
min="1"
/>
</div>
</div>
<div>
<label className="block text-gray-700 text-sm font-medium mb-2">
{translate('::Public.common.userCount')} *
</label>
<div className="relative">
<FaUsers 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={translate('::Public.demo.users')}
min="1"
/>
</div>
</div>
</div>
{/* Message */}
<div>
<label className="block text-gray-700 text-sm font-medium mb-2">
{translate('::Public.common.message')} *
</label>
<div className="relative">
<FaRegComment 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={translate('::Public.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"
>
<FaPaperPlane className="w-5 h-5" />
{translate('::Public.demo.send')}
</button>
</div>
</form>
</div>
</div>
);
};
export default Demo;