erp-platform/ui/src/views/maintenance/components/MaintenancePlanModal.tsx

215 lines
7.7 KiB
TypeScript
Raw Normal View History

2025-09-15 21:29:07 +00:00
import React, { useState } from 'react'
import { FaTimes, FaSave, FaPlus } from 'react-icons/fa'
2025-09-15 09:31:47 +00:00
import {
PmWorkCenter,
MaintenancePlanTypeEnum,
FrequencyUnitEnum,
PmMaintenancePlan,
2025-09-15 21:29:07 +00:00
} from '../../../types/pm'
import { PriorityEnum } from '../../../types/common'
2025-09-15 09:31:47 +00:00
interface MaintenancePlanModalProps {
2025-09-15 21:29:07 +00:00
isOpen: boolean
onClose: () => void
onSave: (planData: PmMaintenancePlan[]) => void
selectedWorkCenters: PmWorkCenter[]
2025-09-15 09:31:47 +00:00
}
const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
isOpen,
onClose,
onSave,
selectedWorkCenters,
}) => {
const [planData, setPlanData] = useState({
planType: MaintenancePlanTypeEnum.Preventive,
2025-09-15 21:29:07 +00:00
description: '',
2025-09-15 09:31:47 +00:00
frequency: 1,
frequencyUnit: FrequencyUnitEnum.Months,
estimatedDuration: 60,
priority: PriorityEnum.Normal,
2025-09-15 21:29:07 +00:00
instructions: '',
2025-09-15 09:31:47 +00:00
requiredSkills: [] as string[],
nextDue: new Date(),
2025-09-15 21:29:07 +00:00
})
2025-09-15 09:31:47 +00:00
2025-09-15 21:29:07 +00:00
const [newSkill, setNewSkill] = useState('')
2025-09-15 09:31:47 +00:00
2025-09-15 21:29:07 +00:00
if (!isOpen) return null
2025-09-15 09:31:47 +00:00
const handleInputChange = (
2025-09-15 21:29:07 +00:00
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>,
2025-09-15 09:31:47 +00:00
) => {
2025-09-15 21:29:07 +00:00
const { name, value, type } = e.target
2025-09-15 09:31:47 +00:00
setPlanData((prev) => ({
...prev,
2025-09-15 21:29:07 +00:00
[name]: type === 'date' ? new Date(value) : type === 'number' ? Number(value) : value,
}))
}
2025-09-15 09:31:47 +00:00
const addSkill = () => {
if (newSkill.trim() && !planData.requiredSkills.includes(newSkill.trim())) {
setPlanData((prev) => ({
...prev,
requiredSkills: [...prev.requiredSkills, newSkill.trim()],
2025-09-15 21:29:07 +00:00
}))
setNewSkill('')
2025-09-15 09:31:47 +00:00
}
2025-09-15 21:29:07 +00:00
}
2025-09-15 09:31:47 +00:00
const removeSkill = (skillToRemove: string) => {
setPlanData((prev) => ({
...prev,
2025-09-15 21:29:07 +00:00
requiredSkills: prev.requiredSkills.filter((skill) => skill !== skillToRemove),
}))
}
2025-09-15 09:31:47 +00:00
const handleSave = () => {
const plansToCreate = selectedWorkCenters.map((workCenter) => ({
id: `MP${Date.now()}-${workCenter.id}`,
planCode: `MP-${workCenter.code}-${Date.now()}`,
workCenterId: workCenter.id,
workCenter: workCenter,
...planData,
requiredMaterials: [],
isActive: true,
creationTime: new Date(),
lastModificationTime: new Date(),
2025-09-15 21:29:07 +00:00
}))
2025-09-15 09:31:47 +00:00
2025-09-15 21:29:07 +00:00
onSave(plansToCreate)
onClose()
}
2025-09-15 09:31:47 +00:00
return (
<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-2xl mx-4 max-h-[90vh] overflow-y-auto">
{/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200">
<h2 className="text-lg font-semibold text-gray-900">
Bakım Planı Oluştur ({selectedWorkCenters.length} merkezi)
</h2>
2025-09-15 21:29:07 +00:00
<button onClick={onClose} className="p-2 hover:bg-gray-100 rounded-lg transition-colors">
2025-09-15 09:31:47 +00:00
<FaTimes className="w-5 h-5 text-gray-500" />
</button>
</div>
{/* Content */}
<div className="p-4 space-y-4">
{/* Selected Work Center List */}
<div>
2025-09-15 21:29:07 +00:00
<h3 className="text-sm font-medium text-gray-900 mb-2">Seçili İş Merkezleri</h3>
2025-09-15 09:31:47 +00:00
<div className="max-h-28 overflow-y-auto bg-gray-50 rounded-lg p-2">
{selectedWorkCenters.map((workCenter) => (
2025-09-15 21:29:07 +00:00
<div key={workCenter.id} className="flex items-center justify-between py-0.5">
2025-09-15 09:31:47 +00:00
<span className="text-sm text-gray-700">
{workCenter.code} - {workCenter.name}
</span>
2025-09-15 21:29:07 +00:00
<span className="text-xs text-gray-500">{workCenter.location}</span>
2025-09-15 09:31:47 +00:00
</div>
))}
</div>
</div>
{/* Plan Details */}
<div>
2025-09-15 21:29:07 +00:00
<h3 className="text-sm font-medium text-gray-900 mb-2">Plan Detayları</h3>
2025-09-15 09:31:47 +00:00
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-1">Plan Tipi</label>
2025-09-15 09:31:47 +00:00
<select
name="planType"
value={planData.planType}
onChange={handleInputChange}
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-blue-500"
>
2025-09-15 21:29:07 +00:00
<option value={MaintenancePlanTypeEnum.Preventive}>Önleyici Bakım</option>
<option value={MaintenancePlanTypeEnum.Predictive}>Kestirimci Bakım</option>
<option value={MaintenancePlanTypeEnum.Corrective}>Düzeltici Bakım</option>
<option value={MaintenancePlanTypeEnum.Condition}>Durum Bazlı Bakım</option>
2025-09-15 09:31:47 +00:00
</select>
</div>
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-1">Öncelik</label>
2025-09-15 09:31:47 +00:00
<select
name="priority"
value={planData.priority}
onChange={handleInputChange}
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-blue-500"
>
<option value={PriorityEnum.Low}>Düşük</option>
<option value={PriorityEnum.Normal}>Normal</option>
<option value={PriorityEnum.High}>Yüksek</option>
<option value={PriorityEnum.Urgent}>Acil</option>
</select>
</div>
</div>
</div>
{/* Required Skills */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Gerekli Yetenekler
</label>
<div className="flex space-x-2 mb-2">
<input
type="text"
value={newSkill}
onChange={(e) => setNewSkill(e.target.value)}
placeholder="Yetenek ekle..."
className="flex-1 px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
2025-09-15 21:29:07 +00:00
onKeyPress={(e) => e.key === 'Enter' && addSkill()}
2025-09-15 09:31:47 +00:00
/>
<button
type="button"
onClick={addSkill}
className="px-3 py-1.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
>
<FaPlus className="w-4 h-4" />
</button>
</div>
<div className="flex flex-wrap gap-2">
{planData.requiredSkills.map((skill, index) => (
<span
key={index}
className="inline-flex items-center px-2 py-1 bg-blue-100 text-blue-800 rounded-full text-xs"
>
{skill}
<button
type="button"
onClick={() => removeSkill(skill)}
className="ml-2 text-blue-600 hover:text-blue-800"
>
×
</button>
</span>
))}
</div>
</div>
</div>
{/* Footer */}
<div className="flex items-center justify-end space-x-3 p-4 border-t border-gray-200">
<button
type="button"
onClick={onClose}
className="px-3 py-1.5 text-sm text-gray-600 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
>
İptal
</button>
<button
type="button"
onClick={handleSave}
className="flex items-center space-x-2 px-3 py-1.5 text-sm bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors"
>
<FaSave className="w-4 h-4" />
<span>Bakım Planı Oluştur</span>
</button>
</div>
</div>
</div>
2025-09-15 21:29:07 +00:00
)
}
2025-09-15 09:31:47 +00:00
2025-09-15 21:29:07 +00:00
export default MaintenancePlanModal