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

222 lines
8.1 KiB
TypeScript
Raw Normal View History

2025-09-15 21:29:07 +00:00
import React, { useState } from 'react'
import { FaTimes, FaSave, FaUser, FaUsers } from 'react-icons/fa'
import { PmFaultNotification } from '../../../types/pm'
import { mockEmployees } from '../../../mocks/mockEmployees'
import { mockMaintenanceTeams } from '../../../mocks/mockMaintenanceTeams'
2025-09-15 09:31:47 +00:00
interface AssignNotificationModalProps {
2025-09-15 21:29:07 +00:00
isOpen: boolean
onClose: () => void
onSave: (assignments: { notificationIds: string[]; assignedTo?: string; teamId?: string }) => void
notifications: PmFaultNotification[]
2025-09-15 09:31:47 +00:00
}
const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
isOpen,
onClose,
onSave,
notifications,
}) => {
2025-09-15 21:29:07 +00:00
const [assignmentType, setAssignmentType] = useState<'person' | 'team'>('person')
const [assignedTo, setAssignedTo] = useState('')
const [teamId, setTeamId] = useState('')
const [errors, setErrors] = useState<Record<string, string>>({})
2025-09-15 09:31:47 +00:00
2025-09-15 21:29:07 +00:00
if (!isOpen || notifications.length === 0) 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
2025-09-15 21:29:07 +00:00
if (assignmentType === 'person' && !assignedTo) {
newErrors.assignedTo = 'Kişi seçimi gerekli'
2025-09-15 09:31:47 +00:00
}
2025-09-15 21:29:07 +00:00
if (assignmentType === 'team' && !teamId) {
newErrors.teamId = 'Ekip seçimi 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 handleSave = () => {
if (validateForm()) {
const assignmentData = {
notificationIds: notifications.map((n) => n.id),
2025-09-15 21:29:07 +00:00
...(assignmentType === 'person' ? { assignedTo } : { teamId }),
}
2025-09-15 09:31:47 +00:00
2025-09-15 21:29:07 +00:00
onSave(assignmentData)
onClose()
2025-09-15 09:31:47 +00:00
// Reset form
2025-09-15 21:29:07 +00:00
setAssignmentType('person')
setAssignedTo('')
setTeamId('')
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-2xl mx-4 max-h-[90vh] overflow-y-auto">
{/* Header */}
<div className="flex items-center justify-between p-3 border-b border-gray-200">
<h2 className="text-xl font-bold text-gray-900">Atama Yap</h2>
2025-09-15 21:29:07 +00:00
<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">
{/* Notification Summary */}
<div className="bg-blue-50 border border-blue-200 rounded-lg p-2">
<h4 className="text-xs font-medium text-blue-800 mb-1.5">
Seçili Arıza Bildirimleri ({notifications.length})
</h4>
<div className="space-y-1">
{notifications.map((notification) => (
<div key={notification.id} className="text-sm text-blue-700">
2025-09-15 21:29:07 +00:00
<span className="font-medium">{notification.notificationCode}</span>
{' - '}
2025-09-15 09:31:47 +00:00
<span>{notification.title}</span>
2025-09-15 21:29:07 +00:00
{' ('}
2025-09-15 09:31:47 +00:00
<span>{notification.workCenter.code}</span>
2025-09-15 21:29:07 +00:00
{')'}
2025-09-15 09:31:47 +00:00
</div>
))}
</div>
</div>
{/* Assignment Type */}
<div>
2025-09-15 21:29:07 +00:00
<label className="block text-sm font-medium text-gray-700 mb-2">Atama Türü</label>
2025-09-15 09:31:47 +00:00
<div className="flex space-x-3">
<label className="flex items-center">
<input
type="radio"
value="person"
2025-09-15 21:29:07 +00:00
checked={assignmentType === 'person'}
onChange={(e) => setAssignmentType(e.target.value as 'person' | 'team')}
2025-09-15 09:31:47 +00:00
className="mr-2"
/>
<FaUser className="w-4 h-4 mr-2 text-gray-500" />
<span>Kişiye Ata</span>
</label>
<label className="flex items-center">
<input
type="radio"
value="team"
2025-09-15 21:29:07 +00:00
checked={assignmentType === 'team'}
onChange={(e) => setAssignmentType(e.target.value as 'person' | 'team')}
2025-09-15 09:31:47 +00:00
className="mr-2"
/>
<FaUsers className="w-4 h-4 mr-2 text-gray-500" />
<span>Ekibe Ata</span>
</label>
</div>
</div>
{/* Person Assignment */}
2025-09-15 21:29:07 +00:00
{assignmentType === 'person' && (
2025-09-15 09:31:47 +00:00
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Atanacak Kişi *
</label>
<select
value={assignedTo}
onChange={(e) => setAssignedTo(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.assignedTo ? 'border-red-500' : 'border-gray-300'
2025-09-15 09:31:47 +00:00
}`}
>
<option value="">Kişi seçin</option>
{mockEmployees.map((employee) => (
<option key={employee.id} value={employee.fullName}>
{employee.fullName} - {employee.jobPosition?.name}
</option>
))}
</select>
{errors.assignedTo && (
<p className="text-red-500 text-xs mt-1">{errors.assignedTo}</p>
)}
</div>
)}
{/* Team Assignment */}
2025-09-15 21:29:07 +00:00
{assignmentType === 'team' && (
2025-09-15 09:31:47 +00:00
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Atanacak Ekip *
</label>
<select
value={teamId}
onChange={(e) => setTeamId(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.teamId ? 'border-red-500' : 'border-gray-300'
2025-09-15 09:31:47 +00:00
}`}
>
<option value="">Ekip seçin</option>
{mockMaintenanceTeams
.filter((team) => team.isActive)
.map((team) => (
<option key={team.id} value={team.id}>
{team.name} ({team.code})
</option>
))}
</select>
2025-09-15 21:29:07 +00:00
{errors.teamId && <p className="text-red-500 text-xs mt-1">{errors.teamId}</p>}
2025-09-15 09:31:47 +00:00
</div>
)}
{/* Assignment Preview */}
{(assignedTo || teamId) && (
<div className="bg-green-50 border border-green-200 rounded-lg p-2">
2025-09-15 21:29:07 +00:00
<h4 className="text-sm font-medium text-green-800 mb-1">Atama Özeti</h4>
2025-09-15 09:31:47 +00:00
<div className="text-sm text-green-700">
<p>
2025-09-15 21:29:07 +00:00
<strong>{notifications.length}</strong> arıza bildirimi{' '}
{assignmentType === 'person' ? (
2025-09-15 09:31:47 +00:00
<>
<strong>
2025-09-15 21:29:07 +00:00
{mockEmployees.find((emp) => emp.fullName === assignedTo)?.fullName}
2025-09-15 09:31:47 +00:00
</strong>
kişisine atanacak
</>
) : (
<>
<strong>
2025-09-15 21:29:07 +00:00
{mockMaintenanceTeams.find((team) => team.id === teamId)?.name}
2025-09-15 09:31:47 +00:00
</strong>
ekibine atanacak
</>
)}
</p>
</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>Ata</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 AssignNotificationModal