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">Açı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 Açı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
|