demo talep formu
This commit is contained in:
parent
f01bcd440c
commit
6d1516eb0f
8 changed files with 505 additions and 265 deletions
|
|
@ -4,19 +4,19 @@ using System.Threading.Tasks;
|
||||||
using Kurs.Platform.Data.Seeds;
|
using Kurs.Platform.Data.Seeds;
|
||||||
using Kurs.Sender.Mail;
|
using Kurs.Sender.Mail;
|
||||||
using Volo.Abp.Settings;
|
using Volo.Abp.Settings;
|
||||||
using Volo.Abp.UI.Navigation.Urls;
|
|
||||||
|
|
||||||
namespace Kurs.Platform.Dashboard;
|
namespace Kurs.Platform.Dashboard;
|
||||||
|
|
||||||
public class ContactFormDto
|
public class ContactFormDto
|
||||||
{
|
{
|
||||||
public string Company { get; set; }
|
public string OrganizationName { get; set; }
|
||||||
public string FullName { get; set; }
|
public string FullName { get; set; }
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
public string Phone { get; set; }
|
public string Phone { get; set; }
|
||||||
public string Address { get; set; }
|
public string Address { get; set; }
|
||||||
public string BranchCount { get; set; }
|
public string NumberOfBranches { get; set; }
|
||||||
public string UserCount { get; set; }
|
public string NumberOfUsers { get; set; }
|
||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,13 +37,13 @@ public class DemoAppService : PlatformAppService
|
||||||
public async Task DemoFormAsync(ContactFormDto input)
|
public async Task DemoFormAsync(ContactFormDto input)
|
||||||
{
|
{
|
||||||
var bodyBuilder = new StringBuilder();
|
var bodyBuilder = new StringBuilder();
|
||||||
bodyBuilder.AppendLine($"Şirket: {input.Company}");
|
bodyBuilder.AppendLine($"Şirket: {input.OrganizationName}");
|
||||||
bodyBuilder.AppendLine($"Ad Soyad: {input.FullName}");
|
bodyBuilder.AppendLine($"Ad Soyad: {input.FullName}");
|
||||||
bodyBuilder.AppendLine($"E-Posta: {input.Email}");
|
bodyBuilder.AppendLine($"E-Posta: {input.Email}");
|
||||||
bodyBuilder.AppendLine($"Telefon: {input.Phone}");
|
bodyBuilder.AppendLine($"Telefon: {input.Phone}");
|
||||||
bodyBuilder.AppendLine($"Adres: {input.Address}");
|
bodyBuilder.AppendLine($"Adres: {input.Address}");
|
||||||
bodyBuilder.AppendLine($"Şube Sayısı: {input.BranchCount}");
|
bodyBuilder.AppendLine($"Şube Sayısı: {input.NumberOfBranches}");
|
||||||
bodyBuilder.AppendLine($"Kullanıcı Sayısı: {input.UserCount}");
|
bodyBuilder.AppendLine($"Kullanıcı Sayısı: {input.NumberOfUsers}");
|
||||||
bodyBuilder.AppendLine($"Mesaj: {input.Message}");
|
bodyBuilder.AppendLine($"Mesaj: {input.Message}");
|
||||||
|
|
||||||
var SenderName = await settingProvider.GetOrNullAsync(SeedConsts.AbpSettings.Mailing.Default.DefaultFromDisplayName);
|
var SenderName = await settingProvider.GetOrNullAsync(SeedConsts.AbpSettings.Mailing.Default.DefaultFromDisplayName);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ import Contact from './pages/Contact';
|
||||||
import BlogDetail from './pages/BlogDetail';
|
import BlogDetail from './pages/BlogDetail';
|
||||||
import NotFound from './pages/NotFound';
|
import NotFound from './pages/NotFound';
|
||||||
import { LanguageProvider } from './context/LanguageContext';
|
import { LanguageProvider } from './context/LanguageContext';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import Demo from './pages/Demo';
|
||||||
|
|
||||||
// Create a client
|
// Create a client
|
||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
|
|
@ -23,11 +25,16 @@ const queryClient = new QueryClient({
|
||||||
});
|
});
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
const [isDemoModalOpen, setIsDemoModalOpen] = useState(false);
|
||||||
|
|
||||||
|
const openDemoModal = () => setIsDemoModalOpen(true);
|
||||||
|
const closeDemoModal = () => setIsDemoModalOpen(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<LanguageProvider>
|
<LanguageProvider>
|
||||||
<Router>
|
<Router>
|
||||||
<Layout>
|
<Layout openDemoModal={openDemoModal}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<Home />} />
|
||||||
<Route path="/about" element={<About />} />
|
<Route path="/about" element={<About />} />
|
||||||
|
|
@ -39,6 +46,7 @@ function App() {
|
||||||
<Route path="*" element={<NotFound />} />
|
<Route path="*" element={<NotFound />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
<Demo isOpen={isDemoModalOpen} onClose={closeDemoModal} />
|
||||||
<Toaster position="top-right" />
|
<Toaster position="top-right" />
|
||||||
</Router>
|
</Router>
|
||||||
</LanguageProvider>
|
</LanguageProvider>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,11 @@ import Logo from "./Logo";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import { useLanguage } from "../../context/LanguageContext";
|
import { useLanguage } from "../../context/LanguageContext";
|
||||||
|
|
||||||
const Header: React.FC = () => {
|
interface HeaderProps {
|
||||||
|
openDemoModal: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Header: React.FC<HeaderProps> = ({ openDemoModal }) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [scrolled, setScrolled] = useState(false);
|
const [scrolled, setScrolled] = useState(false);
|
||||||
const { language, setLanguage, t } = useLanguage();
|
const { language, setLanguage, t } = useLanguage();
|
||||||
|
|
@ -41,8 +45,9 @@ const Header: React.FC = () => {
|
||||||
{ name: t("nav.products"), path: "/products", icon: Package },
|
{ name: t("nav.products"), path: "/products", icon: Package },
|
||||||
{ name: t("nav.services"), path: "/services", icon: Briefcase },
|
{ name: t("nav.services"), path: "/services", icon: Briefcase },
|
||||||
{ name: t("nav.blog"), path: "/blog", icon: BookOpen },
|
{ name: t("nav.blog"), path: "/blog", icon: BookOpen },
|
||||||
|
{ name: t("nav.demo"), action: openDemoModal, icon: Globe },
|
||||||
{ name: t("nav.contact"), path: "/contact", icon: Phone },
|
{ name: t("nav.contact"), path: "/contact", icon: Phone },
|
||||||
{ name: t("nav.demo"), path: import.meta.env.VITE_KURS_URL },
|
{ name: t("nav.giris"), path: import.meta.env.VITE_KURS_URL },
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -60,7 +65,8 @@ const Header: React.FC = () => {
|
||||||
|
|
||||||
{/* Desktop Navigation */}
|
{/* Desktop Navigation */}
|
||||||
<nav className="hidden md:flex items-center space-x-6">
|
<nav className="hidden md:flex items-center space-x-6">
|
||||||
{navLinks.map((link) => (
|
{navLinks.map((link) =>
|
||||||
|
link.path ? (
|
||||||
<Link
|
<Link
|
||||||
key={link.path}
|
key={link.path}
|
||||||
to={link.path}
|
to={link.path}
|
||||||
|
|
@ -70,7 +76,18 @@ const Header: React.FC = () => {
|
||||||
>
|
>
|
||||||
{link.name}
|
{link.name}
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
) : (
|
||||||
|
<button
|
||||||
|
key={link.name}
|
||||||
|
onClick={link.action}
|
||||||
|
className={`font-medium text-sm text-white hover:text-blue-400 transition-colors ${
|
||||||
|
link.name === "Giriş" || link.name === "Login" ? "bg-blue-600 rounded px-2 py-1" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{link.name}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={toggleLanguage}
|
onClick={toggleLanguage}
|
||||||
|
|
@ -96,7 +113,8 @@ const Header: React.FC = () => {
|
||||||
<div className="md:hidden bg-gray-900/95 backdrop-blur-sm shadow-lg">
|
<div className="md:hidden bg-gray-900/95 backdrop-blur-sm shadow-lg">
|
||||||
<div className="container mx-auto px-4 py-2">
|
<div className="container mx-auto px-4 py-2">
|
||||||
<nav className="flex flex-col space-y-4 py-4">
|
<nav className="flex flex-col space-y-4 py-4">
|
||||||
{navLinks.map((link) => (
|
{navLinks.map((link) =>
|
||||||
|
link.path ? (
|
||||||
<Link
|
<Link
|
||||||
key={link.path}
|
key={link.path}
|
||||||
to={link.path}
|
to={link.path}
|
||||||
|
|
@ -107,7 +125,21 @@ const Header: React.FC = () => {
|
||||||
>
|
>
|
||||||
{link.name}
|
{link.name}
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
) : (
|
||||||
|
<button
|
||||||
|
key={link.name}
|
||||||
|
onClick={() => {
|
||||||
|
link.action && link.action();
|
||||||
|
toggleMenu();
|
||||||
|
}}
|
||||||
|
className={`font-medium text-white hover:text-blue-400 transition-colors ${
|
||||||
|
link.name === "Giriş" || link.name === "Login" ? "bg-blue-600 rounded px-2 py-1" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{link.name}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={toggleLanguage}
|
onClick={toggleLanguage}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,10 @@ import Footer from './Footer';
|
||||||
|
|
||||||
interface LayoutProps {
|
interface LayoutProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
openDemoModal: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Layout: React.FC<LayoutProps> = ({ children }) => {
|
const Layout: React.FC<LayoutProps> = ({ children, openDemoModal }) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -16,7 +17,7 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col min-h-screen">
|
<div className="flex flex-col min-h-screen">
|
||||||
<Header />
|
<Header openDemoModal={openDemoModal} />
|
||||||
<main className="flex-grow">
|
<main className="flex-grow">
|
||||||
{children}
|
{children}
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ const translations = {
|
||||||
"nav.about": "Hakkımızda",
|
"nav.about": "Hakkımızda",
|
||||||
"nav.products": "Ürünler",
|
"nav.products": "Ürünler",
|
||||||
"nav.services": "Hizmetler",
|
"nav.services": "Hizmetler",
|
||||||
"nav.demo": "Giriş",
|
"nav.demo": "Demo",
|
||||||
|
"nav.giris": "Giriş",
|
||||||
"nav.blog": "Blog",
|
"nav.blog": "Blog",
|
||||||
"nav.forum": "Forum",
|
"nav.forum": "Forum",
|
||||||
"nav.contact": "İletişim",
|
"nav.contact": "İletişim",
|
||||||
|
|
@ -123,9 +124,17 @@ const translations = {
|
||||||
"services.cta.description":
|
"services.cta.description":
|
||||||
"İşletmenizin ihtiyaçlarına özel çözümlerimizle rekabette öne geçin. Danışmanlık için bize ulaşın.",
|
"İşletmenizin ihtiyaçlarına özel çözümlerimizle rekabette öne geçin. Danışmanlık için bize ulaşın.",
|
||||||
"services.cta.contact": "İletişime Geçin",
|
"services.cta.contact": "İletişime Geçin",
|
||||||
"demo.form.title": "Demo Talep Formu",
|
"demo.title": "Demo Talep Formu",
|
||||||
"demo.subtitle":
|
"demo.subtitle": "Sorularınız için bizimle iletişime geçin. Size yardımcı olmaktan mutluluk duyarız.",
|
||||||
"Sorularınız için bizimle iletişime geçin. Size yardımcı olmaktan mutluluk duyarız.",
|
"demo.send": "Demo Talebi Gönder",
|
||||||
|
"demo.organizationName": "Organizasyon adınızı girin",
|
||||||
|
"demo.fullName": "Ad soyadınızı girin",
|
||||||
|
"demo.email": "ornek@email.com",
|
||||||
|
"demo.phone": "+90 (555) 123-4567",
|
||||||
|
"demo.address": "Adresinizi girin",
|
||||||
|
"demo.branches": "örn. 5",
|
||||||
|
"demo.users": "örn. 50",
|
||||||
|
"demo.message": "İhtiyaçlarınız ve demoda görmek istediğiniz özellikler hakkında bize bilgi verin...",
|
||||||
|
|
||||||
// Services Page
|
// Services Page
|
||||||
"services.title": "Hizmetlerimiz",
|
"services.title": "Hizmetlerimiz",
|
||||||
|
|
@ -421,7 +430,8 @@ const translations = {
|
||||||
"nav.about": "About Us",
|
"nav.about": "About Us",
|
||||||
"nav.products": "Products",
|
"nav.products": "Products",
|
||||||
"nav.services": "Services",
|
"nav.services": "Services",
|
||||||
"nav.demo": "Login",
|
"nav.demo": "Demo",
|
||||||
|
"nav.giris": "Login",
|
||||||
"nav.blog": "Blog",
|
"nav.blog": "Blog",
|
||||||
"nav.forum": "Forum",
|
"nav.forum": "Forum",
|
||||||
"nav.contact": "Contact",
|
"nav.contact": "Contact",
|
||||||
|
|
@ -533,9 +543,17 @@ const translations = {
|
||||||
"services.cta.description":
|
"services.cta.description":
|
||||||
"Gain a competitive edge with our tailored solutions. Contact us for a consultation.",
|
"Gain a competitive edge with our tailored solutions. Contact us for a consultation.",
|
||||||
"services.cta.contact": "Get in Touch",
|
"services.cta.contact": "Get in Touch",
|
||||||
"demo.form.title": "Demo Request Form",
|
"demo.title": "Demo Request Form",
|
||||||
"demo.subtitle":
|
"demo.subtitle":"Contact us for any inquiries. We are happy to assist you.",
|
||||||
"Contact us for any inquiries. We are happy to assist you.",
|
"demo.send": "Send Demo Request",
|
||||||
|
"demo.organizationName": "Enter your organization name",
|
||||||
|
"demo.fullName": "Enter your name and surname",
|
||||||
|
"demo.email": "sample@email.com",
|
||||||
|
"demo.phone": "+90 (555) 123-4567",
|
||||||
|
"demo.address": "Enter your address",
|
||||||
|
"demo.branches": "sample 5",
|
||||||
|
"demo.users": "sample 50",
|
||||||
|
"demo.message": "Tell us about your needs and the features you would like to see in the demo...",
|
||||||
|
|
||||||
// Services Page
|
// Services Page
|
||||||
"services.title": "Our Services",
|
"services.title": "Our Services",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState } from "react";
|
import React from "react";
|
||||||
import {
|
import {
|
||||||
Mail,
|
Mail,
|
||||||
Phone,
|
Phone,
|
||||||
|
|
@ -10,55 +10,10 @@ import {
|
||||||
MessageCircle,
|
MessageCircle,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { useLanguage } from "../context/LanguageContext";
|
import { useLanguage } from "../context/LanguageContext";
|
||||||
import { demoService } from "../services/api/demo.service";
|
|
||||||
|
|
||||||
const Contact: React.FC = () => {
|
const Contact: React.FC = () => {
|
||||||
const { t } = useLanguage();
|
const { t } = useLanguage();
|
||||||
|
|
||||||
const [formData, setFormData] = useState({
|
|
||||||
company: "",
|
|
||||||
fullName: "",
|
|
||||||
email: "",
|
|
||||||
phone: "",
|
|
||||||
address: "",
|
|
||||||
branchCount: "",
|
|
||||||
userCount: "",
|
|
||||||
message: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleChange = (
|
|
||||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
|
||||||
) => {
|
|
||||||
const { name, value } = e.target;
|
|
||||||
setFormData((prev: any) => ({
|
|
||||||
...prev,
|
|
||||||
[name]: value,
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
try {
|
|
||||||
await demoService.createDemoForm(formData);
|
|
||||||
|
|
||||||
alert("Form başarıyla gönderildi.");
|
|
||||||
setFormData({
|
|
||||||
company: "",
|
|
||||||
fullName: "",
|
|
||||||
email: "",
|
|
||||||
phone: "",
|
|
||||||
address: "",
|
|
||||||
branchCount: "",
|
|
||||||
userCount: "",
|
|
||||||
message: "",
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Gönderim hatası:", error);
|
|
||||||
alert("Sunucuya ulaşılamıyor.");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50">
|
<div className="min-h-screen bg-gray-50">
|
||||||
{/* Hero Section */}
|
{/* Hero Section */}
|
||||||
|
|
@ -187,167 +142,8 @@ const Contact: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-8">
|
|
||||||
<div className="bg-white rounded-xl shadow-lg p-8">
|
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-6">
|
|
||||||
{t("demo.form.title")}
|
|
||||||
</h2>
|
|
||||||
<form className="space-y-6" onSubmit={handleSubmit}>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
htmlFor="company"
|
|
||||||
className="block text-sm font-medium text-gray-700 mb-2"
|
|
||||||
>
|
|
||||||
{t("common.company")}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="company"
|
|
||||||
name="company"
|
|
||||||
value={formData.company}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
htmlFor="fullName"
|
|
||||||
className="block text-sm font-medium text-gray-700 mb-2"
|
|
||||||
>
|
|
||||||
{t("common.fullName") || "Adınız Soyadınız"}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="fullName"
|
|
||||||
name="fullName"
|
|
||||||
value={formData.fullName}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
htmlFor="email"
|
|
||||||
className="block text-sm font-medium text-gray-700 mb-2"
|
|
||||||
>
|
|
||||||
{t("common.email")}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
id="email"
|
|
||||||
name="email"
|
|
||||||
value={formData.email}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
htmlFor="phone"
|
|
||||||
className="block text-sm font-medium text-gray-700 mb-2"
|
|
||||||
>
|
|
||||||
{t("common.phone")}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="tel"
|
|
||||||
id="phone"
|
|
||||||
name="phone"
|
|
||||||
value={formData.phone}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
htmlFor="address"
|
|
||||||
className="block text-sm font-medium text-gray-700 mb-2"
|
|
||||||
>
|
|
||||||
{t("common.address")}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="address"
|
|
||||||
name="address"
|
|
||||||
value={formData.address}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
htmlFor="branchCount"
|
|
||||||
className="block text-sm font-medium text-gray-700 mb-2"
|
|
||||||
>
|
|
||||||
{t("common.branchCount") || "Şube Adedi"}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
id="branchCount"
|
|
||||||
name="branchCount"
|
|
||||||
value={formData.branchCount}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
htmlFor="userCount"
|
|
||||||
className="block text-sm font-medium text-gray-700 mb-2"
|
|
||||||
>
|
|
||||||
{t("common.userCount") || "Kullanıcı Adedi"}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
id="userCount"
|
|
||||||
name="userCount"
|
|
||||||
value={formData.userCount}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
htmlFor="message"
|
|
||||||
className="block text-sm font-medium text-gray-700 mb-2"
|
|
||||||
>
|
|
||||||
{t("common.message")}
|
|
||||||
</label>
|
|
||||||
<textarea
|
|
||||||
id="message"
|
|
||||||
name="message"
|
|
||||||
rows={10}
|
|
||||||
value={formData.message}
|
|
||||||
onChange={handleChange}
|
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="w-full bg-blue-600 text-white py-3 px-6 rounded-lg hover:bg-blue-700 transition-colors font-semibold"
|
|
||||||
>
|
|
||||||
{t("common.send")}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Map Section */}
|
{/* Map Section */}
|
||||||
<div className="bg-white py-16">
|
<div className="bg-white rounded-xl shadow-lg p-8">
|
||||||
<div className="container mx-auto px-4">
|
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-8 text-center">
|
<h2 className="text-2xl font-bold text-gray-900 mb-8 text-center">
|
||||||
{t("contact.location")}
|
{t("contact.location")}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
@ -355,7 +151,7 @@ const Contact: React.FC = () => {
|
||||||
<iframe
|
<iframe
|
||||||
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3006.209566407676!2d28.757000999999992!3d41.10811400000001!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x8a0bbbdfcfd3fd24!2zU8O2enNvZnQ!5e0!3m2!1str!2str!4v1450816303558"
|
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3006.209566407676!2d28.757000999999992!3d41.10811400000001!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x8a0bbbdfcfd3fd24!2zU8O2enNvZnQ!5e0!3m2!1str!2str!4v1450816303558"
|
||||||
width="100%"
|
width="100%"
|
||||||
height="450"
|
height="740"
|
||||||
style={{ border: 0 }}
|
style={{ border: 0 }}
|
||||||
allowFullScreen
|
allowFullScreen
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
|
|
@ -365,6 +161,8 @@ const Contact: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
383
company/src/pages/Demo.tsx
Normal file
383
company/src/pages/Demo.tsx
Normal file
|
|
@ -0,0 +1,383 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { useLanguage } from "../context/LanguageContext";
|
||||||
|
import { demoService } from "../services/api/demo.service";
|
||||||
|
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;
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import { apiClient } from './config'
|
import { apiClient } from './config'
|
||||||
|
|
||||||
export interface DemoFormRequest {
|
export interface DemoFormRequest {
|
||||||
company: string
|
organizationName: string
|
||||||
fullName: string
|
fullName: string
|
||||||
email: string
|
email: string
|
||||||
phone: string
|
phone: string
|
||||||
address: string
|
address: string
|
||||||
branchCount: string
|
numberOfBranches: string
|
||||||
userCount: string
|
numberOfUsers: string
|
||||||
message: string
|
message: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue