782 lines
30 KiB
TypeScript
782 lines
30 KiB
TypeScript
|
|
import React, { useState } from "react";
|
|||
|
|
import { useParams, useNavigate, Link } from "react-router-dom";
|
|||
|
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|||
|
|
import {
|
|||
|
|
FaArrowLeft,
|
|||
|
|
FaSave,
|
|||
|
|
FaTimes,
|
|||
|
|
FaBuilding,
|
|||
|
|
FaUser,
|
|||
|
|
FaMapMarkerAlt,
|
|||
|
|
FaIdCard,
|
|||
|
|
FaCreditCard,
|
|||
|
|
FaExclamationTriangle,
|
|||
|
|
} from "react-icons/fa";
|
|||
|
|
import classNames from "classnames";
|
|||
|
|
import { CustomerSegmentEnum, CustomerTypeEnum } from "../../../types/crm";
|
|||
|
|
import {
|
|||
|
|
mockBusinessParties,
|
|||
|
|
mockBusinessPartyNew,
|
|||
|
|
} from "../../../mocks/mockBusinessParties";
|
|||
|
|
import {
|
|||
|
|
BusinessParty,
|
|||
|
|
BusinessPartyStatusEnum,
|
|||
|
|
PaymentTerms,
|
|||
|
|
} from "../../../types/common";
|
|||
|
|
|
|||
|
|
const CustomerEdit: React.FC = () => {
|
|||
|
|
const { id } = useParams<{ id: string }>();
|
|||
|
|
const navigate = useNavigate();
|
|||
|
|
const queryClient = useQueryClient();
|
|||
|
|
const [activeTab, setActiveTab] = useState("basic");
|
|||
|
|
const [isDirty, setIsDirty] = useState(false);
|
|||
|
|
|
|||
|
|
const {
|
|||
|
|
data: customer,
|
|||
|
|
isLoading,
|
|||
|
|
error,
|
|||
|
|
} = useQuery({
|
|||
|
|
queryKey: ["customer", id],
|
|||
|
|
queryFn: async () => {
|
|||
|
|
await new Promise((resolve) => setTimeout(resolve, 300));
|
|||
|
|
const found = mockBusinessParties.find((c) => c.id === id);
|
|||
|
|
if (!found) throw new Error("Müşteri bulunamadı");
|
|||
|
|
return found;
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const [formData, setFormData] = useState<BusinessParty>(mockBusinessPartyNew);
|
|||
|
|
|
|||
|
|
// Initialize form data when customer is loaded
|
|||
|
|
React.useEffect(() => {
|
|||
|
|
if (customer) {
|
|||
|
|
setFormData(
|
|||
|
|
mockBusinessParties.find((c) => c.id === id) || mockBusinessPartyNew
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}, [customer, id]);
|
|||
|
|
|
|||
|
|
const updateMutation = useMutation({
|
|||
|
|
mutationFn: async (data: BusinessParty) => {
|
|||
|
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|||
|
|
// Simulate API call
|
|||
|
|
return { ...customer, ...data };
|
|||
|
|
},
|
|||
|
|
onSuccess: () => {
|
|||
|
|
queryClient.invalidateQueries({ queryKey: ["customers"] });
|
|||
|
|
queryClient.invalidateQueries({ queryKey: ["customer", id] });
|
|||
|
|
setIsDirty(false);
|
|||
|
|
navigate(`/admin/crm/customers/${id}`);
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const handleInputChange = (field: string, value: string | number) => {
|
|||
|
|
const keys = field.split(".");
|
|||
|
|
if (keys.length === 2) {
|
|||
|
|
const [section, subField] = keys;
|
|||
|
|
setFormData((prev: any) => {
|
|||
|
|
if (section === "primaryContact") {
|
|||
|
|
return {
|
|||
|
|
...prev,
|
|||
|
|
primaryContact: {
|
|||
|
|
...prev.primaryContact,
|
|||
|
|
[subField]: value,
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
} else if (section === "address") {
|
|||
|
|
return {
|
|||
|
|
...prev,
|
|||
|
|
address: {
|
|||
|
|
...prev.address,
|
|||
|
|
[subField]: value,
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
return prev;
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
setFormData((prev) => ({
|
|||
|
|
...prev,
|
|||
|
|
[field]: value,
|
|||
|
|
}));
|
|||
|
|
}
|
|||
|
|
setIsDirty(true);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const handleSubmit = (e: React.FormEvent) => {
|
|||
|
|
e.preventDefault();
|
|||
|
|
|
|||
|
|
updateMutation.mutate(formData);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const handleCancel = () => {
|
|||
|
|
if (isDirty) {
|
|||
|
|
if (
|
|||
|
|
window.confirm(
|
|||
|
|
"Değişiklikleriniz kaydedilmedi. Çıkmak istediğinizden emin misiniz?"
|
|||
|
|
)
|
|||
|
|
) {
|
|||
|
|
navigate(`/admin/crm/customers/${id}`);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
navigate(`/admin/crm/customers/${id}`);
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
if (isLoading) {
|
|||
|
|
return (
|
|||
|
|
<div className="min-h-screen bg-gray-50 p-6">
|
|||
|
|
<div className="mx-auto">
|
|||
|
|
<div className="animate-pulse">
|
|||
|
|
<div className="h-8 bg-gray-200 rounded w-1/4 mb-6"></div>
|
|||
|
|
<div className="bg-white rounded-lg shadow p-6">
|
|||
|
|
<div className="space-y-4">
|
|||
|
|
{[...Array(8)].map((_, i) => (
|
|||
|
|
<div key={i} className="h-10 bg-gray-200 rounded"></div>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (error || !customer) {
|
|||
|
|
return (
|
|||
|
|
<div className="min-h-screen bg-gray-50 p-6">
|
|||
|
|
<div className="mx-auto">
|
|||
|
|
<div className="bg-red-50 border border-red-200 rounded-lg p-6">
|
|||
|
|
<div className="flex items-center">
|
|||
|
|
<FaExclamationTriangle className="h-8 w-8 text-red-600 mr-3" />
|
|||
|
|
<div>
|
|||
|
|
<h3 className="text-lg font-medium text-red-800">
|
|||
|
|
Müşteri Bulunamadı
|
|||
|
|
</h3>
|
|||
|
|
<p className="text-red-600">
|
|||
|
|
Düzenlemek istediğiniz müşteri mevcut değil.
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div className="mt-4">
|
|||
|
|
<button
|
|||
|
|
onClick={() => navigate("/admin/crm/customers")}
|
|||
|
|
className="inline-flex items-center px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
|
|||
|
|
>
|
|||
|
|
<FaArrowLeft className="w-4 h-4 mr-2" />
|
|||
|
|
Müşteri Listesine Dön
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const tabs = [
|
|||
|
|
{ id: "basic", label: "Temel Bilgiler", icon: FaBuilding },
|
|||
|
|
{ id: "contact", label: "İletişim", icon: FaUser },
|
|||
|
|
{ id: "business", label: "İş Bilgileri", icon: FaIdCard },
|
|||
|
|
{ id: "financial", label: "Finansal", icon: FaCreditCard },
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div className="min-h-screen bg-gray-50">
|
|||
|
|
<form onSubmit={handleSubmit}>
|
|||
|
|
{/* Header */}
|
|||
|
|
<div className="bg-white border-b border-gray-200">
|
|||
|
|
<div className="mx-auto px-4 py-3">
|
|||
|
|
{/* Breadcrumb */}
|
|||
|
|
<div className="flex items-center space-x-2 text-xs text-gray-500 mb-3">
|
|||
|
|
<Link to="/admin/crm/customers" className="hover:text-blue-600">
|
|||
|
|
Müşteriler
|
|||
|
|
</Link>
|
|||
|
|
<span>/</span>
|
|||
|
|
<Link
|
|||
|
|
to={`/admin/crm/customers/${id}`}
|
|||
|
|
className="hover:text-blue-600"
|
|||
|
|
>
|
|||
|
|
{customer.name}
|
|||
|
|
</Link>
|
|||
|
|
<span>/</span>
|
|||
|
|
<span className="text-gray-900">Düzenle</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Header */}
|
|||
|
|
<div className="flex items-center justify-between">
|
|||
|
|
<div className="flex items-center space-x-4">
|
|||
|
|
<button
|
|||
|
|
type="button"
|
|||
|
|
onClick={handleCancel}
|
|||
|
|
className="p-1.5 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors"
|
|||
|
|
>
|
|||
|
|
<FaArrowLeft className="w-5 h-5" />
|
|||
|
|
</button>
|
|||
|
|
|
|||
|
|
<div className="flex items-center space-x-4">
|
|||
|
|
<div className="w-10 h-10 bg-gradient-to-br from-blue-500 to-blue-600 rounded-lg flex items-center justify-center text-white shadow-lg">
|
|||
|
|
<FaBuilding className="w-6 h-6" />
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<h1 className="text-xl font-bold text-gray-900">
|
|||
|
|
Müşteri Düzenle
|
|||
|
|
</h1>
|
|||
|
|
<p className="text-sm text-gray-600">{customer.name}</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="flex items-center space-x-2">
|
|||
|
|
<button
|
|||
|
|
type="button"
|
|||
|
|
onClick={handleCancel}
|
|||
|
|
className="inline-flex items-center px-3 py-1.5 text-sm border border-gray-300 bg-white text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
|||
|
|
>
|
|||
|
|
<FaTimes className="w-4 h-4 mr-2" />
|
|||
|
|
İptal
|
|||
|
|
</button>
|
|||
|
|
<button
|
|||
|
|
type="submit"
|
|||
|
|
disabled={!isDirty || updateMutation.isPending}
|
|||
|
|
className={classNames(
|
|||
|
|
"inline-flex items-center px-3 py-1.5 text-sm rounded-lg transition-colors",
|
|||
|
|
isDirty && !updateMutation.isPending
|
|||
|
|
? "bg-blue-600 text-white hover:bg-blue-700"
|
|||
|
|
: "bg-gray-300 text-gray-500 cursor-not-allowed"
|
|||
|
|
)}
|
|||
|
|
>
|
|||
|
|
{updateMutation.isPending ? (
|
|||
|
|
<>
|
|||
|
|
<div className="animate-spin w-4 h-4 mr-2 border-2 border-white border-t-transparent rounded-full"></div>
|
|||
|
|
Kaydediliyor...
|
|||
|
|
</>
|
|||
|
|
) : (
|
|||
|
|
<>
|
|||
|
|
<FaSave className="w-4 h-4 mr-2" />
|
|||
|
|
Kaydet
|
|||
|
|
</>
|
|||
|
|
)}
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Tabs */}
|
|||
|
|
<div className="bg-white border-b border-gray-200">
|
|||
|
|
<div className="mx-auto px-4">
|
|||
|
|
<nav className="flex space-x-8">
|
|||
|
|
{tabs.map((tab) => (
|
|||
|
|
<button
|
|||
|
|
key={tab.id}
|
|||
|
|
type="button"
|
|||
|
|
onClick={() => setActiveTab(tab.id)}
|
|||
|
|
className={classNames(
|
|||
|
|
"flex items-center space-x-2 py-3 px-1 border-b-2 font-medium text-sm transition-colors",
|
|||
|
|
activeTab === tab.id
|
|||
|
|
? "border-blue-500 text-blue-600"
|
|||
|
|
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300"
|
|||
|
|
)}
|
|||
|
|
>
|
|||
|
|
<tab.icon className="w-4 h-4" />
|
|||
|
|
<span>{tab.label}</span>
|
|||
|
|
</button>
|
|||
|
|
))}
|
|||
|
|
</nav>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Form Content */}
|
|||
|
|
<div className="mx-auto py-4">
|
|||
|
|
{activeTab === "basic" && (
|
|||
|
|
<div className="bg-white rounded-lg shadow p-4">
|
|||
|
|
<h3 className="text-base font-semibold text-gray-900 mb-4 flex items-center">
|
|||
|
|
<FaBuilding className="w-5 h-5 mr-2" />
|
|||
|
|
Temel Bilgiler
|
|||
|
|
</h3>
|
|||
|
|
|
|||
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Müşteri Kodu *
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.code}
|
|||
|
|
onChange={(e) => handleInputChange("code", e.target.value)}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
required
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Şirket Adı *
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.name}
|
|||
|
|
onChange={(e) => handleInputChange("name", e.target.value)}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
required
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Müşteri Tipi
|
|||
|
|
</label>
|
|||
|
|
<select
|
|||
|
|
value={formData.customerType}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("customerType", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
>
|
|||
|
|
<option value={CustomerTypeEnum.Company}>Şirket</option>
|
|||
|
|
<option value={CustomerTypeEnum.Individual}>
|
|||
|
|
Bireysel
|
|||
|
|
</option>
|
|||
|
|
<option value={CustomerTypeEnum.Government}>Kamu</option>
|
|||
|
|
<option value={CustomerTypeEnum.NonProfit}>
|
|||
|
|
Kar Amacı Gütmeyen
|
|||
|
|
</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Sektör
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.industry}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("industry", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
placeholder="Teknoloji, İmalat, Hizmet vb."
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="md:col-span-2">
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Website
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="url"
|
|||
|
|
value={formData.website}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("website", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
placeholder="https://www.ornek.com"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Müşteri Durumu
|
|||
|
|
</label>
|
|||
|
|
<select
|
|||
|
|
value={formData.status}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("status", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
>
|
|||
|
|
<option value={BusinessPartyStatusEnum.Prospect}>
|
|||
|
|
Potansiyel
|
|||
|
|
</option>
|
|||
|
|
<option value={BusinessPartyStatusEnum.Active}>
|
|||
|
|
Aktif
|
|||
|
|
</option>
|
|||
|
|
<option value={BusinessPartyStatusEnum.Inactive}>
|
|||
|
|
Pasif
|
|||
|
|
</option>
|
|||
|
|
<option value={BusinessPartyStatusEnum.Blocked}>
|
|||
|
|
Blokeli
|
|||
|
|
</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Müşteri Segmenti
|
|||
|
|
</label>
|
|||
|
|
<select
|
|||
|
|
value={formData.customerSegment}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("customerSegment", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
>
|
|||
|
|
<option value={CustomerSegmentEnum.Enterprise}>
|
|||
|
|
Kurumsal
|
|||
|
|
</option>
|
|||
|
|
<option value={CustomerSegmentEnum.SMB}>KOBİ</option>
|
|||
|
|
<option value={CustomerSegmentEnum.Startup}>Girişim</option>
|
|||
|
|
<option value={CustomerSegmentEnum.Government}>Kamu</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{activeTab === "contact" && (
|
|||
|
|
<div className="space-y-4">
|
|||
|
|
{/* Primary Contact */}
|
|||
|
|
<div className="bg-white rounded-lg shadow p-4">
|
|||
|
|
<h3 className="text-base font-semibold text-gray-900 mb-4 flex items-center">
|
|||
|
|
<FaUser className="w-5 h-5 mr-2" />
|
|||
|
|
Ana İletişim Kişisi
|
|||
|
|
</h3>
|
|||
|
|
|
|||
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Ad *
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.primaryContact?.firstName}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange(
|
|||
|
|
"primaryContact.firstName",
|
|||
|
|
e.target.value
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
required
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Soyad *
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.primaryContact?.lastName}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange(
|
|||
|
|
"primaryContact.lastName",
|
|||
|
|
e.target.value
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
required
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Ünvan
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.primaryContact?.title}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange(
|
|||
|
|
"primaryContact.title",
|
|||
|
|
e.target.value
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
placeholder="Genel Müdür, Satış Direktörü vb."
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Departman
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.primaryContact?.department}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange(
|
|||
|
|
"primaryContact.department",
|
|||
|
|
e.target.value
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
placeholder="Satış, Pazarlama, İnsan Kaynakları vb."
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
E-posta *
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="email"
|
|||
|
|
value={formData.primaryContact?.email}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange(
|
|||
|
|
"primaryContact.email",
|
|||
|
|
e.target.value
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
required
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Telefon
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="tel"
|
|||
|
|
value={formData.primaryContact?.phone}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange(
|
|||
|
|
"primaryContact.phone",
|
|||
|
|
e.target.value
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
placeholder="+90 (212) 555 0123"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="md:col-span-2">
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Mobil Telefon
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="tel"
|
|||
|
|
value={formData.primaryContact?.mobile}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange(
|
|||
|
|
"primaryContact.mobile",
|
|||
|
|
e.target.value
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
placeholder="+90 (555) 123 4567"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Address */}
|
|||
|
|
<div className="bg-white rounded-lg shadow p-4">
|
|||
|
|
<h3 className="text-base font-semibold text-gray-900 mb-4 flex items-center">
|
|||
|
|
<FaMapMarkerAlt className="w-5 h-5 mr-2" />
|
|||
|
|
Adres Bilgileri
|
|||
|
|
</h3>
|
|||
|
|
|
|||
|
|
<div className="grid grid-cols-1 gap-4">
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Adres *
|
|||
|
|
</label>
|
|||
|
|
<textarea
|
|||
|
|
value={formData.address?.street}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("address.street", e.target.value)
|
|||
|
|
}
|
|||
|
|
rows={3}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
placeholder="Sokak, cadde, mahalle, bina no vb."
|
|||
|
|
required
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Şehir *
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.address?.city}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("address.city", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
required
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
İl/Eyalet
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.address?.state}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("address.state", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Posta Kodu
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.address?.postalCode}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange(
|
|||
|
|
"address.postalCode",
|
|||
|
|
e.target.value
|
|||
|
|
)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Ülke *
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.address?.country}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("address.country", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
required
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{activeTab === "business" && (
|
|||
|
|
<div className="bg-white rounded-lg shadow p-4">
|
|||
|
|
<h3 className="text-base font-semibold text-gray-900 mb-4 flex items-center">
|
|||
|
|
<FaIdCard className="w-5 h-5 mr-2" />
|
|||
|
|
İş Bilgileri
|
|||
|
|
</h3>
|
|||
|
|
|
|||
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Vergi Numarası
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.taxNumber}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("taxNumber", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
placeholder="1234567890"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Sicil Numarası
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.registrationNumber}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("registrationNumber", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
placeholder="123456789"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="md:col-span-2">
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Atanmış Satış Temsilcisi
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="text"
|
|||
|
|
value={formData.assignedSalesRep}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("assignedSalesRep", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
placeholder="Satış temsilcisi adı"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
|
|||
|
|
{activeTab === "financial" && (
|
|||
|
|
<div className="bg-white rounded-lg shadow p-4">
|
|||
|
|
<h3 className="text-base font-semibold text-gray-900 mb-4 flex items-center">
|
|||
|
|
<FaCreditCard className="w-5 h-5 mr-2" />
|
|||
|
|
Finansal Bilgiler
|
|||
|
|
</h3>
|
|||
|
|
|
|||
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Kredi Limiti (₺)
|
|||
|
|
</label>
|
|||
|
|
<input
|
|||
|
|
type="number"
|
|||
|
|
value={formData.creditLimit}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("creditLimit", Number(e.target.value))
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
min="0"
|
|||
|
|
step="1000"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div>
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Para Birimi
|
|||
|
|
</label>
|
|||
|
|
<select
|
|||
|
|
value={formData.currency}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("currency", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
>
|
|||
|
|
<option value="TRY">Türk Lirası (TRY)</option>
|
|||
|
|
<option value="USD">Amerikan Doları (USD)</option>
|
|||
|
|
<option value="EUR">Euro (EUR)</option>
|
|||
|
|
<option value="GBP">İngiliz Sterlini (GBP)</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="md:col-span-2">
|
|||
|
|
<label className="block text-xs font-medium text-gray-700 mb-1">
|
|||
|
|
Ödeme Koşulları
|
|||
|
|
</label>
|
|||
|
|
<select
|
|||
|
|
value={formData.paymentTerms}
|
|||
|
|
onChange={(e) =>
|
|||
|
|
handleInputChange("paymentTerms", e.target.value)
|
|||
|
|
}
|
|||
|
|
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|||
|
|
>
|
|||
|
|
<option value={PaymentTerms.Prepaid}>Peşin</option>
|
|||
|
|
<option value={PaymentTerms.COD}>Kapıda Ödeme</option>
|
|||
|
|
<option value={PaymentTerms.Net30}>30 Gün Vade</option>
|
|||
|
|
<option value={PaymentTerms.Net60}>60 Gün Vade</option>
|
|||
|
|
<option value={PaymentTerms.Net90}>90 Gün Vade</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
</form>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export default CustomerEdit;
|