erp-platform/ui/src/views/crm/components/SalesTeamCreate.tsx

482 lines
17 KiB
TypeScript
Raw Normal View History

2025-09-15 09:31:47 +00:00
import React, { useState } from "react";
import {
FaUsers,
FaArrowLeft,
FaSave,
FaTimes,
FaPlus,
FaTrash,
FaMapMarkerAlt,
} from "react-icons/fa";
import { useNavigate } from "react-router-dom";
import { CrmTerritory } from "../../../types/crm";
import { mockEmployees } from "../../../mocks/mockEmployees";
import { Team, TeamMember, TeamRoleEnum } from "../../../types/common";
const SalesTeamCreate: React.FC = () => {
const navigate = useNavigate();
const [formData, setFormData] = useState({
teamCode: "",
name: "",
description: "",
managerId: "",
isActive: true,
});
const [members, setMembers] = useState<Partial<TeamMember>[]>([]);
const [territories, setTerritories] = useState<Partial<CrmTerritory>[]>([]);
const [errors, setErrors] = useState<Record<string, string>>({});
const handleInputChange = (field: string, value: string | boolean) => {
setFormData((prev) => ({ ...prev, [field]: value }));
if (errors[field]) {
setErrors((prev) => ({ ...prev, [field]: "" }));
}
};
const addMember = () => {
setMembers((prev) => [
...prev,
{
employeeId: "",
role: TeamRoleEnum.Member,
isActive: true,
},
]);
};
const removeMember = (index: number) => {
setMembers((prev) => prev.filter((_, i) => i !== index));
};
const updateMember = (
index: number,
field: string,
value: string | TeamRoleEnum | boolean
) => {
setMembers((prev) =>
prev.map((member, i) =>
i === index ? { ...member, [field]: value } : member
)
);
};
const addTerritory = () => {
setTerritories((prev) => [
...prev,
{
territoryCode: "",
name: "",
description: "",
region: "",
countries: [],
cities: [],
isActive: true,
},
]);
};
const removeTerritory = (index: number) => {
setTerritories((prev) => prev.filter((_, i) => i !== index));
};
const updateTerritory = (
index: number,
field: string,
value: string | string[] | boolean
) => {
setTerritories((prev) =>
prev.map((territory, i) =>
i === index ? { ...territory, [field]: value } : territory
)
);
};
const validateForm = () => {
const newErrors: Record<string, string> = {};
if (!formData.teamCode.trim()) {
newErrors.teamCode = "Takım kodu zorunludur";
}
if (!formData.name.trim()) {
newErrors.name = "Takım adı zorunludur";
}
if (!formData.managerId.trim()) {
newErrors.managerId = "Takım lideri seçimi zorunludur";
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSave = () => {
if (!validateForm()) return;
const newTeam: Partial<Team> = {
...formData,
members: members.map((member, index) => ({
...member,
id: `member-new-${index}`,
teamId: "new-team",
joinDate: new Date(),
})) as TeamMember[],
territories: territories.map((territory, index) => ({
...territory,
id: `territory-new-${index}`,
assignedTeamId: "new-team",
})) as CrmTerritory[],
targets: [],
creationTime: new Date(),
lastModificationTime: new Date(),
};
console.log("Creating new sales team:", newTeam);
alert("Satış ekibi başarıyla oluşturuldu!");
navigate("/admin/crm/sales-teams");
};
const handleCancel = () => {
if (
confirm("Değişiklikler kaydedilmedi. Çıkmak istediğinizden emin misiniz?")
) {
navigate("/admin/crm/sales-teams");
}
};
return (
<div className="space-y-4 pt-2">
{/* Header */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<button
onClick={() => navigate("/admin/crm/sales-teams")}
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>
<h2 className="text-xl font-bold text-gray-900">
Yeni Satış Ekibi
</h2>
<p className="text-sm text-gray-600 mt-1">
Yeni satış ekibi oluşturun ve ekip üyelerini atayın
</p>
</div>
</div>
<div className="flex gap-2">
<button
onClick={handleCancel}
className="flex items-center gap-2 px-3 py-1.5 text-sm text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200 transition-colors"
>
<FaTimes className="w-4 h-4" />
İptal
</button>
<button
onClick={handleSave}
className="flex items-center gap-2 px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
>
<FaSave className="w-4 h-4" />
Kaydet
</button>
</div>
</div>
{/* Form */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
{/* Basic Information */}
<div className="lg:col-span-2">
<div className="bg-white rounded-lg shadow-sm border p-4">
<h3 className="text-base font-semibold text-gray-900 mb-4 flex items-center">
<FaUsers 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">
Takım Kodu *
</label>
<input
type="text"
value={formData.teamCode}
onChange={(e) =>
handleInputChange("teamCode", e.target.value)
}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${
errors.teamCode ? "border-red-500" : "border-gray-300"
}`}
placeholder="ST-001"
/>
{errors.teamCode && (
<p className="text-red-500 text-sm mt-1">{errors.teamCode}</p>
)}
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Takım Lideri *
</label>
<select
value={formData.managerId}
onChange={(e) =>
handleInputChange("managerId", e.target.value)
}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${
errors.managerId ? "border-red-500" : "border-gray-300"
}`}
>
<option value="">Çalışan seçin</option>
{mockEmployees.map((employee) => (
<option key={employee.id} value={employee.id}>
{employee.fullName}
</option>
))}
</select>
{errors.managerId && (
<p className="text-red-500 text-sm mt-1">
{errors.managerId}
</p>
)}
</div>
</div>
<div className="mt-4">
<label className="block text-xs font-medium text-gray-700 mb-1">
Takım 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 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${
errors.name ? "border-red-500" : "border-gray-300"
}`}
placeholder="Kurumsal Satış Ekibi"
/>
{errors.name && (
<p className="text-red-500 text-sm mt-1">{errors.name}</p>
)}
</div>
<div className="mt-4">
<label className="block text-xs font-medium text-gray-700 mb-1">
ıklama
</label>
<textarea
value={formData.description}
onChange={(e) =>
handleInputChange("description", 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"
rows={3}
placeholder="Ekip açıklaması..."
/>
</div>
<div className="mt-4">
<label className="flex items-center">
<input
type="checkbox"
checked={formData.isActive}
onChange={(e) =>
handleInputChange("isActive", e.target.checked)
}
className="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
/>
<span className="ml-2 text-sm text-gray-700">Aktif</span>
</label>
</div>
</div>
{/* Team Members */}
<div className="bg-white rounded-lg shadow-sm border p-4 mt-4">
<div className="flex items-center justify-between mb-4">
<h3 className="text-base font-semibold text-gray-900 flex items-center">
<FaUsers className="w-5 h-5 mr-2" />
Ekip Üyeleri
</h3>
<button
onClick={addMember}
className="flex items-center gap-2 px-3 py-1.5 text-sm text-blue-600 border border-blue-200 rounded-md hover:bg-blue-50 transition-colors"
>
<FaPlus className="w-4 h-4" />
Üye Ekle
</button>
</div>
<div className="space-y-3">
{members.map((member, index) => (
<div
key={index}
className="flex items-center gap-3 p-3 border border-gray-200 rounded-lg"
>
<div className="flex-1 grid grid-cols-1 md:grid-cols-2 gap-3">
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Çalışan
</label>
<select
value={member.employeeId || ""}
onChange={(e) =>
updateMember(index, "employeeId", 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="">Çalışan seçin</option>
{mockEmployees.map((employee) => (
<option key={employee.id} value={employee.id}>
{employee.fullName}
</option>
))}
</select>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Rol
</label>
<select
value={member.role || TeamRoleEnum.Member}
onChange={(e) =>
updateMember(index, "role", e.target.value)
}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<option value={TeamRoleEnum.Member}>Üye</option>
<option value={TeamRoleEnum.Lead}>Takım Lideri</option>
<option value={TeamRoleEnum.Manager}>Yönetici</option>
</select>
</div>
</div>
<button
onClick={() => removeMember(index)}
className="p-1.5 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
>
<FaTrash className="w-4 h-4" />
</button>
</div>
))}
{members.length === 0 && (
<div className="text-center py-8 text-gray-500">
<FaUsers className="w-8 h-8 mx-auto mb-2 text-gray-400" />
<p>Henüz ekip üyesi eklenmedi</p>
<p className="text-sm">
Üye eklemek için yukarıdaki butona tıklayın
</p>
</div>
)}
</div>
</div>
</div>
{/* Territories */}
<div>
<div className="bg-white rounded-lg shadow-sm border p-4">
<div className="flex items-center justify-between mb-4">
<h3 className="text-base font-semibold text-gray-900 flex items-center">
<FaMapMarkerAlt className="w-5 h-5 mr-2" />
Bölgeler
</h3>
<button
onClick={addTerritory}
className="flex items-center gap-2 px-3 py-1.5 text-sm text-blue-600 border border-blue-200 rounded-md hover:bg-blue-50 transition-colors"
>
<FaPlus className="w-4 h-4" />
Bölge Ekle
</button>
</div>
<div className="space-y-3">
{territories.map((territory, index) => (
<div
key={index}
className="p-3 border border-gray-200 rounded-lg"
>
<div className="flex justify-between items-start mb-3">
<h4 className="font-medium text-gray-900">
Bölge {index + 1}
</h4>
<button
onClick={() => removeTerritory(index)}
className="p-1.5 text-red-600 hover:bg-red-50 rounded"
>
<FaTrash className="w-4 h-4" />
</button>
</div>
<div className="space-y-2">
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Bölge Kodu
</label>
<input
type="text"
value={territory.territoryCode || ""}
onChange={(e) =>
updateTerritory(
index,
"territoryCode",
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="TR-IST"
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Bölge Adı
</label>
<input
type="text"
value={territory.name || ""}
onChange={(e) =>
updateTerritory(index, "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"
placeholder="İstanbul Anadolu"
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Bölge
</label>
<input
type="text"
value={territory.region || ""}
onChange={(e) =>
updateTerritory(index, "region", 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="Marmara"
/>
</div>
</div>
</div>
))}
{territories.length === 0 && (
<div className="text-center py-8 text-gray-500">
<FaMapMarkerAlt className="w-8 h-8 mx-auto mb-2 text-gray-400" />
<p>Henüz bölge eklenmedi</p>
<p className="text-sm">
Bölge eklemek için yukarıdaki butona tıklayın
</p>
</div>
)}
</div>
</div>
</div>
</div>
</div>
);
};
export default SalesTeamCreate;