erp-platform/ui/src/views/warehouse/components/PutawayRules.tsx
2025-09-15 12:31:47 +03:00

1066 lines
44 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState } from "react";
import { PutawayStrategyEnum } from "../../../types/wm";
import {
FaSearch,
FaPlus,
FaEdit,
FaTrash,
FaCog,
FaBullseye,
FaCheckCircle,
FaExclamationCircle,
FaFilter,
FaArrowDown,
FaTh,
FaList,
} from "react-icons/fa";
import { mockPutawayRules } from "../../../mocks/mockPutawayRules";
import { mockWarehouses } from "../../../mocks/mockWarehouses";
import { mockZones } from "../../../mocks/mockZones";
import { mockLocations } from "../../../mocks/mockLocations";
import { mockMaterialTypes } from "../../../mocks/mockMaterialTypes";
import { mockMaterialGroups } from "../../../mocks/mockMaterialGroups";
import {
getPutawayStrategyColor,
getPutawayStrategyText,
getConditionTypeText,
getConditionOperatorText,
} from "../../../utils/erp";
const PutawayRules: React.FC = () => {
const [searchTerm, setSearchTerm] = useState("");
const [selectedStrategy, setSelectedStrategy] = useState<
PutawayStrategyEnum | ""
>("");
const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
const [showRuleForm, setShowRuleForm] = useState(false);
const [editingRuleId, setEditingRuleId] = useState<string | null>(null);
const [selectedRule, setSelectedRule] = useState<string>("");
// Form States
const [formData, setFormData] = useState({
name: "",
ruleCode: "",
description: "",
warehouseId: "",
materialTypeId: "",
materialGroupId: "",
priority: 1,
targetZoneId: "",
targetLocationId: "",
strategy: PutawayStrategyEnum.FIFO,
isActive: true,
});
// Helper functions for names
const getWarehouseName = (warehouseId: string | undefined) => {
if (!warehouseId) return "Belirtilmemiş";
const warehouse = mockWarehouses.find((w) => w.id === warehouseId);
return warehouse ? warehouse.name : `Depo ${warehouseId}`;
};
const getZoneName = (zoneId: string | undefined) => {
if (!zoneId) return "Belirtilmemiş";
const zone = mockZones.find((z) => z.id === zoneId);
return zone ? zone.name : `Bölge ${zoneId}`;
};
const getLocationName = (locationId: string | undefined) => {
if (!locationId) return "Belirtilmemiş";
const location = mockLocations.find((l) => l.id === locationId);
return location ? location.name : `Lokasyon ${locationId}`;
};
const getMaterialTypeName = (materialTypeId: string | undefined) => {
if (!materialTypeId) return "Belirtilmemiş";
const materialType = mockMaterialTypes.find(
(mt) => mt.id === materialTypeId
);
return materialType ? materialType.name : `Tip ${materialTypeId}`;
};
const getMaterialGroupName = (materialGroupId: string | undefined) => {
if (!materialGroupId) return "Belirtilmemiş";
const materialGroup = mockMaterialGroups.find(
(mg) => mg.id === materialGroupId
);
return materialGroup ? materialGroup.name : `Grup ${materialGroupId}`;
};
// Form Functions
const resetForm = () => {
setFormData({
name: "",
ruleCode: "",
description: "",
warehouseId: "",
materialTypeId: "",
materialGroupId: "",
priority: 1,
targetZoneId: "",
targetLocationId: "",
strategy: PutawayStrategyEnum.FIFO,
isActive: true,
});
};
const handleEditRule = (ruleId: string) => {
const rule = mockPutawayRules.find((r) => r.id === ruleId);
if (rule) {
setFormData({
name: rule.name,
ruleCode: rule.code,
description: rule.description || "",
warehouseId: rule.warehouseId,
materialTypeId: rule.materialTypeId || "",
materialGroupId: rule.materialGroupId || "",
priority: rule.priority,
targetZoneId: rule.targetZoneId || "",
targetLocationId: rule.targetLocationId || "",
strategy: rule.strategy,
isActive: rule.isActive,
});
}
setEditingRuleId(ruleId);
setShowRuleForm(true);
};
const handleNewRule = () => {
resetForm();
setEditingRuleId(null);
setShowRuleForm(true);
};
const handleCloseForm = () => {
setShowRuleForm(false);
setEditingRuleId(null);
resetForm();
};
const handleSubmitForm = () => {
// Form validation and submission logic here
console.log("Form Data:", formData);
handleCloseForm();
};
const filteredRules = mockPutawayRules.filter((rule) => {
const matchesSearch =
rule.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
rule.code.toLowerCase().includes(searchTerm.toLowerCase());
const matchesStrategy =
selectedStrategy === "" || rule.strategy === selectedStrategy;
return matchesSearch && matchesStrategy;
});
const RuleDetailModal = () => {
const rule = mockPutawayRules.find((r) => r.id === selectedRule);
if (!selectedRule || !rule) return null;
return (
<div className="fixed inset-0 z-50 overflow-y-auto">
<div className="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<div
className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"
onClick={() => setSelectedRule("")}
/>
<div className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-4xl sm:w-full">
<div className="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-medium text-gray-900">
{rule.name} - Kural Detayları
</h3>
<button
onClick={() => setSelectedRule("")}
className="text-gray-400 hover:text-gray-600"
>
<svg
className="w-5 h-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{/* Rule Info */}
<div className="bg-gray-50 rounded-lg p-3">
<h4 className="font-medium text-sm text-gray-900 mb-2">
Kural Bilgileri
</h4>
<div className="space-y-2 text-sm">
<div>
<strong>Kod:</strong> {rule.code}
</div>
<div>
<strong>ıklama:</strong> {rule.description}
</div>
<div>
<strong>Öncelik:</strong> {rule.priority}
</div>
<div>
<strong>Strateji:</strong>
<span
className={`ml-2 inline-flex px-2 py-1 text-xs font-medium rounded-full ${getPutawayStrategyColor(
rule.strategy
)}`}
>
{getPutawayStrategyText(rule.strategy)}
</span>
</div>
<div>
<strong>Durum:</strong>
{rule.isActive ? (
<span className="ml-2 inline-flex items-center px-2 py-1 text-xs font-medium rounded-full bg-green-100 text-green-800">
<FaCheckCircle className="w-3 h-3 mr-1" />
Aktif
</span>
) : (
<span className="ml-2 inline-flex items-center px-2 py-1 text-xs font-medium rounded-full bg-red-100 text-red-800">
<FaExclamationCircle className="w-3 h-3 mr-1" />
Pasif
</span>
)}
</div>
</div>
</div>
{/* Conditions */}
<div className="bg-gray-50 rounded-lg p-3">
<h4 className="font-medium text-sm text-gray-900 mb-2">
Koşullar ({rule.conditions.length})
</h4>
<div className="space-y-2">
{rule.conditions.map((condition, index) => (
<div
key={condition.id}
className="bg-white rounded p-2 border"
>
<div className="flex items-center justify-between">
<span className="text-sm font-medium">
Koşul {index + 1}
</span>
</div>
<div className="mt-2 text-sm text-gray-600">
<div className="flex items-center gap-2">
<span className="bg-blue-100 text-blue-800 px-1.5 py-0.5 rounded text-xs">
{getConditionTypeText(condition.conditionType)}
</span>
<FaArrowDown className="w-3 h-3 text-gray-400" />
<span className="bg-gray-100 text-gray-800 px-1.5 py-0.5 rounded text-xs">
{getConditionOperatorText(condition.operator)}
</span>
<FaArrowDown className="w-3 h-3 text-gray-400" />
<span className="bg-green-100 text-green-800 px-1.5 py-0.5 rounded text-xs">
{condition.value}
</span>
</div>
</div>
</div>
))}
{rule.conditions.length === 0 && (
<div className="text-sm text-gray-500 text-center py-4">
Koşul tanımlanmamış
</div>
)}
</div>
</div>
</div>
{/* Target Info */}
<div className="mt-4 bg-gray-50 rounded-lg p-3">
<h4 className="font-medium text-sm text-gray-900 mb-2">
Hedef Lokasyon
</h4>
<div className="grid grid-cols-1 md:grid-cols-3 gap-3 text-sm">
<div>
<strong>Depo:</strong> {getWarehouseName(rule.warehouseId)}
</div>
<div>
<strong>Hedef Bölge:</strong>{" "}
{getZoneName(rule.targetZoneId)}
</div>
<div>
<strong>Hedef Lokasyon:</strong>{" "}
{getLocationName(rule.targetLocationId)}
</div>
{rule.materialTypeId && (
<div>
<strong>Malzeme Tipi:</strong>{" "}
{getMaterialTypeName(rule.materialTypeId)}
</div>
)}
{rule.materialGroupId && (
<div>
<strong>Malzeme Grubu:</strong>{" "}
{getMaterialGroupName(rule.materialGroupId)}
</div>
)}
</div>
</div>
</div>
</div>
</div>
</div>
);
};
return (
<div className="space-y-4 pt-2">
<div className="flex items-center justify-between">
<div>
<h2 className="text-xl font-bold text-gray-900">
Yerleştirme Kuralları
</h2>
<p className="text-sm text-gray-600 mt-1">
Malzeme yerleştirme kurallarını tanımlayın ve yönetin
</p>
</div>
<div className="flex items-center gap-2">
{/* View Mode Toggle */}
<div className="flex items-center bg-gray-100 rounded-lg p-1">
<button
onClick={() => setViewMode("grid")}
className={`p-1.5 rounded-md ${
viewMode === "grid"
? "bg-white text-blue-600 shadow-sm"
: "text-gray-500 hover:text-gray-700"
}`}
title="Kart Görünümü"
>
<FaTh className="w-4 h-4" />
</button>
<button
onClick={() => setViewMode("list")}
className={`p-1.5 rounded-md ${
viewMode === "list"
? "bg-white text-blue-600 shadow-sm"
: "text-gray-500 hover:text-gray-700"
}`}
title="Liste Görünümü"
>
<FaList className="w-4 h-4" />
</button>
</div>
<button
onClick={handleNewRule}
className="bg-blue-600 text-white px-4 py-1.5 text-sm rounded-lg hover:bg-blue-700 flex items-center gap-2"
>
<FaPlus className="w-4 h-4" />
Yeni Kural
</button>
</div>
</div>
{/* Filters */}
<div className="flex flex-col sm:flex-row gap-4">
<div className="relative flex-1">
<FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
<input
type="text"
placeholder="Kural ara..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10 pr-4 py-1.5 text-sm w-full border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/>
</div>
<select
value={selectedStrategy}
onChange={(e) =>
setSelectedStrategy(e.target.value as PutawayStrategyEnum | "")
}
className="px-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<option value="">Tüm Stratejiler</option>
{Object.values(PutawayStrategyEnum).map((strategy) => (
<option key={strategy} value={strategy}>
{getPutawayStrategyText(strategy)}
</option>
))}
</select>
<button className="bg-gray-600 text-white px-4 py-1.5 text-sm rounded-lg hover:bg-gray-700 flex items-center gap-2">
<FaFilter className="w-4 h-4" />
Filtrele
</button>
</div>
{/* Rules Display */}
{viewMode === "grid" ? (
// Grid View (Kart Görünümü)
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{filteredRules.map((rule) => (
<div
key={rule.id}
className="bg-white rounded-lg shadow-sm border border-gray-200 p-3"
>
<div className="flex items-start justify-between mb-3">
<div className="flex items-center gap-2">
<div className="p-2 bg-blue-100 rounded-lg">
<FaCog className="w-5 h-5 text-blue-600" />
</div>
<div>
<h3 className="font-medium text-gray-900">{rule.name}</h3>
<p className="text-sm text-gray-500">{rule.code}</p>
</div>
</div>
<div className="flex items-center gap-2">
<span className="bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full">
Öncelik: {rule.priority}
</span>
{rule.isActive ? (
<FaCheckCircle className="w-4 h-4 text-green-500" />
) : (
<FaExclamationCircle className="w-4 h-4 text-red-500" />
)}
</div>
</div>
<div className="space-y-3">
<div className="text-xs text-gray-600">
<p>{rule.description}</p>
</div>
<span
className={`inline-flex px-2 py-1 text-xs font-medium rounded-full ${getPutawayStrategyColor(
rule.strategy
)}`}
>
{getPutawayStrategyText(rule.strategy)}
</span>
{/* Conditions Summary */}
<h4 className="text-xs font-medium text-gray-900">
Koşullar ({rule.conditions.length})
</h4>
{rule.conditions.length > 0 ? (
<div className="space-y-1">
{rule.conditions.slice(0, 2).map((condition) => (
<div
key={condition.id}
className="text-xs text-gray-600 bg-gray-50 rounded p-1.5"
>
<div className="flex items-center gap-1">
<span className="font-medium">
{getConditionTypeText(condition.conditionType)}
</span>
<span>
{getConditionOperatorText(condition.operator)}
</span>
<span className="font-medium">{condition.value}</span>
</div>
</div>
))}
{rule.conditions.length > 2 && (
<div className="text-xs text-gray-500">
+{rule.conditions.length - 2} koşul daha
</div>
)}
</div>
) : (
<div className="text-xs text-gray-500">
Koşul tanımlanmamış
</div>
)}
{/* Target Info */}
<h4 className="text-xs font-medium">Hedef</h4>
<div>
<div className="bg-gray-50 rounded p-2">
<div className="text-xs text-gray-600 space-y-0.5">
<div>Depo: {getWarehouseName(rule.warehouseId)}</div>
{rule.targetZoneId && (
<div>Bölge: {getZoneName(rule.targetZoneId)}</div>
)}
{rule.targetLocationId && (
<div>
Lokasyon: {getLocationName(rule.targetLocationId)}
</div>
)}
{rule.materialTypeId && (
<div>
Malzeme Tipi:{" "}
{getMaterialTypeName(rule.materialTypeId)}
</div>
)}
{rule.materialGroupId && (
<div>
Malzeme Grubu:{" "}
{getMaterialGroupName(rule.materialGroupId)}
</div>
)}
</div>
</div>
</div>
</div>
<div className="flex items-center justify-between pt-3 mt-3 border-t border-gray-100">
<div className="flex items-center gap-2">
{rule.isActive ? (
<>
<FaCheckCircle className="w-4 h-4 text-green-500" />
<span className="text-sm text-green-600">Aktif</span>
</>
) : (
<>
<FaExclamationCircle className="w-4 h-4 text-red-500" />
<span className="text-sm text-red-600">Pasif</span>
</>
)}
</div>
<div className="flex items-center gap-2">
<button
onClick={() => setSelectedRule(rule.id)}
className="p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-md"
>
<FaBullseye className="w-4 h-4" />
</button>
<button
onClick={() => handleEditRule(rule.id)}
className="p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-md"
>
<FaEdit className="w-4 h-4" />
</button>
<button className="p-1.5 text-gray-400 hover:text-red-600 hover:bg-red-50 rounded-md">
<FaTrash className="w-4 h-4" />
</button>
</div>
</div>
</div>
))}
</div>
) : (
// List View (Liste Görünümü)
<div className="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Kural
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Strateji
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Depo
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Hedef Lokasyon
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Koşullar
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Öncelik
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Durum
</th>
<th className="px-3 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
İşlemler
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{filteredRules.map((rule) => (
<tr key={rule.id} className="hover:bg-gray-50">
<td className="px-3 py-2 whitespace-nowrap">
<div className="flex items-center">
<div className="p-2 bg-blue-100 rounded-lg mr-3">
<FaCog className="w-4 h-4 text-blue-600" />
</div>
<div>
<div
className="text-sm font-medium text-gray-900 max-w-[150px] truncate"
title={rule.name}
>
{rule.name}
</div>
<div className="text-sm text-gray-500">
{rule.code}
</div>
</div>
</div>
</td>
<td className="px-3 py-2 whitespace-nowrap">
<span
className={`inline-flex px-2 py-1 text-xs font-medium rounded-full ${getPutawayStrategyColor(
rule.strategy
)}`}
>
{getPutawayStrategyText(rule.strategy)}
</span>
</td>
<td className="px-3 py-2 whitespace-nowrap text-sm text-gray-900">
{getWarehouseName(rule.warehouseId)}
</td>
<td className="px-3 py-2 whitespace-nowrap text-sm text-gray-900">
<div className="space-y-1">
{rule.targetZoneId && (
<div>Bölge: {getZoneName(rule.targetZoneId)}</div>
)}
{rule.targetLocationId && (
<div>
Lokasyon: {getLocationName(rule.targetLocationId)}
</div>
)}
</div>
</td>
<td className="px-3 py-2 whitespace-nowrap text-sm text-gray-500">
{rule.conditions.length > 0 ? (
<div className="space-y-1">
{rule.conditions.slice(0, 1).map((condition) => (
<div key={condition.id} className="text-xs">
{getConditionTypeText(condition.conditionType)}{" "}
{getConditionOperatorText(condition.operator)}{" "}
{condition.value}
</div>
))}
{rule.conditions.length > 1 && (
<div className="text-xs text-gray-400">
+{rule.conditions.length - 1} koşul daha
</div>
)}
</div>
) : (
<span className="text-gray-400">Koşul yok</span>
)}
</td>
<td className="px-3 py-2 whitespace-nowrap">
<span className="bg-gray-100 text-gray-800 text-xs px-2 py-1 rounded-full">
{rule.priority}
</span>
</td>
<td className="px-3 py-2 whitespace-nowrap">
<div className="flex items-center">
{rule.isActive ? (
<>
<FaCheckCircle className="w-4 h-4 text-green-500 mr-2" />
<span className="text-sm text-green-600">
Aktif
</span>
</>
) : (
<>
<FaExclamationCircle className="w-4 h-4 text-red-500 mr-2" />
<span className="text-sm text-red-600">Pasif</span>
</>
)}
</div>
</td>
<td className="px-3 py-2 whitespace-nowrap text-right text-sm text-gray-500">
<div className="flex items-center gap-2">
<button
onClick={() => setSelectedRule(rule.id)}
className="p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-md"
title="Görüntüle"
>
<FaBullseye className="w-4 h-4" />
</button>
<button
onClick={() => handleEditRule(rule.id)}
className="p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-md"
title="Düzenle"
>
<FaEdit className="w-4 h-4" />
</button>
<button
className="p-1.5 text-gray-400 hover:text-red-600 hover:bg-red-50 rounded-md"
title="Sil"
>
<FaTrash className="w-4 h-4" />
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{filteredRules.length === 0 && (
<div className="text-center py-12">
<FaCog className="w-12 h-12 text-gray-400 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2">
Kural bulunamadı
</h3>
<p className="text-gray-500 mb-4">
Arama kriterlerinize uygun yerleştirme kuralı bulunamadı.
</p>
<button
onClick={handleNewRule}
className="bg-blue-600 text-white px-4 py-1.5 text-sm rounded-lg hover:bg-blue-700"
>
İlk Kuralı Oluştur
</button>
</div>
)}
{/* Rule Detail Modal */}
<RuleDetailModal />
{/* Rule Form Modal */}
{showRuleForm && (
<div className="fixed inset-0 z-50 overflow-y-auto">
<div className="flex min-h-screen pt-4 px-4 pb-20 text-left sm:block sm:p-0">
<div
className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"
onClick={() => {
setShowRuleForm(false);
setEditingRuleId(null);
}}
/>
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg w-full max-w-4xl mx-4 max-h-[90vh] overflow-y-auto">
<div className="flex items-center justify-between p-4 border-b">
<h3 className="text-base font-medium text-gray-900">
{editingRuleId
? "Yerleştirme Kuralını Güncelle"
: "Yeni Yerleştirme Kuralı"}
</h3>
<button
onClick={handleCloseForm}
className="text-gray-400 hover:text-gray-600 p-1 rounded-full"
>
<svg
className="w-6 h-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
{/* Form Content */}
<form className="space-y-4 p-4">
{/* Basic Information */}
<div className="space-y-3">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Kural Adı *
</label>
<input
type="text"
value={formData.name}
onChange={(e) =>
setFormData({ ...formData, name: e.target.value })
}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Kural adını girin"
required
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Kural Kodu *
</label>
<input
type="text"
value={formData.ruleCode}
onChange={(e) =>
setFormData({ ...formData, ruleCode: e.target.value })
}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="PR001"
required
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
ıklama
</label>
<textarea
value={formData.description}
onChange={(e) =>
setFormData({
...formData,
description: e.target.value,
})
}
rows={2}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="Kural açıklaması"
/>
</div>
{/* Warehouse and Location Settings */}
<div className="border-t pt-4">
<h4 className="text-base font-medium text-gray-900 mb-2">
Lokasyon Ayarları
</h4>
<div className="space-y-3">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Depo *
</label>
<select
value={formData.warehouseId}
onChange={(e) => {
setFormData({
...formData,
warehouseId: e.target.value,
targetZoneId: "",
targetLocationId: "",
});
}}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
>
<option value="">Depo seçin</option>
{mockWarehouses.map((warehouse) => (
<option key={warehouse.id} value={warehouse.id}>
{warehouse.name}
</option>
))}
</select>
</div>
{formData.warehouseId && (
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Hedef Bölge
</label>
<select
value={formData.targetZoneId}
onChange={(e) => {
setFormData({
...formData,
targetZoneId: e.target.value,
targetLocationId: "",
});
}}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Bölge seçin</option>
{mockZones
.filter(
(zone) =>
zone.warehouseId === formData.warehouseId
)
.map((zone) => (
<option key={zone.id} value={zone.id}>
{zone.name}
</option>
))}
</select>
</div>
)}
{formData.targetZoneId && (
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Hedef Lokasyon
</label>
<select
value={formData.targetLocationId}
onChange={(e) =>
setFormData({
...formData,
targetLocationId: e.target.value,
})
}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Lokasyon seçin</option>
{mockLocations
.filter(
(location) =>
location.zoneId === formData.targetZoneId
)
.map((location) => (
<option key={location.id} value={location.id}>
{location.name}
</option>
))}
</select>
</div>
)}
</div>
</div>
{/* Material Settings */}
<div className="border-t pt-4">
<h4 className="text-base font-medium text-gray-900 mb-2">
Malzeme Ayarları
</h4>
<div className="space-y-3">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Malzeme Tipi
</label>
<select
value={formData.materialTypeId}
onChange={(e) =>
setFormData({
...formData,
materialTypeId: e.target.value,
})
}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Malzeme tipi seçin</option>
{mockMaterialTypes.map((type) => (
<option key={type.id} value={type.id}>
{type.name}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Malzeme Grubu
</label>
<select
value={formData.materialGroupId}
onChange={(e) =>
setFormData({
...formData,
materialGroupId: e.target.value,
})
}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Malzeme grubu seçin</option>
{mockMaterialGroups.map((group) => (
<option key={group.id} value={group.id}>
{group.name}
</option>
))}
</select>
</div>
</div>
</div>
{/* Strategy and Priority */}
<div className="border-t pt-4">
<h4 className="text-base font-medium text-gray-900 mb-2">
Strateji ve Öncelik
</h4>
<div className="space-y-3">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Yerleştirme Stratejisi *
</label>
<select
value={formData.strategy}
onChange={(e) =>
setFormData({
...formData,
strategy: e.target.value as PutawayStrategyEnum,
})
}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
>
<option value={PutawayStrategyEnum.FIFO}>
İlk Giren İlk Çıkar (FIFO)
</option>
<option value={PutawayStrategyEnum.LIFO}>
Son Giren İlk Çıkar (LIFO)
</option>
<option value={PutawayStrategyEnum.NearestLocation}>
En Yakın Lokasyon
</option>
<option value={PutawayStrategyEnum.EmptyLocation}>
Boş Lokasyon
</option>
<option value={PutawayStrategyEnum.SameProduct}>
Aynı Ürün Gruplaması
</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Öncelik *
</label>
<input
type="number"
min="1"
max="100"
value={formData.priority}
onChange={(e) =>
setFormData({
...formData,
priority: parseInt(e.target.value) || 1,
})
}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
required
/>
</div>
</div>
</div>
{/* Status */}
<div className="border-t pt-4">
<div className="flex items-center">
<input
type="checkbox"
id="isActive"
checked={formData.isActive}
onChange={(e) =>
setFormData({
...formData,
isActive: e.target.checked,
})
}
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
/>
<label
htmlFor="isActive"
className="ml-2 block text-sm text-gray-900"
>
Bu kural aktif
</label>
</div>
</div>
</form>
{/* Form Actions */}
<div className="flex items-center justify-end gap-2 mt-4 pt-4 border-t p-4">
<button
type="button"
onClick={handleCloseForm}
className="px-4 py-1.5 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500"
>
İptal
</button>
<button
type="button"
onClick={handleSubmitForm}
className="px-4 py-1.5 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500"
>
{editingRuleId ? "Güncelle" : "Kaydet"}
</button>
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
};
export default PutawayRules;