2025-09-15 21:29:07 +00:00
|
|
|
|
import React, { useState } from 'react'
|
|
|
|
|
|
import { FaTimes, FaSave, FaUpload, FaMinus } from 'react-icons/fa'
|
2025-09-15 09:31:47 +00:00
|
|
|
|
import {
|
|
|
|
|
|
PmFaultNotification,
|
|
|
|
|
|
FaultTypeEnum,
|
|
|
|
|
|
CriticalityLevelEnum,
|
|
|
|
|
|
NotificationStatusEnum,
|
2025-09-15 21:29:07 +00:00
|
|
|
|
} from '../../../types/pm'
|
|
|
|
|
|
import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
|
|
|
|
|
|
import { mockEmployees } from '../../../mocks/mockEmployees'
|
|
|
|
|
|
import { PriorityEnum } from '../../../types/common'
|
2025-09-17 09:46:58 +00:00
|
|
|
|
import { getCriticalityLevelText, getFaultTypeText, getPriorityText } from '@/utils/erp'
|
2025-09-15 09:31:47 +00:00
|
|
|
|
|
|
|
|
|
|
interface NewFaultNotificationModalProps {
|
2025-09-15 21:29:07 +00:00
|
|
|
|
isOpen: boolean
|
|
|
|
|
|
onClose: () => void
|
|
|
|
|
|
onSave: (notification: Partial<PmFaultNotification>) => void
|
2025-09-15 09:31:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
|
|
|
|
|
|
isOpen,
|
|
|
|
|
|
onClose,
|
|
|
|
|
|
onSave,
|
|
|
|
|
|
}) => {
|
2025-09-15 21:29:07 +00:00
|
|
|
|
const [notificationData, setNotificationData] = useState<Partial<PmFaultNotification>>({
|
|
|
|
|
|
notificationCode: `ARZ-${new Date().getFullYear()}-${String(Date.now()).slice(-3)}`,
|
2025-09-15 09:31:47 +00:00
|
|
|
|
faultType: FaultTypeEnum.Mechanical,
|
|
|
|
|
|
priority: PriorityEnum.Normal,
|
|
|
|
|
|
severity: CriticalityLevelEnum.Medium,
|
|
|
|
|
|
status: NotificationStatusEnum.Open,
|
|
|
|
|
|
followUpRequired: false,
|
|
|
|
|
|
isActive: true,
|
|
|
|
|
|
images: [],
|
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 [errors, setErrors] = useState<Record<string, string>>({})
|
|
|
|
|
|
const [uploadedImages, setUploadedImages] = useState<string[]>([])
|
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 validateForm = () => {
|
2025-09-15 21:29:07 +00:00
|
|
|
|
const newErrors: Record<string, string> = {}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
|
|
|
|
|
|
if (!notificationData.workCenterId) {
|
2025-09-15 21:29:07 +00:00
|
|
|
|
newErrors.workCenterId = 'İş merkezi seçimi gerekli'
|
2025-09-15 09:31:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
if (!notificationData.title?.trim()) {
|
2025-09-15 21:29:07 +00:00
|
|
|
|
newErrors.title = 'Başlık gerekli'
|
2025-09-15 09:31:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
if (!notificationData.description?.trim()) {
|
2025-09-15 21:29:07 +00:00
|
|
|
|
newErrors.description = 'Açıklama gerekli'
|
2025-09-15 09:31:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
if (!notificationData.location?.trim()) {
|
2025-09-15 21:29:07 +00:00
|
|
|
|
newErrors.location = 'Konum gerekli'
|
2025-09-15 09:31:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
if (!notificationData.reportedBy?.trim()) {
|
2025-09-15 21:29:07 +00:00
|
|
|
|
newErrors.reportedBy = 'Bildiren kişi gerekli'
|
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 handleInputChange = (
|
|
|
|
|
|
field: keyof PmFaultNotification,
|
2025-09-15 21:29:07 +00:00
|
|
|
|
value: string | number | boolean | undefined,
|
2025-09-15 09:31:47 +00:00
|
|
|
|
) => {
|
|
|
|
|
|
setNotificationData((prev) => ({
|
|
|
|
|
|
...prev,
|
|
|
|
|
|
[field]: value,
|
2025-09-15 21:29:07 +00:00
|
|
|
|
}))
|
2025-09-15 09:31:47 +00:00
|
|
|
|
// Clear error when user starts typing
|
|
|
|
|
|
if (errors[field]) {
|
|
|
|
|
|
setErrors((prev) => ({
|
|
|
|
|
|
...prev,
|
2025-09-15 21:29:07 +00:00
|
|
|
|
[field]: '',
|
|
|
|
|
|
}))
|
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 handleWorkCenterChange = (workCenterId: string) => {
|
2025-09-15 21:29:07 +00:00
|
|
|
|
const selectedWorkCenter = mockWorkCenters.find((eq) => eq.id === workCenterId)
|
2025-09-15 09:31:47 +00:00
|
|
|
|
if (selectedWorkCenter) {
|
|
|
|
|
|
setNotificationData((prev) => ({
|
|
|
|
|
|
...prev,
|
|
|
|
|
|
workCenterId: selectedWorkCenter.id,
|
|
|
|
|
|
workCenterCode: selectedWorkCenter.code,
|
|
|
|
|
|
workCenterName: selectedWorkCenter.name,
|
|
|
|
|
|
location: selectedWorkCenter.location,
|
2025-09-15 21:29:07 +00:00
|
|
|
|
}))
|
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 handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
2025-09-15 21:29:07 +00:00
|
|
|
|
const files = event.target.files
|
2025-09-15 09:31:47 +00:00
|
|
|
|
if (files) {
|
2025-09-15 21:29:07 +00:00
|
|
|
|
const imageNames = Array.from(files).map((file) => file.name)
|
|
|
|
|
|
setUploadedImages((prev) => [...prev, ...imageNames])
|
2025-09-15 09:31:47 +00:00
|
|
|
|
setNotificationData((prev) => ({
|
|
|
|
|
|
...prev,
|
|
|
|
|
|
images: [...(prev.images || []), ...imageNames],
|
2025-09-15 21:29:07 +00:00
|
|
|
|
}))
|
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 removeImage = (index: number) => {
|
2025-09-15 21:29:07 +00:00
|
|
|
|
setUploadedImages((prev) => prev.filter((_, i) => i !== index))
|
2025-09-15 09:31:47 +00:00
|
|
|
|
setNotificationData((prev) => ({
|
|
|
|
|
|
...prev,
|
|
|
|
|
|
images: prev.images?.filter((_, i) => i !== index) || [],
|
2025-09-15 21:29:07 +00:00
|
|
|
|
}))
|
|
|
|
|
|
}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
|
|
|
|
|
|
const handleSave = () => {
|
|
|
|
|
|
if (validateForm()) {
|
|
|
|
|
|
const notificationToSave: Partial<PmFaultNotification> = {
|
|
|
|
|
|
...notificationData,
|
|
|
|
|
|
id: `FN${Date.now()}`,
|
|
|
|
|
|
reportedAt: new Date(),
|
|
|
|
|
|
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(notificationToSave)
|
|
|
|
|
|
onClose()
|
2025-09-15 09:31:47 +00:00
|
|
|
|
|
|
|
|
|
|
// Reset form
|
|
|
|
|
|
setNotificationData({
|
2025-09-15 21:29:07 +00:00
|
|
|
|
notificationCode: `ARZ-${new Date().getFullYear()}-${String(Date.now()).slice(-3)}`,
|
2025-09-15 09:31:47 +00:00
|
|
|
|
faultType: FaultTypeEnum.Mechanical,
|
|
|
|
|
|
priority: PriorityEnum.Normal,
|
|
|
|
|
|
severity: CriticalityLevelEnum.Medium,
|
|
|
|
|
|
status: NotificationStatusEnum.Open,
|
|
|
|
|
|
followUpRequired: false,
|
|
|
|
|
|
isActive: true,
|
|
|
|
|
|
images: [],
|
2025-09-15 21:29:07 +00:00
|
|
|
|
})
|
|
|
|
|
|
setUploadedImages([])
|
|
|
|
|
|
setErrors({})
|
2025-09-15 09:31:47 +00:00
|
|
|
|
}
|
2025-09-15 21:29:07 +00:00
|
|
|
|
}
|
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-3xl max-h-[90vh] overflow-y-auto">
|
|
|
|
|
|
{/* Header */}
|
|
|
|
|
|
<div className="flex items-center justify-between p-4 border-b border-gray-200">
|
2025-09-15 21:29:07 +00:00
|
|
|
|
<h2 className="text-xl font-bold text-gray-900">Yeni Arıza Bildirimi</h2>
|
|
|
|
|
|
<button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors">
|
2025-09-15 09:31:47 +00:00
|
|
|
|
<FaTimes className="w-5 h-5" />
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Content */}
|
|
|
|
|
|
<div className="p-3 space-y-3">
|
|
|
|
|
|
{/* Basic Info */}
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
|
|
|
|
Bildirim Kodu *
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
2025-09-15 21:29:07 +00:00
|
|
|
|
value={notificationData.notificationCode || ''}
|
|
|
|
|
|
onChange={(e) => handleInputChange('notificationCode', e.target.value)}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
className="w-full px-2.5 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
|
|
|
|
|
placeholder="ARZ-2024-001"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</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
|
2025-09-15 21:29:07 +00:00
|
|
|
|
value={notificationData.workCenterId || ''}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
onChange={(e) => handleWorkCenterChange(e.target.value)}
|
|
|
|
|
|
className={`w-full px-2.5 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="text-red-500 text-xs mt-1">{errors.workCenterId}</p>
|
2025-09-15 09:31:47 +00:00
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Title and Description */}
|
|
|
|
|
|
<div className="space-y-3">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
|
|
|
|
Arıza Başlığı *
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
2025-09-15 21:29:07 +00:00
|
|
|
|
value={notificationData.title || ''}
|
|
|
|
|
|
onChange={(e) => handleInputChange('title', e.target.value)}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
className={`w-full px-2.5 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.title ? 'border-red-500' : 'border-gray-300'
|
2025-09-15 09:31:47 +00:00
|
|
|
|
}`}
|
|
|
|
|
|
placeholder="Arıza başlığı"
|
|
|
|
|
|
/>
|
2025-09-15 21:29:07 +00:00
|
|
|
|
{errors.title && <p className="text-red-500 text-xs mt-1">{errors.title}</p>}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
|
|
|
|
Detaylı Açıklama *
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<textarea
|
2025-09-15 21:29:07 +00:00
|
|
|
|
value={notificationData.description || ''}
|
|
|
|
|
|
onChange={(e) => handleInputChange('description', e.target.value)}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
rows={2}
|
|
|
|
|
|
className={`w-full px-2.5 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="Arızanın detaylı açıklaması, belirtiler ve gözlemler"
|
|
|
|
|
|
/>
|
|
|
|
|
|
{errors.description && (
|
2025-09-15 21:29:07 +00:00
|
|
|
|
<p className="text-red-500 text-xs mt-1">{errors.description}</p>
|
2025-09-15 09:31:47 +00:00
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Location and Reporter */}
|
|
|
|
|
|
<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">Konum *</label>
|
2025-09-15 09:31:47 +00:00
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
2025-09-15 21:29:07 +00:00
|
|
|
|
value={notificationData.location || ''}
|
|
|
|
|
|
onChange={(e) => handleInputChange('location', e.target.value)}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
className={`w-full px-2.5 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.location ? 'border-red-500' : 'border-gray-300'
|
2025-09-15 09:31:47 +00:00
|
|
|
|
}`}
|
|
|
|
|
|
placeholder="Atölye A - Hat 1"
|
|
|
|
|
|
/>
|
2025-09-15 21:29:07 +00:00
|
|
|
|
{errors.location && <p className="text-red-500 text-xs mt-1">{errors.location}</p>}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
|
|
|
|
Bildiren Kişi *
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<select
|
2025-09-15 21:29:07 +00:00
|
|
|
|
value={notificationData.reportedBy || ''}
|
|
|
|
|
|
onChange={(e) => handleInputChange('reportedBy', e.target.value)}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
className={`w-full px-2.5 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
|
|
|
|
}`}
|
|
|
|
|
|
>
|
|
|
|
|
|
<option value="">Bildiren kişi seçin</option>
|
|
|
|
|
|
{mockEmployees.map((employee) => (
|
|
|
|
|
|
<option key={employee.id} value={employee.fullName}>
|
|
|
|
|
|
{employee.fullName} - {employee.jobPosition?.name}
|
|
|
|
|
|
</option>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</select>
|
|
|
|
|
|
{errors.reportedBy && (
|
|
|
|
|
|
<p className="text-red-500 text-xs mt-1">{errors.reportedBy}</p>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
|
|
|
|
<div>
|
2025-09-15 21:29:07 +00:00
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Arıza Türü</label>
|
2025-09-15 09:31:47 +00:00
|
|
|
|
<select
|
|
|
|
|
|
value={notificationData.faultType || FaultTypeEnum.Mechanical}
|
2025-09-15 21:29:07 +00:00
|
|
|
|
onChange={(e) => handleInputChange('faultType', e.target.value as FaultTypeEnum)}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
className="w-full px-2.5 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(FaultTypeEnum).map((faultType) => (
|
|
|
|
|
|
<option key={faultType} value={faultType}>
|
|
|
|
|
|
{getFaultTypeText(faultType)}
|
|
|
|
|
|
</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
|
|
|
|
|
|
value={notificationData.priority || PriorityEnum.Normal}
|
2025-09-15 21:29:07 +00:00
|
|
|
|
onChange={(e) => handleInputChange('priority', e.target.value as PriorityEnum)}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
className="w-full px-2.5 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>
|
2025-09-15 21:29:07 +00:00
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Kritiklik</label>
|
2025-09-15 09:31:47 +00:00
|
|
|
|
<select
|
|
|
|
|
|
value={notificationData.severity || CriticalityLevelEnum.Medium}
|
|
|
|
|
|
onChange={(e) =>
|
2025-09-15 21:29:07 +00:00
|
|
|
|
handleInputChange('severity', e.target.value as CriticalityLevelEnum)
|
2025-09-15 09:31:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
className="w-full px-2.5 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(CriticalityLevelEnum).map((level) => (
|
|
|
|
|
|
<option key={level} value={level}>
|
|
|
|
|
|
{getCriticalityLevelText(level)}
|
|
|
|
|
|
</option>
|
|
|
|
|
|
))}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
</select>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Estimated Repair Time */}
|
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
|
|
|
|
Tahmini Onarım Süresi (dakika)
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="number"
|
2025-09-15 21:29:07 +00:00
|
|
|
|
value={notificationData.estimatedRepairTime || ''}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
onChange={(e) =>
|
2025-09-15 21:29:07 +00:00
|
|
|
|
handleInputChange('estimatedRepairTime', parseInt(e.target.value) || undefined)
|
2025-09-15 09:31:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
className="w-full px-2.5 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
|
|
|
|
|
placeholder="120"
|
|
|
|
|
|
min="0"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="flex items-center">
|
|
|
|
|
|
<label className="flex items-center">
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="checkbox"
|
|
|
|
|
|
checked={notificationData.followUpRequired || false}
|
2025-09-15 21:29:07 +00:00
|
|
|
|
onChange={(e) => handleInputChange('followUpRequired', e.target.checked)}
|
2025-09-15 09:31:47 +00:00
|
|
|
|
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
|
|
|
|
|
|
/>
|
2025-09-15 21:29:07 +00:00
|
|
|
|
<span className="ml-2 text-sm text-gray-700">Takip gerekli</span>
|
2025-09-15 09:31:47 +00:00
|
|
|
|
</label>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Image Upload */}
|
|
|
|
|
|
<div>
|
2025-09-15 21:29:07 +00:00
|
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Fotoğraflar</label>
|
2025-09-15 09:31:47 +00:00
|
|
|
|
<div className="border-2 border-dashed border-gray-300 rounded-lg p-4">
|
|
|
|
|
|
<div className="text-center">
|
|
|
|
|
|
<FaUpload className="mx-auto h-10 w-10 text-gray-400" />
|
|
|
|
|
|
<div className="mt-4">
|
|
|
|
|
|
<label htmlFor="image-upload" className="cursor-pointer">
|
|
|
|
|
|
<span className="mt-2 block text-sm font-medium text-gray-900">
|
|
|
|
|
|
Fotoğraf yükleyin
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span className="mt-1 block text-sm text-gray-500">
|
|
|
|
|
|
PNG, JPG, GIF formatında dosyalar
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
id="image-upload"
|
|
|
|
|
|
name="image-upload"
|
|
|
|
|
|
type="file"
|
|
|
|
|
|
multiple
|
|
|
|
|
|
accept="image/*"
|
|
|
|
|
|
className="sr-only"
|
|
|
|
|
|
onChange={handleImageUpload}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{uploadedImages.length > 0 && (
|
|
|
|
|
|
<div className="mt-4">
|
2025-09-15 21:29:07 +00:00
|
|
|
|
<h4 className="text-sm font-medium text-gray-700 mb-1">Yüklenen Fotoğraflar:</h4>
|
2025-09-15 09:31:47 +00:00
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
|
{uploadedImages.map((image, index) => (
|
|
|
|
|
|
<div
|
|
|
|
|
|
key={index}
|
|
|
|
|
|
className="flex items-center justify-between p-1.5 bg-gray-50 rounded"
|
|
|
|
|
|
>
|
|
|
|
|
|
<span className="text-sm text-gray-600">{image}</span>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => removeImage(index)}
|
|
|
|
|
|
className="text-red-600 hover:text-red-800"
|
|
|
|
|
|
>
|
|
|
|
|
|
<FaMinus className="w-3 h-3" />
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Footer */}
|
|
|
|
|
|
<div className="flex items-center justify-end space-x-2 p-3 border-t border-gray-200">
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
|
className="px-3 py-1 text-sm text-gray-600 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
|
|
|
|
|
|
>
|
|
|
|
|
|
İptal
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={handleSave}
|
|
|
|
|
|
className="px-3 py-1 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors flex items-center space-x-2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<FaSave className="w-4 h-4" />
|
|
|
|
|
|
<span>Kaydet</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 NewFaultNotificationModal
|