erp-platform/ui/src/views/warehouse/components/PutawayRules.tsx

976 lines
42 KiB
TypeScript
Raw Normal View History

2025-09-15 21:11:40 +00:00
import React, { useState } from 'react'
import { PutawayStrategyEnum } from '../../../types/wm'
2025-09-15 09:31:47 +00:00
import {
FaSearch,
FaPlus,
FaEdit,
FaTrash,
FaCog,
FaBullseye,
FaCheckCircle,
FaExclamationCircle,
FaFilter,
FaArrowDown,
FaTh,
FaList,
2025-09-15 21:11:40 +00:00
} 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'
2025-09-15 09:31:47 +00:00
import {
getPutawayStrategyColor,
getPutawayStrategyText,
getConditionTypeText,
getConditionOperatorText,
2025-09-15 21:11:40 +00:00
} from '../../../utils/erp'
import { Container } from '@/components/shared'
2025-09-15 09:31:47 +00:00
const PutawayRules: React.FC = () => {
2025-09-15 21:11:40 +00:00
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>('')
2025-09-15 09:31:47 +00:00
// Form States
const [formData, setFormData] = useState({
2025-09-15 21:11:40 +00:00
name: '',
ruleCode: '',
description: '',
warehouseId: '',
materialTypeId: '',
materialGroupId: '',
2025-09-15 09:31:47 +00:00
priority: 1,
2025-09-15 21:11:40 +00:00
targetZoneId: '',
targetLocationId: '',
2025-09-15 09:31:47 +00:00
strategy: PutawayStrategyEnum.FIFO,
isActive: true,
2025-09-15 21:11:40 +00:00
})
2025-09-15 09:31:47 +00:00
// Helper functions for names
const getWarehouseName = (warehouseId: string | undefined) => {
2025-09-15 21:11:40 +00:00
if (!warehouseId) return 'Belirtilmemiş'
const warehouse = mockWarehouses.find((w) => w.id === warehouseId)
return warehouse ? warehouse.name : `Depo ${warehouseId}`
}
2025-09-15 09:31:47 +00:00
const getZoneName = (zoneId: string | undefined) => {
2025-09-15 21:11:40 +00:00
if (!zoneId) return 'Belirtilmemiş'
const zone = mockZones.find((z) => z.id === zoneId)
return zone ? zone.name : `Bölge ${zoneId}`
}
2025-09-15 09:31:47 +00:00
const getLocationName = (locationId: string | undefined) => {
2025-09-15 21:11:40 +00:00
if (!locationId) return 'Belirtilmemiş'
const location = mockLocations.find((l) => l.id === locationId)
return location ? location.name : `Lokasyon ${locationId}`
}
2025-09-15 09:31:47 +00:00
const getMaterialTypeName = (materialTypeId: string | undefined) => {
2025-09-15 21:11:40 +00:00
if (!materialTypeId) return 'Belirtilmemiş'
const materialType = mockMaterialTypes.find((mt) => mt.id === materialTypeId)
return materialType ? materialType.name : `Tip ${materialTypeId}`
}
2025-09-15 09:31:47 +00:00
const getMaterialGroupName = (materialGroupId: string | undefined) => {
2025-09-15 21:11:40 +00:00
if (!materialGroupId) return 'Belirtilmemiş'
const materialGroup = mockMaterialGroups.find((mg) => mg.id === materialGroupId)
return materialGroup ? materialGroup.name : `Grup ${materialGroupId}`
}
2025-09-15 09:31:47 +00:00
// Form Functions
const resetForm = () => {
setFormData({
2025-09-15 21:11:40 +00:00
name: '',
ruleCode: '',
description: '',
warehouseId: '',
materialTypeId: '',
materialGroupId: '',
2025-09-15 09:31:47 +00:00
priority: 1,
2025-09-15 21:11:40 +00:00
targetZoneId: '',
targetLocationId: '',
2025-09-15 09:31:47 +00:00
strategy: PutawayStrategyEnum.FIFO,
isActive: true,
2025-09-15 21:11:40 +00:00
})
}
2025-09-15 09:31:47 +00:00
const handleEditRule = (ruleId: string) => {
2025-09-15 21:11:40 +00:00
const rule = mockPutawayRules.find((r) => r.id === ruleId)
2025-09-15 09:31:47 +00:00
if (rule) {
setFormData({
name: rule.name,
ruleCode: rule.code,
2025-09-15 21:11:40 +00:00
description: rule.description || '',
2025-09-15 09:31:47 +00:00
warehouseId: rule.warehouseId,
2025-09-15 21:11:40 +00:00
materialTypeId: rule.materialTypeId || '',
materialGroupId: rule.materialGroupId || '',
2025-09-15 09:31:47 +00:00
priority: rule.priority,
2025-09-15 21:11:40 +00:00
targetZoneId: rule.targetZoneId || '',
targetLocationId: rule.targetLocationId || '',
2025-09-15 09:31:47 +00:00
strategy: rule.strategy,
isActive: rule.isActive,
2025-09-15 21:11:40 +00:00
})
2025-09-15 09:31:47 +00:00
}
2025-09-15 21:11:40 +00:00
setEditingRuleId(ruleId)
setShowRuleForm(true)
}
2025-09-15 09:31:47 +00:00
const handleNewRule = () => {
2025-09-15 21:11:40 +00:00
resetForm()
setEditingRuleId(null)
setShowRuleForm(true)
}
2025-09-15 09:31:47 +00:00
const handleCloseForm = () => {
2025-09-15 21:11:40 +00:00
setShowRuleForm(false)
setEditingRuleId(null)
resetForm()
}
2025-09-15 09:31:47 +00:00
const handleSubmitForm = () => {
// Form validation and submission logic here
2025-09-15 21:11:40 +00:00
console.log('Form Data:', formData)
handleCloseForm()
}
2025-09-15 09:31:47 +00:00
const filteredRules = mockPutawayRules.filter((rule) => {
const matchesSearch =
rule.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
2025-09-15 21:11:40 +00:00
rule.code.toLowerCase().includes(searchTerm.toLowerCase())
const matchesStrategy = selectedStrategy === '' || rule.strategy === selectedStrategy
return matchesSearch && matchesStrategy
})
2025-09-15 09:31:47 +00:00
const RuleDetailModal = () => {
2025-09-15 21:11:40 +00:00
const rule = mockPutawayRules.find((r) => r.id === selectedRule)
2025-09-15 09:31:47 +00:00
2025-09-15 21:11:40 +00:00
if (!selectedRule || !rule) return null
2025-09-15 09:31:47 +00:00
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"
2025-09-15 21:11:40 +00:00
onClick={() => setSelectedRule('')}
2025-09-15 09:31:47 +00:00
/>
<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">
2025-09-15 21:11:40 +00:00
<h3 className="text-lg font-medium text-gray-900">{rule.name} - Kural Detayları</h3>
2025-09-15 09:31:47 +00:00
<button
2025-09-15 21:11:40 +00:00
onClick={() => setSelectedRule('')}
2025-09-15 09:31:47 +00:00
className="text-gray-400 hover:text-gray-600"
>
2025-09-15 21:11:40 +00:00
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
2025-09-15 09:31:47 +00:00
<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">
2025-09-15 21:11:40 +00:00
<h4 className="font-medium text-sm text-gray-900 mb-2">Kural Bilgileri</h4>
2025-09-15 09:31:47 +00:00
<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(
2025-09-15 21:11:40 +00:00
rule.strategy,
2025-09-15 09:31:47 +00:00
)}`}
>
{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) => (
2025-09-15 21:11:40 +00:00
<div key={condition.id} className="bg-white rounded p-2 border">
2025-09-15 09:31:47 +00:00
<div className="flex items-center justify-between">
2025-09-15 21:11:40 +00:00
<span className="text-sm font-medium">Koşul {index + 1}</span>
2025-09-15 09:31:47 +00:00
</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">
2025-09-15 21:11:40 +00:00
<h4 className="font-medium text-sm text-gray-900 mb-2">Hedef Lokasyon</h4>
2025-09-15 09:31:47 +00:00
<div className="grid grid-cols-1 md:grid-cols-3 gap-3 text-sm">
<div>
<strong>Depo:</strong> {getWarehouseName(rule.warehouseId)}
</div>
<div>
2025-09-15 21:11:40 +00:00
<strong>Hedef Bölge:</strong> {getZoneName(rule.targetZoneId)}
2025-09-15 09:31:47 +00:00
</div>
<div>
2025-09-15 21:11:40 +00:00
<strong>Hedef Lokasyon:</strong> {getLocationName(rule.targetLocationId)}
2025-09-15 09:31:47 +00:00
</div>
{rule.materialTypeId && (
<div>
2025-09-15 21:11:40 +00:00
<strong>Malzeme Tipi:</strong> {getMaterialTypeName(rule.materialTypeId)}
2025-09-15 09:31:47 +00:00
</div>
)}
{rule.materialGroupId && (
<div>
2025-09-15 21:11:40 +00:00
<strong>Malzeme Grubu:</strong> {getMaterialGroupName(rule.materialGroupId)}
2025-09-15 09:31:47 +00:00
</div>
)}
</div>
</div>
</div>
</div>
</div>
</div>
2025-09-15 21:11:40 +00:00
)
}
2025-09-15 09:31:47 +00:00
return (
2025-09-15 21:11:40 +00:00
<Container>
<div className="space-y-2">
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900">Yerleştirme Kuralları</h2>
<p className="text-gray-600">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>
2025-09-15 09:31:47 +00:00
<button
2025-09-15 21:11:40 +00:00
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"
2025-09-15 09:31:47 +00:00
>
2025-09-15 21:11:40 +00:00
<FaPlus className="w-4 h-4" />
Yeni Kural
2025-09-15 09:31:47 +00:00
</button>
</div>
</div>
2025-09-15 21:11:40 +00:00
{/* 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>
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 21:11:40 +00:00
{/* 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>
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 21:11:40 +00:00
<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" />
)}
2025-09-15 09:31:47 +00:00
</div>
</div>
2025-09-15 21:11:40 +00:00
<div className="space-y-3">
<div className="text-xs text-gray-600">
<p>{rule.description}</p>
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 21:11:40 +00:00
<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>
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 21:11:40 +00:00
))}
{rule.conditions.length > 2 && (
<div className="text-xs text-gray-500">
+{rule.conditions.length - 2} koşul daha
2025-09-15 09:31:47 +00:00
</div>
)}
</div>
) : (
2025-09-15 21:11:40 +00:00
<div className="text-xs text-gray-500">Koşul tanımlanmamış</div>
2025-09-15 09:31:47 +00:00
)}
2025-09-15 21:11:40 +00:00
{/* 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>
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 21:11:40 +00:00
<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>
2025-09-15 09:31:47 +00:00
</div>
</div>
2025-09-15 21:11:40 +00:00
))}
</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" />
2025-09-15 09:31:47 +00:00
</div>
<div>
2025-09-15 21:11:40 +00:00
<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>
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 21:11:40 +00:00
</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">
2025-09-15 09:31:47 +00:00
<div className="space-y-1">
2025-09-15 21:11:40 +00:00
{rule.targetZoneId && <div>Bölge: {getZoneName(rule.targetZoneId)}</div>}
{rule.targetLocationId && (
<div>Lokasyon: {getLocationName(rule.targetLocationId)}</div>
2025-09-15 09:31:47 +00:00
)}
</div>
2025-09-15 21:11:40 +00:00
</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>
2025-09-15 09:31:47 +00:00
) : (
2025-09-15 21:11:40 +00:00
<span className="text-gray-400">Koşul yok</span>
2025-09-15 09:31:47 +00:00
)}
2025-09-15 21:11:40 +00:00
</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>
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 21:11:40 +00:00
)}
{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>
)}
</div>
2025-09-15 09:31:47 +00:00
{/* 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={() => {
2025-09-15 21:11:40 +00:00
setShowRuleForm(false)
setEditingRuleId(null)
2025-09-15 09:31:47 +00:00
}}
/>
<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">
2025-09-15 21:11:40 +00:00
{editingRuleId ? 'Yerleştirme Kuralını Güncelle' : 'Yeni Yerleştirme Kuralı'}
2025-09-15 09:31:47 +00:00
</h3>
<button
onClick={handleCloseForm}
className="text-gray-400 hover:text-gray-600 p-1 rounded-full"
>
2025-09-15 21:11:40 +00:00
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
2025-09-15 09:31:47 +00:00
<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}
2025-09-15 21:11:40 +00:00
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
2025-09-15 09:31:47 +00:00
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}
2025-09-15 21:11:40 +00:00
onChange={(e) => setFormData({ ...formData, ruleCode: e.target.value })}
2025-09-15 09:31:47 +00:00
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>
2025-09-15 21:11:40 +00:00
<label className="block text-sm font-medium text-gray-700 mb-1">ıklama</label>
2025-09-15 09:31:47 +00:00
<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">
2025-09-15 21:11:40 +00:00
<h4 className="text-base font-medium text-gray-900 mb-2">Lokasyon Ayarları</h4>
2025-09-15 09:31:47 +00:00
<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,
2025-09-15 21:11:40 +00:00
targetZoneId: '',
targetLocationId: '',
})
2025-09-15 09:31:47 +00:00
}}
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,
2025-09-15 21:11:40 +00:00
targetLocationId: '',
})
2025-09-15 09:31:47 +00:00
}}
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
2025-09-15 21:11:40 +00:00
.filter((zone) => zone.warehouseId === formData.warehouseId)
2025-09-15 09:31:47 +00:00
.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
2025-09-15 21:11:40 +00:00
.filter((location) => location.zoneId === formData.targetZoneId)
2025-09-15 09:31:47 +00:00
.map((location) => (
<option key={location.id} value={location.id}>
{location.name}
</option>
))}
</select>
</div>
)}
</div>
</div>
{/* Material Settings */}
<div className="border-t pt-4">
2025-09-15 21:11:40 +00:00
<h4 className="text-base font-medium text-gray-900 mb-2">Malzeme Ayarları</h4>
2025-09-15 09:31:47 +00:00
<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
>
2025-09-17 09:46:58 +00:00
{Object.values(PutawayStrategyEnum).map((strategy) => (
<option key={strategy} value={strategy}>
{getPutawayStrategyText(strategy)}
</option>
))}
2025-09-15 09:31:47 +00:00
</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"
/>
2025-09-15 21:11:40 +00:00
<label htmlFor="isActive" className="ml-2 block text-sm text-gray-900">
2025-09-15 09:31:47 +00:00
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"
>
2025-09-15 21:11:40 +00:00
{editingRuleId ? 'Güncelle' : 'Kaydet'}
2025-09-15 09:31:47 +00:00
</button>
</div>
</div>
</div>
</div>
</div>
)}
2025-09-15 21:11:40 +00:00
</Container>
)
}
2025-09-15 09:31:47 +00:00
2025-09-15 21:11:40 +00:00
export default PutawayRules