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

780 lines
31 KiB
TypeScript
Raw Normal View History

2025-09-15 21:29:07 +00:00
import React, { useState, useEffect } from 'react'
import { FaTimes, FaPlus, FaTrash, FaCalendar, FaClock, FaSave } from 'react-icons/fa'
2025-09-15 09:31:47 +00:00
import {
PmMaintenanceWorkOrder,
WorkOrderTypeEnum,
WorkOrderStatusEnum,
PmWorkOrderMaterial,
PmWorkOrderActivity,
2025-09-15 21:29:07 +00:00
} from '../../../types/pm'
import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
import { mockMaintenanceTeams } from '../../../mocks/mockMaintenanceTeams'
import { mockEmployees } from '../../../mocks/mockEmployees'
import { mockMaterials } from '../../../mocks/mockMaterials'
import { PriorityEnum } from '../../../types/common'
2025-09-17 09:46:58 +00:00
import { getPriorityText, getWorkOrderStatusText, getWorkOrderTypeText } from '@/utils/erp'
2025-09-15 09:31:47 +00:00
interface EditWorkOrderModalProps {
2025-09-15 21:29:07 +00:00
isOpen: boolean
onClose: () => void
onSave: (workOrder: PmMaintenanceWorkOrder) => void
workOrder: PmMaintenanceWorkOrder
2025-09-15 09:31:47 +00:00
}
const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
isOpen,
onClose,
onSave,
workOrder,
}) => {
const [formData, setFormData] = useState({
2025-09-15 21:29:07 +00:00
workOrderNumber: '',
workCenterId: '',
2025-09-15 09:31:47 +00:00
orderType: WorkOrderTypeEnum.Corrective,
priority: PriorityEnum.Normal,
status: WorkOrderStatusEnum.Created,
2025-09-15 21:29:07 +00:00
description: '',
reportedBy: '',
assignedTo: '',
maintenanceTeamId: '',
scheduledStart: '',
scheduledEnd: '',
actualStart: '',
actualEnd: '',
2025-09-15 09:31:47 +00:00
estimatedCost: 0,
actualCost: 0,
2025-09-15 21:29:07 +00:00
notes: '',
completionNotes: '',
})
2025-09-15 09:31:47 +00:00
2025-09-15 21:29:07 +00:00
const [materials, setMaterials] = useState<PmWorkOrderMaterial[]>([])
const [activities, setActivities] = useState<PmWorkOrderActivity[]>([])
const [errors, setErrors] = useState<Record<string, string>>({})
2025-09-15 09:31:47 +00:00
useEffect(() => {
if (workOrder && isOpen) {
setFormData({
workOrderNumber: workOrder.workOrderNumber,
workCenterId: workOrder.workCenterId,
orderType: workOrder.orderType,
priority: workOrder.priority,
status: workOrder.status,
description: workOrder.description,
reportedBy: workOrder.reportedBy,
2025-09-15 21:29:07 +00:00
assignedTo: workOrder.assignedTo || '',
maintenanceTeamId: workOrder.maintenanceTeamId || '',
2025-09-15 09:31:47 +00:00
scheduledStart: workOrder.scheduledStart
? workOrder.scheduledStart.toISOString().slice(0, 16)
2025-09-15 21:29:07 +00:00
: '',
2025-09-15 09:31:47 +00:00
scheduledEnd: workOrder.scheduledEnd
? workOrder.scheduledEnd.toISOString().slice(0, 16)
2025-09-15 21:29:07 +00:00
: '',
actualStart: workOrder.actualStart ? workOrder.actualStart.toISOString().slice(0, 16) : '',
actualEnd: workOrder.actualEnd ? workOrder.actualEnd.toISOString().slice(0, 16) : '',
2025-09-15 09:31:47 +00:00
estimatedCost: workOrder.estimatedCost,
actualCost: workOrder.actualCost,
2025-09-15 21:29:07 +00:00
notes: workOrder.notes || '',
completionNotes: workOrder.completionNotes || '',
})
setMaterials(workOrder.materials)
setActivities(workOrder.activities)
2025-09-15 09:31:47 +00:00
}
2025-09-15 21:29:07 +00:00
}, [workOrder, isOpen])
2025-09-15 09:31:47 +00:00
const validateForm = () => {
2025-09-15 21:29:07 +00:00
const newErrors: Record<string, string> = {}
2025-09-15 09:31:47 +00:00
if (!formData.description.trim()) {
2025-09-15 21:29:07 +00:00
newErrors.description = 'Açıklama alanı zorunludur'
2025-09-15 09:31:47 +00:00
}
if (!formData.workCenterId) {
2025-09-15 21:29:07 +00:00
newErrors.workCenterId = 'İş merkezi seçimi zorunludur'
2025-09-15 09:31:47 +00:00
}
if (!formData.reportedBy.trim()) {
2025-09-15 21:29:07 +00:00
newErrors.reportedBy = 'Bildiren kişi zorunludur'
2025-09-15 09:31:47 +00:00
}
if (formData.estimatedCost < 0) {
2025-09-15 21:29:07 +00:00
newErrors.estimatedCost = 'Tahmini maliyet negatif olamaz'
2025-09-15 09:31:47 +00:00
}
if (formData.actualCost < 0) {
2025-09-15 21:29:07 +00:00
newErrors.actualCost = 'Gerçek maliyet negatif olamaz'
2025-09-15 09:31:47 +00:00
}
2025-09-15 21:29:07 +00:00
setErrors(newErrors)
return Object.keys(newErrors).length === 0
}
2025-09-15 09:31:47 +00:00
const handleSubmit = (e: React.FormEvent) => {
2025-09-15 21:29:07 +00:00
e.preventDefault()
if (!validateForm()) return
2025-09-15 09:31:47 +00:00
const updatedWorkOrder: PmMaintenanceWorkOrder = {
...workOrder,
workOrderNumber: formData.workOrderNumber,
workCenterId: formData.workCenterId,
orderType: formData.orderType,
priority: formData.priority,
status: formData.status,
description: formData.description,
reportedBy: formData.reportedBy,
assignedTo: formData.assignedTo || undefined,
maintenanceTeamId: formData.maintenanceTeamId || undefined,
2025-09-15 21:29:07 +00:00
scheduledStart: formData.scheduledStart ? new Date(formData.scheduledStart) : undefined,
scheduledEnd: formData.scheduledEnd ? new Date(formData.scheduledEnd) : undefined,
actualStart: formData.actualStart ? new Date(formData.actualStart) : undefined,
2025-09-15 09:31:47 +00:00
actualEnd: formData.actualEnd ? new Date(formData.actualEnd) : undefined,
estimatedCost: formData.estimatedCost,
actualCost: formData.actualCost,
materials,
activities,
notes: formData.notes || undefined,
completionNotes: formData.completionNotes || undefined,
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(updatedWorkOrder)
onClose()
}
2025-09-15 09:31:47 +00:00
const addMaterial = () => {
const newMaterial: PmWorkOrderMaterial = {
id: `mat-${Date.now()}`,
workOrderId: workOrder.id,
2025-09-15 21:29:07 +00:00
materialId: '',
materialCode: '',
materialName: '',
2025-09-15 09:31:47 +00:00
plannedQuantity: 1,
actualQuantity: 0,
unitCost: 0,
totalCost: 0,
2025-09-15 21:29:07 +00:00
}
setMaterials([...materials, newMaterial])
}
2025-09-15 09:31:47 +00:00
const removeMaterial = (index: number) => {
2025-09-15 21:29:07 +00:00
setMaterials(materials.filter((_, i) => i !== index))
}
const updateMaterial = (index: number, field: string, value: string | number) => {
const updated = [...materials]
if (field === 'materialId') {
const selectedMaterial = mockMaterials.find((m) => m.id === value)
2025-09-15 09:31:47 +00:00
if (selectedMaterial) {
updated[index] = {
...updated[index],
materialId: value as string,
materialCode: selectedMaterial.code,
materialName: selectedMaterial.name,
unitCost: selectedMaterial.costPrice,
2025-09-15 21:29:07 +00:00
totalCost: updated[index].plannedQuantity * selectedMaterial.costPrice,
}
2025-09-15 09:31:47 +00:00
}
} else {
2025-09-15 21:29:07 +00:00
const material = updated[index]
if (field === 'plannedQuantity') {
material.plannedQuantity = value as number
material.totalCost = material.plannedQuantity * material.unitCost
} else if (field === 'actualQuantity') {
material.actualQuantity = value as number
} else if (field === 'unitCost') {
material.unitCost = value as number
material.totalCost = material.plannedQuantity * material.unitCost
2025-09-15 09:31:47 +00:00
}
}
2025-09-15 21:29:07 +00:00
setMaterials(updated)
}
2025-09-15 09:31:47 +00:00
const addActivity = () => {
const newActivity: PmWorkOrderActivity = {
id: `act-${Date.now()}`,
workOrderId: workOrder.id,
2025-09-15 21:29:07 +00:00
activityDescription: '',
2025-09-15 09:31:47 +00:00
plannedDuration: 60,
actualDuration: 0,
2025-09-15 21:29:07 +00:00
performedBy: '',
notes: '',
}
setActivities([...activities, newActivity])
}
2025-09-15 09:31:47 +00:00
const removeActivity = (index: number) => {
2025-09-15 21:29:07 +00:00
setActivities(activities.filter((_, i) => i !== index))
}
const updateActivity = (index: number, field: string, value: string | number) => {
const updated = [...activities]
const activity = updated[index]
if (field === 'activityDescription') {
activity.activityDescription = value as string
} else if (field === 'plannedDuration') {
activity.plannedDuration = value as number
} else if (field === 'actualDuration') {
activity.actualDuration = value as number
} else if (field === 'performedBy') {
activity.performedBy = value as string
} else if (field === 'notes') {
activity.notes = value as string
2025-09-15 09:31:47 +00:00
}
2025-09-15 21:29:07 +00:00
setActivities(updated)
}
2025-09-15 09:31:47 +00:00
const toggleActivityCompletion = (index: number) => {
2025-09-15 21:29:07 +00:00
const updated = [...activities]
const activity = updated[index]
2025-09-15 09:31:47 +00:00
if (activity.completedAt) {
2025-09-15 21:29:07 +00:00
activity.completedAt = undefined
2025-09-15 09:31:47 +00:00
} else {
2025-09-15 21:29:07 +00:00
activity.completedAt = new Date()
2025-09-15 09:31:47 +00:00
}
2025-09-15 21:29:07 +00:00
setActivities(updated)
}
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
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg p-4 w-full max-w-5xl mx-4 max-h-[90vh] overflow-y-auto">
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold text-gray-900 flex items-center">
<FaSave className="w-5 h-5 mr-2 text-blue-600" />
İş Emrini Düzenle
</h3>
2025-09-15 21:29:07 +00:00
<button onClick={onClose} className="text-gray-400 hover:text-gray-600">
2025-09-15 09:31:47 +00:00
<FaTimes className="w-5 h-5" />
</button>
</div>
<form onSubmit={handleSubmit} className="space-y-4">
{/* Basic Information */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-2">İş Emri No</label>
2025-09-15 09:31:47 +00:00
<input
type="text"
value={formData.workOrderNumber}
2025-09-15 21:29:07 +00:00
onChange={(e) => setFormData({ ...formData, workOrderNumber: 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-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
readOnly
/>
</div>
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-2">Durum</label>
2025-09-15 09:31:47 +00:00
<select
value={formData.status}
onChange={(e) =>
setFormData({
...formData,
status: e.target.value as WorkOrderStatusEnum,
})
}
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-17 09:46:58 +00:00
{Object.values(WorkOrderStatusEnum).map((status) => (
<option key={status} value={status}>
{getWorkOrderStatusText(status)}
</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-2">İş Merkezi *</label>
2025-09-15 09:31:47 +00:00
<select
value={formData.workCenterId}
2025-09-15 21:29:07 +00:00
onChange={(e) => setFormData({ ...formData, workCenterId: e.target.value })}
2025-09-15 09:31:47 +00:00
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
2025-09-15 21:29:07 +00:00
errors.workCenterId ? 'border-red-500' : 'border-gray-300'
2025-09-15 09:31:47 +00:00
}`}
>
<option value="">İş Merkezi Seçin</option>
{mockWorkCenters.map((workCenter) => (
<option key={workCenter.id} value={workCenter.id}>
{workCenter.code} - {workCenter.name}
</option>
))}
</select>
{errors.workCenterId && (
2025-09-15 21:29:07 +00:00
<p className="mt-1 text-sm text-red-600">{errors.workCenterId}</p>
2025-09-15 09:31:47 +00:00
)}
</div>
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-2">İş Emri Tipi</label>
2025-09-15 09:31:47 +00:00
<select
value={formData.orderType}
onChange={(e) =>
setFormData({
...formData,
orderType: e.target.value as WorkOrderTypeEnum,
})
}
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-17 09:46:58 +00:00
{Object.values(WorkOrderTypeEnum).map((type) => (
<option key={type} value={type}>
{getWorkOrderTypeText(type)}
</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-2">Öncelik</label>
2025-09-15 09:31:47 +00:00
<select
value={formData.priority}
onChange={(e) =>
setFormData({
...formData,
priority: e.target.value as PriorityEnum,
})
}
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-17 09:46:58 +00:00
{Object.values(PriorityEnum).map((priority) => (
<option key={priority} value={priority}>
{getPriorityText(priority)}
</option>
))}
2025-09-15 09:31:47 +00:00
</select>
</div>
</div>
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-2">ıklama *</label>
2025-09-15 09:31:47 +00:00
<textarea
value={formData.description}
2025-09-15 21:29:07 +00:00
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
2025-09-15 09:31:47 +00:00
rows={2}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
2025-09-15 21:29:07 +00:00
errors.description ? 'border-red-500' : 'border-gray-300'
2025-09-15 09:31:47 +00:00
}`}
placeholder="İş emri açıklaması..."
/>
{errors.description && (
<p className="mt-1 text-sm text-red-600">{errors.description}</p>
)}
</div>
{/* Assignment */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-2">Bildiren *</label>
2025-09-15 09:31:47 +00:00
<input
type="text"
value={formData.reportedBy}
2025-09-15 21:29:07 +00:00
onChange={(e) => setFormData({ ...formData, reportedBy: e.target.value })}
2025-09-15 09:31:47 +00:00
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
2025-09-15 21:29:07 +00:00
errors.reportedBy ? 'border-red-500' : 'border-gray-300'
2025-09-15 09:31:47 +00:00
}`}
placeholder="Bildiren kişi adı"
/>
{errors.reportedBy && (
<p className="mt-1 text-sm text-red-600">{errors.reportedBy}</p>
)}
</div>
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-2">Atanan Kişi</label>
2025-09-15 09:31:47 +00:00
<select
value={formData.assignedTo}
2025-09-15 21:29:07 +00:00
onChange={(e) => setFormData({ ...formData, assignedTo: 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-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="">Kişi Seçin</option>
{mockEmployees.map((employee) => (
<option key={employee.id} value={employee.fullName}>
{employee.fullName} - {employee.jobPosition?.name}
</option>
))}
</select>
</div>
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-2">Bakım Ekibi</label>
2025-09-15 09:31:47 +00:00
<select
value={formData.maintenanceTeamId}
onChange={(e) =>
setFormData({
...formData,
maintenanceTeamId: 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-blue-500"
>
<option value="">Ekip Seçin</option>
{mockMaintenanceTeams.map((team) => (
<option key={team.id} value={team.id}>
{team.name}
</option>
))}
</select>
</div>
</div>
{/* Schedule */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
<FaCalendar className="w-4 h-4 inline mr-2" />
Planlanan Başlangıç
</label>
<input
type="datetime-local"
value={formData.scheduledStart}
2025-09-15 21:29:07 +00:00
onChange={(e) => setFormData({ ...formData, scheduledStart: 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-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
<FaCalendar className="w-4 h-4 inline mr-2" />
Planlanan Bitiş
</label>
<input
type="datetime-local"
value={formData.scheduledEnd}
2025-09-15 21:29:07 +00:00
onChange={(e) => setFormData({ ...formData, scheduledEnd: 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-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
<FaCalendar className="w-4 h-4 inline mr-2" />
Gerçek Başlangıç
</label>
<input
type="datetime-local"
value={formData.actualStart}
2025-09-15 21:29:07 +00:00
onChange={(e) => setFormData({ ...formData, actualStart: 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-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
<FaCalendar className="w-4 h-4 inline mr-2" />
Gerçek Bitiş
</label>
<input
type="datetime-local"
value={formData.actualEnd}
2025-09-15 21:29:07 +00:00
onChange={(e) => setFormData({ ...formData, actualEnd: 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-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
</div>
{/* Costs */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Tahmini Maliyet
</label>
<input
type="number"
min="0"
step="0.01"
value={formData.estimatedCost}
onChange={(e) =>
setFormData({
...formData,
estimatedCost: parseFloat(e.target.value) || 0,
})
}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
2025-09-15 21:29:07 +00:00
errors.estimatedCost ? 'border-red-500' : 'border-gray-300'
2025-09-15 09:31:47 +00:00
}`}
placeholder="0.00"
/>
{errors.estimatedCost && (
2025-09-15 21:29:07 +00:00
<p className="mt-1 text-sm text-red-600">{errors.estimatedCost}</p>
2025-09-15 09:31:47 +00:00
)}
</div>
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-2">Gerçek Maliyet</label>
2025-09-15 09:31:47 +00:00
<input
type="number"
min="0"
step="0.01"
value={formData.actualCost}
onChange={(e) =>
setFormData({
...formData,
actualCost: parseFloat(e.target.value) || 0,
})
}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
2025-09-15 21:29:07 +00:00
errors.actualCost ? 'border-red-500' : 'border-gray-300'
2025-09-15 09:31:47 +00:00
}`}
placeholder="0.00"
/>
{errors.actualCost && (
<p className="mt-1 text-sm text-red-600">{errors.actualCost}</p>
)}
</div>
</div>
{/* Materials */}
<div>
<div className="flex items-center justify-between mb-4">
<h4 className="text-lg font-medium text-gray-900">Malzemeler</h4>
<button
type="button"
onClick={addMaterial}
className="bg-blue-600 text-white px-3 py-1.5 text-sm rounded-lg hover:bg-blue-700 flex items-center space-x-2"
>
<FaPlus className="w-4 h-4" />
<span>Malzeme Ekle</span>
</button>
</div>
{materials.map((material, index) => (
2025-09-15 21:29:07 +00:00
<div key={material.id || index} className="bg-gray-50 p-3 rounded-lg mb-2">
2025-09-15 09:31:47 +00:00
<div className="grid grid-cols-1 md:grid-cols-6 gap-4">
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-1">Malzeme</label>
2025-09-15 09:31:47 +00:00
<select
value={material.materialId}
2025-09-15 21:29:07 +00:00
onChange={(e) => updateMaterial(index, 'materialId', 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-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="">Malzeme Seçin</option>
{mockMaterials.map((mat) => (
<option key={mat.id} value={mat.id}>
{mat.code} - {mat.name}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Planlanan
</label>
<input
type="number"
min="0"
value={material.plannedQuantity}
onChange={(e) =>
2025-09-15 21:29:07 +00:00
updateMaterial(index, 'plannedQuantity', parseInt(e.target.value) || 0)
2025-09-15 09:31:47 +00:00
}
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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Kullanılan
</label>
<input
type="number"
min="0"
value={material.actualQuantity}
onChange={(e) =>
2025-09-15 21:29:07 +00:00
updateMaterial(index, 'actualQuantity', parseInt(e.target.value) || 0)
2025-09-15 09:31:47 +00:00
}
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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Birim Fiyat
</label>
<input
type="number"
min="0"
step="0.01"
value={material.unitCost}
onChange={(e) =>
2025-09-15 21:29:07 +00:00
updateMaterial(index, 'unitCost', parseFloat(e.target.value) || 0)
2025-09-15 09:31:47 +00:00
}
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"
/>
</div>
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-1">Toplam</label>
2025-09-15 09:31:47 +00:00
<input
type="text"
value={`${material.totalCost.toFixed(2)}`}
readOnly
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg bg-gray-100"
/>
</div>
<div className="flex items-end">
<button
type="button"
onClick={() => removeMaterial(index)}
className="text-red-600 hover:text-red-800 p-2"
>
<FaTrash className="w-4 h-4" />
</button>
</div>
</div>
</div>
))}
</div>
{/* Activities */}
<div>
<div className="flex items-center justify-between mb-4">
<h4 className="text-lg font-medium text-gray-900">Aktiviteler</h4>
<button
type="button"
onClick={addActivity}
className="bg-green-600 text-white px-3 py-1.5 text-sm rounded-lg hover:bg-green-700 flex items-center space-x-2"
>
<FaPlus className="w-4 h-4" />
<span>Aktivite Ekle</span>
</button>
</div>
{activities.map((activity, index) => (
2025-09-15 21:29:07 +00:00
<div key={activity.id || index} className="bg-gray-50 p-3 rounded-lg mb-2">
2025-09-15 09:31:47 +00:00
<div className="grid grid-cols-1 md:grid-cols-6 gap-4">
<div className="md:col-span-2">
<label className="block text-sm font-medium text-gray-700 mb-1">
Aktivite ıklaması
</label>
<input
type="text"
value={activity.activityDescription}
2025-09-15 21:29:07 +00:00
onChange={(e) => updateActivity(index, 'activityDescription', 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-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="Aktivite açıklaması"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
<FaClock className="w-4 h-4 inline mr-1" />
Planlanan (dk)
</label>
<input
type="number"
min="0"
value={activity.plannedDuration}
onChange={(e) =>
2025-09-15 21:29:07 +00:00
updateActivity(index, 'plannedDuration', parseInt(e.target.value) || 0)
2025-09-15 09:31:47 +00:00
}
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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
<FaClock className="w-4 h-4 inline mr-1" />
Gerçek (dk)
</label>
<input
type="number"
min="0"
value={activity.actualDuration}
onChange={(e) =>
2025-09-15 21:29:07 +00:00
updateActivity(index, 'actualDuration', parseInt(e.target.value) || 0)
2025-09-15 09:31:47 +00:00
}
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"
/>
</div>
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-1">Yapan</label>
2025-09-15 09:31:47 +00:00
<input
type="text"
value={activity.performedBy}
2025-09-15 21:29:07 +00:00
onChange={(e) => updateActivity(index, 'performedBy', 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-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="Yapan kişi"
/>
</div>
<div className="flex items-end space-x-2">
<button
type="button"
onClick={() => toggleActivityCompletion(index)}
className={`px-3 py-2 rounded text-xs ${
activity.completedAt
2025-09-15 21:29:07 +00:00
? 'bg-green-600 text-white'
: 'bg-gray-300 text-gray-700'
2025-09-15 09:31:47 +00:00
}`}
>
2025-09-15 21:29:07 +00:00
{activity.completedAt ? 'Tamamlandı' : 'Bekliyor'}
2025-09-15 09:31:47 +00:00
</button>
<button
type="button"
onClick={() => removeActivity(index)}
className="text-red-600 hover:text-red-800 p-2"
>
<FaTrash className="w-4 h-4" />
</button>
</div>
</div>
{activity.notes !== undefined && (
<div className="mt-3">
<label className="block text-sm font-medium text-gray-700 mb-1">
Aktivite Notları
</label>
<textarea
value={activity.notes}
2025-09-15 21:29:07 +00:00
onChange={(e) => updateActivity(index, 'notes', e.target.value)}
2025-09-15 09:31:47 +00:00
rows={1}
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"
placeholder="Aktivite hakkında notlar..."
/>
</div>
)}
</div>
))}
</div>
{/* Notes */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
İş Emri Notları
</label>
<textarea
value={formData.notes}
2025-09-15 21:29:07 +00:00
onChange={(e) => setFormData({ ...formData, notes: e.target.value })}
2025-09-15 09:31:47 +00:00
rows={2}
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"
placeholder="Genel notlar..."
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Tamamlanma Notları
</label>
<textarea
value={formData.completionNotes}
2025-09-15 21:29:07 +00:00
onChange={(e) => setFormData({ ...formData, completionNotes: e.target.value })}
2025-09-15 09:31:47 +00:00
rows={2}
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"
placeholder="Tamamlanma ile ilgili notlar..."
/>
</div>
</div>
{/* Form Actions */}
<div className="flex justify-end space-x-3 pt-4 border-t border-gray-200">
<button
type="button"
onClick={onClose}
className="px-4 py-2 text-sm text-gray-600 border border-gray-300 rounded-lg hover:bg-gray-50"
>
İptal
</button>
<button
type="submit"
className="px-4 py-2 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 flex items-center space-x-2"
>
<FaSave className="w-4 h-4" />
<span>Kaydet</span>
</button>
</div>
</form>
</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 EditWorkOrderModal