Container Maintenance Management

This commit is contained in:
Sedat Öztürk 2025-09-16 00:29:07 +03:00
parent bb2e39c2c3
commit 4b7fd59e61
35 changed files with 4620 additions and 6560 deletions

View file

@ -3330,16 +3330,6 @@
"RequiredPermissionName": null, "RequiredPermissionName": null,
"IsDisabled": false "IsDisabled": false
}, },
{
"ParentCode": "App.Maintenance",
"Code": "App.Maintenance.Equipment",
"DisplayName": "Ekipmanlar",
"Order": 1,
"Url": "/admin/maintenance/equipment",
"Icon": "FcEngineering",
"RequiredPermissionName": null,
"IsDisabled": false
},
{ {
"ParentCode": "App.Maintenance", "ParentCode": "App.Maintenance",
"Code": "App.Maintenance.Workcenters", "Code": "App.Maintenance.Workcenters",
@ -3373,7 +3363,7 @@
{ {
"ParentCode": "App.Maintenance", "ParentCode": "App.Maintenance",
"Code": "App.Maintenance.Teams", "Code": "App.Maintenance.Teams",
"DisplayName": "Bakım Takımları", "DisplayName": "Bakım Ekipleri",
"Order": 5, "Order": 5,
"Url": "/admin/maintenance/teams", "Url": "/admin/maintenance/teams",
"Icon": "FcConferenceCall", "Icon": "FcConferenceCall",

View file

@ -1,18 +1,14 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaSave, FaUser, FaUsers } from "react-icons/fa"; import { FaTimes, FaSave, FaUser, FaUsers } from 'react-icons/fa'
import { PmFaultNotification } from "../../../types/pm"; import { PmFaultNotification } from '../../../types/pm'
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from '../../../mocks/mockEmployees'
import { mockMaintenanceTeams } from "../../../mocks/mockMaintenanceTeams"; import { mockMaintenanceTeams } from '../../../mocks/mockMaintenanceTeams'
interface AssignNotificationModalProps { interface AssignNotificationModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (assignments: { onSave: (assignments: { notificationIds: string[]; assignedTo?: string; teamId?: string }) => void
notificationIds: string[]; notifications: PmFaultNotification[]
assignedTo?: string;
teamId?: string;
}) => void;
notifications: PmFaultNotification[];
} }
const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({ const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
@ -21,46 +17,44 @@ const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
onSave, onSave,
notifications, notifications,
}) => { }) => {
const [assignmentType, setAssignmentType] = useState<"person" | "team">( const [assignmentType, setAssignmentType] = useState<'person' | 'team'>('person')
"person" const [assignedTo, setAssignedTo] = useState('')
); const [teamId, setTeamId] = useState('')
const [assignedTo, setAssignedTo] = useState(""); const [errors, setErrors] = useState<Record<string, string>>({})
const [teamId, setTeamId] = useState("");
const [errors, setErrors] = useState<Record<string, string>>({});
if (!isOpen || notifications.length === 0) return null; if (!isOpen || notifications.length === 0) return null
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (assignmentType === "person" && !assignedTo) { if (assignmentType === 'person' && !assignedTo) {
newErrors.assignedTo = "Kişi seçimi gerekli"; newErrors.assignedTo = 'Kişi seçimi gerekli'
} }
if (assignmentType === "team" && !teamId) { if (assignmentType === 'team' && !teamId) {
newErrors.teamId = "Ekip seçimi gerekli"; newErrors.teamId = 'Ekip seçimi gerekli'
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleSave = () => { const handleSave = () => {
if (validateForm()) { if (validateForm()) {
const assignmentData = { const assignmentData = {
notificationIds: notifications.map((n) => n.id), notificationIds: notifications.map((n) => n.id),
...(assignmentType === "person" ? { assignedTo } : { teamId }), ...(assignmentType === 'person' ? { assignedTo } : { teamId }),
}; }
onSave(assignmentData); onSave(assignmentData)
onClose(); onClose()
// Reset form // Reset form
setAssignmentType("person"); setAssignmentType('person')
setAssignedTo(""); setAssignedTo('')
setTeamId(""); setTeamId('')
setErrors({}); setErrors({})
} }
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -68,10 +62,7 @@ const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-3 border-b border-gray-200"> <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> <h2 className="text-xl font-bold text-gray-900">Atama Yap</h2>
<button <button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors">
onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors"
>
<FaTimes className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>
@ -86,14 +77,12 @@ const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
<div className="space-y-1"> <div className="space-y-1">
{notifications.map((notification) => ( {notifications.map((notification) => (
<div key={notification.id} className="text-sm text-blue-700"> <div key={notification.id} className="text-sm text-blue-700">
<span className="font-medium"> <span className="font-medium">{notification.notificationCode}</span>
{notification.notificationCode} {' - '}
</span>
{" - "}
<span>{notification.title}</span> <span>{notification.title}</span>
{" ("} {' ('}
<span>{notification.workCenter.code}</span> <span>{notification.workCenter.code}</span>
{")"} {')'}
</div> </div>
))} ))}
</div> </div>
@ -101,18 +90,14 @@ const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
{/* Assignment Type */} {/* Assignment Type */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Atama Türü</label>
Atama Türü
</label>
<div className="flex space-x-3"> <div className="flex space-x-3">
<label className="flex items-center"> <label className="flex items-center">
<input <input
type="radio" type="radio"
value="person" value="person"
checked={assignmentType === "person"} checked={assignmentType === 'person'}
onChange={(e) => onChange={(e) => setAssignmentType(e.target.value as 'person' | 'team')}
setAssignmentType(e.target.value as "person" | "team")
}
className="mr-2" className="mr-2"
/> />
<FaUser className="w-4 h-4 mr-2 text-gray-500" /> <FaUser className="w-4 h-4 mr-2 text-gray-500" />
@ -122,10 +107,8 @@ const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
<input <input
type="radio" type="radio"
value="team" value="team"
checked={assignmentType === "team"} checked={assignmentType === 'team'}
onChange={(e) => onChange={(e) => setAssignmentType(e.target.value as 'person' | 'team')}
setAssignmentType(e.target.value as "person" | "team")
}
className="mr-2" className="mr-2"
/> />
<FaUsers className="w-4 h-4 mr-2 text-gray-500" /> <FaUsers className="w-4 h-4 mr-2 text-gray-500" />
@ -135,7 +118,7 @@ const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
</div> </div>
{/* Person Assignment */} {/* Person Assignment */}
{assignmentType === "person" && ( {assignmentType === 'person' && (
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">
Atanacak Kişi * Atanacak Kişi *
@ -144,7 +127,7 @@ const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
value={assignedTo} value={assignedTo}
onChange={(e) => setAssignedTo(e.target.value)} 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 ${ 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 ${
errors.assignedTo ? "border-red-500" : "border-gray-300" errors.assignedTo ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
<option value="">Kişi seçin</option> <option value="">Kişi seçin</option>
@ -161,7 +144,7 @@ const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
)} )}
{/* Team Assignment */} {/* Team Assignment */}
{assignmentType === "team" && ( {assignmentType === 'team' && (
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">
Atanacak Ekip * Atanacak Ekip *
@ -170,7 +153,7 @@ const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
value={teamId} value={teamId}
onChange={(e) => setTeamId(e.target.value)} 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 ${ 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 ${
errors.teamId ? "border-red-500" : "border-gray-300" errors.teamId ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
<option value="">Ekip seçin</option> <option value="">Ekip seçin</option>
@ -182,40 +165,28 @@ const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
</option> </option>
))} ))}
</select> </select>
{errors.teamId && ( {errors.teamId && <p className="text-red-500 text-xs mt-1">{errors.teamId}</p>}
<p className="text-red-500 text-xs mt-1">{errors.teamId}</p>
)}
</div> </div>
)} )}
{/* Assignment Preview */} {/* Assignment Preview */}
{(assignedTo || teamId) && ( {(assignedTo || teamId) && (
<div className="bg-green-50 border border-green-200 rounded-lg p-2"> <div className="bg-green-50 border border-green-200 rounded-lg p-2">
<h4 className="text-sm font-medium text-green-800 mb-1"> <h4 className="text-sm font-medium text-green-800 mb-1">Atama Özeti</h4>
Atama Özeti
</h4>
<div className="text-sm text-green-700"> <div className="text-sm text-green-700">
<p> <p>
<strong>{notifications.length}</strong> arıza bildirimi{" "} <strong>{notifications.length}</strong> arıza bildirimi{' '}
{assignmentType === "person" ? ( {assignmentType === 'person' ? (
<> <>
<strong> <strong>
{ {mockEmployees.find((emp) => emp.fullName === assignedTo)?.fullName}
mockEmployees.find(
(emp) => emp.fullName === assignedTo
)?.fullName
}
</strong> </strong>
kişisine atanacak kişisine atanacak
</> </>
) : ( ) : (
<> <>
<strong> <strong>
{ {mockMaintenanceTeams.find((team) => team.id === teamId)?.name}
mockMaintenanceTeams.find(
(team) => team.id === teamId
)?.name
}
</strong> </strong>
ekibine atanacak ekibine atanacak
</> </>
@ -244,7 +215,7 @@ const AssignNotificationModal: React.FC<AssignNotificationModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default AssignNotificationModal; export default AssignNotificationModal

View file

@ -1,13 +1,13 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaSave, FaWrench } from "react-icons/fa"; import { FaTimes, FaSave, FaWrench } from 'react-icons/fa'
import { mockMaintenancePlans } from "../../../mocks/mockMaintenancePlans"; import { mockMaintenancePlans } from '../../../mocks/mockMaintenancePlans'
import { Team } from "../../../types/common"; import { Team } from '../../../types/common'
interface AssignWorkOrderModalProps { interface AssignWorkOrderModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (assignments: { teamId: string; planIds: string[] }[]) => void; onSave: (assignments: { teamId: string; planIds: string[] }[]) => void
selectedTeams: Team[]; selectedTeams: Team[]
} }
const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
@ -16,22 +16,20 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
onSave, onSave,
selectedTeams, selectedTeams,
}) => { }) => {
const [assignments, setAssignments] = useState<Record<string, string[]>>({}); const [assignments, setAssignments] = useState<Record<string, string[]>>({})
const [bulkPlanIds, setBulkPlanIds] = useState<string[]>([]); const [bulkPlanIds, setBulkPlanIds] = useState<string[]>([])
const [useBulkAssignment, setUseBulkAssignment] = useState(true); const [useBulkAssignment, setUseBulkAssignment] = useState(true)
if (!isOpen) return null; if (!isOpen) return null
// Get available maintenance plans // Get available maintenance plans
const availablePlans = mockMaintenancePlans.filter((plan) => plan.isActive); const availablePlans = mockMaintenancePlans.filter((plan) => plan.isActive)
const handleBulkPlanChange = (planId: string) => { const handleBulkPlanChange = (planId: string) => {
setBulkPlanIds((prev) => setBulkPlanIds((prev) =>
prev.includes(planId) prev.includes(planId) ? prev.filter((id) => id !== planId) : [...prev, planId],
? prev.filter((id) => id !== planId) )
: [...prev, planId] }
);
};
const handleIndividualPlanChange = (teamId: string, planId: string) => { const handleIndividualPlanChange = (teamId: string, planId: string) => {
setAssignments((prev) => ({ setAssignments((prev) => ({
@ -39,40 +37,40 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
[teamId]: prev[teamId]?.includes(planId) [teamId]: prev[teamId]?.includes(planId)
? prev[teamId].filter((id) => id !== planId) ? prev[teamId].filter((id) => id !== planId)
: [...(prev[teamId] || []), planId], : [...(prev[teamId] || []), planId],
})); }))
}; }
const handleSave = () => { const handleSave = () => {
if (useBulkAssignment) { if (useBulkAssignment) {
if (bulkPlanIds.length === 0) { if (bulkPlanIds.length === 0) {
alert("Lütfen en az bir bakım planı seçin"); alert('Lütfen en az bir bakım planı seçin')
return; return
} }
const bulkAssignments = selectedTeams.map((team) => ({ const bulkAssignments = selectedTeams.map((team) => ({
teamId: team.id, teamId: team.id,
planIds: bulkPlanIds, planIds: bulkPlanIds,
})); }))
onSave(bulkAssignments); onSave(bulkAssignments)
} else { } else {
const individualAssignments = selectedTeams const individualAssignments = selectedTeams
.map((team) => ({ .map((team) => ({
teamId: team.id, teamId: team.id,
planIds: assignments[team.id] || [], planIds: assignments[team.id] || [],
})) }))
.filter((assignment) => assignment.planIds.length > 0); .filter((assignment) => assignment.planIds.length > 0)
if (individualAssignments.length === 0) { if (individualAssignments.length === 0) {
alert("Lütfen en az bir ekip için bakım planı seçin"); alert('Lütfen en az bir ekip için bakım planı seçin')
return; return
} }
onSave(individualAssignments); onSave(individualAssignments)
} }
onClose(); onClose()
// Reset state // Reset state
setAssignments({}); setAssignments({})
setBulkPlanIds([]); setBulkPlanIds([])
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -85,10 +83,7 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
Seçili ekiplere ({selectedTeams.length}) bakım planları atayın Seçili ekiplere ({selectedTeams.length}) bakım planları atayın
</p> </p>
</div> </div>
<button <button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors">
onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors"
>
<FaTimes className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>
@ -97,9 +92,7 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
<div className="p-3 space-y-3"> <div className="p-3 space-y-3">
{/* Assignment Mode Selection */} {/* Assignment Mode Selection */}
<div className="border border-gray-200 rounded-lg p-3"> <div className="border border-gray-200 rounded-lg p-3">
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Atama Türü</h3>
Atama Türü
</h3>
<div className="space-y-2"> <div className="space-y-2">
<label className="flex items-center"> <label className="flex items-center">
<input <input
@ -128,9 +121,7 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
{/* Selected Teams */} {/* Selected Teams */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Seçili Ekipler</h3>
Seçili Ekipler
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2"> <div className="grid grid-cols-1 md:grid-cols-2 gap-2">
{selectedTeams.map((team) => ( {selectedTeams.map((team) => (
<div <div
@ -139,9 +130,7 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
> >
<FaWrench className="w-5 h-5 text-blue-600" /> <FaWrench className="w-5 h-5 text-blue-600" />
<div> <div>
<h4 className="font-medium text-sm text-gray-900"> <h4 className="font-medium text-sm text-gray-900">{team.name}</h4>
{team.name}
</h4>
<p className="text-gray-600">{team.code}</p> <p className="text-gray-600">{team.code}</p>
</div> </div>
</div> </div>
@ -169,12 +158,8 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
className="mt-1 text-blue-600 focus:ring-blue-500" className="mt-1 text-blue-600 focus:ring-blue-500"
/> />
<div className="flex-1"> <div className="flex-1">
<h4 className="font-medium text-gray-900"> <h4 className="font-medium text-gray-900">{plan.planCode}</h4>
{plan.planCode} <p className="text-gray-600">{plan.description}</p>
</h4>
<p className="text-gray-600">
{plan.description}
</p>
<div className="flex items-center space-x-4 mt-1 text-xs text-gray-500"> <div className="flex items-center space-x-4 mt-1 text-xs text-gray-500">
<span> <span>
Sıklık: {plan.frequency} {plan.frequencyUnit} Sıklık: {plan.frequency} {plan.frequencyUnit}
@ -192,15 +177,10 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
{/* Individual Assignment */} {/* Individual Assignment */}
{!useBulkAssignment && ( {!useBulkAssignment && (
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Bireysel Plan Atamaları</h3>
Bireysel Plan Atamaları
</h3>
<div className="space-y-3"> <div className="space-y-3">
{selectedTeams.map((team) => ( {selectedTeams.map((team) => (
<div <div key={team.id} className="border border-gray-200 rounded-lg p-2">
key={team.id}
className="border border-gray-200 rounded-lg p-2"
>
<h4 className="font-medium text-sm text-gray-900 mb-2"> <h4 className="font-medium text-sm text-gray-900 mb-2">
{team.name} ({team.code}) {team.name} ({team.code})
</h4> </h4>
@ -212,21 +192,13 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
> >
<input <input
type="checkbox" type="checkbox"
checked={ checked={assignments[team.id]?.includes(plan.id) || false}
assignments[team.id]?.includes(plan.id) || false onChange={() => handleIndividualPlanChange(team.id, plan.id)}
}
onChange={() =>
handleIndividualPlanChange(team.id, plan.id)
}
className="mt-1 text-blue-600 focus:ring-blue-500" className="mt-1 text-blue-600 focus:ring-blue-500"
/> />
<div className="flex-1"> <div className="flex-1">
<h5 className="text-sm font-medium text-gray-900"> <h5 className="text-sm font-medium text-gray-900">{plan.planCode}</h5>
{plan.planCode} <p className="text-xs text-gray-600">{plan.description}</p>
</h5>
<p className="text-xs text-gray-600">
{plan.description}
</p>
<div className="flex items-center space-x-3 mt-1 text-xs text-gray-500"> <div className="flex items-center space-x-3 mt-1 text-xs text-gray-500">
<span> <span>
Sıklık: {plan.frequency} {plan.frequencyUnit} Sıklık: {plan.frequency} {plan.frequencyUnit}
@ -262,7 +234,7 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default AssignWorkOrderModal; export default AssignWorkOrderModal

View file

@ -1,24 +1,21 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaUserCog, FaUser, FaUsers } from "react-icons/fa"; import { FaTimes, FaUserCog, FaUser, FaUsers } from 'react-icons/fa'
import { PmMaintenanceWorkOrder } from "../../../types/pm"; import { PmMaintenanceWorkOrder } from '../../../types/pm'
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from '../../../mocks/mockEmployees'
import { mockMaintenanceTeams } from "../../../mocks/mockMaintenanceTeams"; import { mockMaintenanceTeams } from '../../../mocks/mockMaintenanceTeams'
interface AssignWorkOrderModalProps { interface AssignWorkOrderModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onAssign: ( onAssign: (workOrders: PmMaintenanceWorkOrder[], assignmentData: AssignmentData) => void
workOrders: PmMaintenanceWorkOrder[], workOrders: PmMaintenanceWorkOrder[]
assignmentData: AssignmentData
) => void;
workOrders: PmMaintenanceWorkOrder[];
} }
interface AssignmentData { interface AssignmentData {
assignmentType: "person" | "team"; assignmentType: 'person' | 'team'
assignedTo?: string; assignedTo?: string
maintenanceTeamId?: string; maintenanceTeamId?: string
notes?: string; notes?: string
} }
const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
@ -27,65 +24,60 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
onAssign, onAssign,
workOrders, workOrders,
}) => { }) => {
const [assignmentType, setAssignmentType] = useState<"person" | "team">( const [assignmentType, setAssignmentType] = useState<'person' | 'team'>('person')
"person"
);
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
assignedTo: "", assignedTo: '',
maintenanceTeamId: "", maintenanceTeamId: '',
notes: "", notes: '',
}); })
const [errors, setErrors] = useState<Record<string, string>>({}); const [errors, setErrors] = useState<Record<string, string>>({})
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (assignmentType === "person" && !formData.assignedTo) { if (assignmentType === 'person' && !formData.assignedTo) {
newErrors.assignedTo = "Atanacak kişi seçilmelidir"; newErrors.assignedTo = 'Atanacak kişi seçilmelidir'
} }
if (assignmentType === "team" && !formData.maintenanceTeamId) { if (assignmentType === 'team' && !formData.maintenanceTeamId) {
newErrors.maintenanceTeamId = "Atanacak ekip seçilmelidir"; newErrors.maintenanceTeamId = 'Atanacak ekip seçilmelidir'
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault()
if (!validateForm()) return; if (!validateForm()) return
const assignmentData: AssignmentData = { const assignmentData: AssignmentData = {
assignmentType, assignmentType,
assignedTo: assignmentType === "person" ? formData.assignedTo : undefined, assignedTo: assignmentType === 'person' ? formData.assignedTo : undefined,
maintenanceTeamId: maintenanceTeamId: assignmentType === 'team' ? formData.maintenanceTeamId : undefined,
assignmentType === "team" ? formData.maintenanceTeamId : undefined,
notes: formData.notes || undefined, notes: formData.notes || undefined,
}; }
onAssign(workOrders, assignmentData); onAssign(workOrders, assignmentData)
onClose(); onClose()
}; }
const getSelectedTeam = () => { const getSelectedTeam = () => {
if (assignmentType === "team" && formData.maintenanceTeamId) { if (assignmentType === 'team' && formData.maintenanceTeamId) {
return mockMaintenanceTeams.find( return mockMaintenanceTeams.find((team) => team.id === formData.maintenanceTeamId)
(team) => team.id === formData.maintenanceTeamId
);
} }
return null; return null
}; }
const getSelectedEmployee = () => { const getSelectedEmployee = () => {
if (assignmentType === "person" && formData.assignedTo) { if (assignmentType === 'person' && formData.assignedTo) {
return mockEmployees.find((emp) => emp.fullName === formData.assignedTo); return mockEmployees.find((emp) => emp.fullName === formData.assignedTo)
} }
return null; return null
}; }
if (!isOpen) return null; if (!isOpen) return null
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -95,10 +87,7 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
<FaUserCog className="w-5 h-5 mr-2 text-blue-600" /> <FaUserCog className="w-5 h-5 mr-2 text-blue-600" />
İş Emirlerini Ata İş Emirlerini Ata
</h3> </h3>
<button <button onClick={onClose} className="text-gray-400 hover:text-gray-600">
onClick={onClose}
className="text-gray-400 hover:text-gray-600"
>
<FaTimes className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>
@ -110,22 +99,15 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
</h4> </h4>
<div className="max-h-32 overflow-y-auto border border-gray-200 rounded-lg"> <div className="max-h-32 overflow-y-auto border border-gray-200 rounded-lg">
{workOrders.map((workOrder) => ( {workOrders.map((workOrder) => (
<div <div key={workOrder.id} className="p-2 border-b border-gray-100 last:border-b-0">
key={workOrder.id}
className="p-2 border-b border-gray-100 last:border-b-0"
>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<p className="font-medium text-gray-900"> <p className="font-medium text-gray-900">{workOrder.workOrderNumber}</p>
{workOrder.workOrderNumber} <p className="text-sm text-gray-600 truncate">{workOrder.description}</p>
</p>
<p className="text-sm text-gray-600 truncate">
{workOrder.description}
</p>
</div> </div>
<div className="text-right text-sm"> <div className="text-right text-sm">
<p className="text-gray-600"> <p className="text-gray-600">
Mevcut Atama: {workOrder.assignedTo || "Atanmadı"} Mevcut Atama: {workOrder.assignedTo || 'Atanmadı'}
</p> </p>
</div> </div>
</div> </div>
@ -137,43 +119,33 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
<form onSubmit={handleSubmit} className="space-y-3"> <form onSubmit={handleSubmit} className="space-y-3">
{/* Assignment Type Selection */} {/* Assignment Type Selection */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Atama Türü</label>
Atama Türü
</label>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<label className="relative"> <label className="relative">
<input <input
type="radio" type="radio"
name="assignmentType" name="assignmentType"
value="person" value="person"
checked={assignmentType === "person"} checked={assignmentType === 'person'}
onChange={(e) => onChange={(e) => setAssignmentType(e.target.value as 'person' | 'team')}
setAssignmentType(e.target.value as "person" | "team")
}
className="sr-only" className="sr-only"
/> />
<div <div
className={`p-2 border-2 rounded-lg cursor-pointer transition-colors ${ className={`p-2 border-2 rounded-lg cursor-pointer transition-colors ${
assignmentType === "person" assignmentType === 'person'
? "border-blue-500 bg-blue-50" ? 'border-blue-500 bg-blue-50'
: "border-gray-300 bg-white hover:bg-gray-50" : 'border-gray-300 bg-white hover:bg-gray-50'
}`} }`}
> >
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<FaUser <FaUser
className={`w-5 h-5 ${ className={`w-5 h-5 ${
assignmentType === "person" assignmentType === 'person' ? 'text-blue-600' : 'text-gray-400'
? "text-blue-600"
: "text-gray-400"
}`} }`}
/> />
<div> <div>
<h4 className="font-medium text-sm text-gray-900"> <h4 className="font-medium text-sm text-gray-900">Kişiye Ata</h4>
Kişiye Ata <p className="text-xs text-gray-600">Belirli bir çalışana atama yap</p>
</h4>
<p className="text-xs text-gray-600">
Belirli bir çalışana atama yap
</p>
</div> </div>
</div> </div>
</div> </div>
@ -184,34 +156,26 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
type="radio" type="radio"
name="assignmentType" name="assignmentType"
value="team" value="team"
checked={assignmentType === "team"} checked={assignmentType === 'team'}
onChange={(e) => onChange={(e) => setAssignmentType(e.target.value as 'person' | 'team')}
setAssignmentType(e.target.value as "person" | "team")
}
className="sr-only" className="sr-only"
/> />
<div <div
className={`p-2 border-2 rounded-lg cursor-pointer transition-colors ${ className={`p-2 border-2 rounded-lg cursor-pointer transition-colors ${
assignmentType === "team" assignmentType === 'team'
? "border-blue-500 bg-blue-50" ? 'border-blue-500 bg-blue-50'
: "border-gray-300 bg-white hover:bg-gray-50" : 'border-gray-300 bg-white hover:bg-gray-50'
}`} }`}
> >
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<FaUsers <FaUsers
className={`w-5 h-5 ${ className={`w-5 h-5 ${
assignmentType === "team" assignmentType === 'team' ? 'text-blue-600' : 'text-gray-400'
? "text-blue-600"
: "text-gray-400"
}`} }`}
/> />
<div> <div>
<h4 className="font-medium text-sm text-gray-900"> <h4 className="font-medium text-sm text-gray-900">Ekibe Ata</h4>
Ekibe Ata <p className="text-xs text-gray-600">Bakım ekibine atama yap</p>
</h4>
<p className="text-xs text-gray-600">
Bakım ekibine atama yap
</p>
</div> </div>
</div> </div>
</div> </div>
@ -220,7 +184,7 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
</div> </div>
{/* Person Assignment */} {/* Person Assignment */}
{assignmentType === "person" && ( {assignmentType === 'person' && (
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">
<FaUser className="w-4 h-4 inline mr-2" /> <FaUser className="w-4 h-4 inline mr-2" />
@ -228,11 +192,9 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
</label> </label>
<select <select
value={formData.assignedTo} value={formData.assignedTo}
onChange={(e) => onChange={(e) => setFormData({ ...formData, assignedTo: e.target.value })}
setFormData({ ...formData, assignedTo: e.target.value })
}
className={`w-full px-2 py-1 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-2 py-1 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.assignedTo ? "border-red-500" : "border-gray-300" errors.assignedTo ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
<option value="">Kişi Seçin</option> <option value="">Kişi Seçin</option>
@ -249,7 +211,7 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
)} )}
{/* Team Assignment */} {/* Team Assignment */}
{assignmentType === "team" && ( {assignmentType === 'team' && (
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">
<FaUsers className="w-4 h-4 inline mr-2" /> <FaUsers className="w-4 h-4 inline mr-2" />
@ -264,9 +226,7 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
}) })
} }
className={`w-full px-2 py-1 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-2 py-1 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.maintenanceTeamId errors.maintenanceTeamId ? 'border-red-500' : 'border-gray-300'
? "border-red-500"
: "border-gray-300"
}`} }`}
> >
<option value="">Ekip Seçin</option> <option value="">Ekip Seçin</option>
@ -277,31 +237,23 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
))} ))}
</select> </select>
{errors.maintenanceTeamId && ( {errors.maintenanceTeamId && (
<p className="mt-1 text-xs text-red-600"> <p className="mt-1 text-xs text-red-600">{errors.maintenanceTeamId}</p>
{errors.maintenanceTeamId}
</p>
)} )}
</div> </div>
)} )}
{/* Team Details */} {/* Team Details */}
{assignmentType === "team" && getSelectedTeam() && ( {assignmentType === 'team' && getSelectedTeam() && (
<div className="bg-blue-50 border border-blue-200 rounded-lg p-2"> <div className="bg-blue-50 border border-blue-200 rounded-lg p-2">
<h5 className="font-medium text-sm text-blue-900 mb-2"> <h5 className="font-medium text-sm text-blue-900 mb-2">Ekip Detayları</h5>
Ekip Detayları
</h5>
<div className="space-y-2 text-sm"> <div className="space-y-2 text-sm">
<div> <div>
<span className="text-blue-700">Ekip Adı:</span> <span className="text-blue-700">Ekip Adı:</span>
<span className="ml-2 font-medium"> <span className="ml-2 font-medium">{getSelectedTeam()?.name}</span>
{getSelectedTeam()?.name}
</span>
</div> </div>
<div> <div>
<span className="text-blue-700">Üye Sayısı:</span> <span className="text-blue-700">Üye Sayısı:</span>
<span className="ml-2 font-medium"> <span className="ml-2 font-medium">{getSelectedTeam()?.members.length}</span>
{getSelectedTeam()?.members.length}
</span>
</div> </div>
<div> <div>
<span className="text-blue-700">Uzmanlık Alanları:</span> <span className="text-blue-700">Uzmanlık Alanları:</span>
@ -321,17 +273,13 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
)} )}
{/* Employee Details */} {/* Employee Details */}
{assignmentType === "person" && getSelectedEmployee() && ( {assignmentType === 'person' && getSelectedEmployee() && (
<div className="bg-green-50 border border-green-200 rounded-lg p-2"> <div className="bg-green-50 border border-green-200 rounded-lg p-2">
<h5 className="font-medium text-sm text-green-900 mb-2"> <h5 className="font-medium text-sm text-green-900 mb-2">Çalışan Detayları</h5>
Çalışan Detayları
</h5>
<div className="space-y-2 text-sm"> <div className="space-y-2 text-sm">
<div> <div>
<span className="text-green-700">Ad Soyad:</span> <span className="text-green-700">Ad Soyad:</span>
<span className="ml-2 font-medium"> <span className="ml-2 font-medium">{getSelectedEmployee()?.fullName}</span>
{getSelectedEmployee()?.fullName}
</span>
</div> </div>
<div> <div>
<span className="text-green-700">Pozisyon:</span> <span className="text-green-700">Pozisyon:</span>
@ -351,14 +299,10 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
{/* Notes */} {/* Notes */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Atama Notları</label>
Atama Notları
</label>
<textarea <textarea
value={formData.notes} value={formData.notes}
onChange={(e) => onChange={(e) => setFormData({ ...formData, notes: e.target.value })}
setFormData({ ...formData, notes: e.target.value })
}
rows={2} rows={2}
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" 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="Atama ile ilgili notlar..." placeholder="Atama ile ilgili notlar..."
@ -367,9 +311,7 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
{/* Assignment Preview */} {/* Assignment Preview */}
<div className="bg-gray-50 rounded-lg p-2"> <div className="bg-gray-50 rounded-lg p-2">
<h5 className="font-medium text-sm text-gray-900 mb-2"> <h5 className="font-medium text-sm text-gray-900 mb-2">Atama Önizlemesi</h5>
Atama Önizlemesi
</h5>
<div className="space-y-2 text-sm"> <div className="space-y-2 text-sm">
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600">İş Emri Sayısı:</span> <span className="text-gray-600">İş Emri Sayısı:</span>
@ -378,19 +320,17 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600">Atama Türü:</span> <span className="text-gray-600">Atama Türü:</span>
<span className="font-medium"> <span className="font-medium">
{assignmentType === "person" ? "Kişiye Atama" : "Ekip Atama"} {assignmentType === 'person' ? 'Kişiye Atama' : 'Ekip Atama'}
</span> </span>
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600"> <span className="text-gray-600">
{assignmentType === "person" {assignmentType === 'person' ? 'Atanan Kişi:' : 'Atanan Ekip:'}
? "Atanan Kişi:"
: "Atanan Ekip:"}
</span> </span>
<span className="font-medium"> <span className="font-medium">
{assignmentType === "person" {assignmentType === 'person'
? formData.assignedTo || "Seçilmedi" ? formData.assignedTo || 'Seçilmedi'
: getSelectedTeam()?.name || "Seçilmedi"} : getSelectedTeam()?.name || 'Seçilmedi'}
</span> </span>
</div> </div>
</div> </div>
@ -416,7 +356,7 @@ const AssignWorkOrderModal: React.FC<AssignWorkOrderModalProps> = ({
</form> </form>
</div> </div>
</div> </div>
); )
}; }
export default AssignWorkOrderModal; export default AssignWorkOrderModal

View file

@ -1,43 +1,43 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaSave, FaExclamationTriangle } from "react-icons/fa"; import { FaTimes, FaSave, FaExclamationTriangle } from 'react-icons/fa'
import { PmFaultNotification, NotificationStatusEnum } from "../../../types/pm"; import { PmFaultNotification, NotificationStatusEnum } from '../../../types/pm'
import { import { getNotificationStatusColor, getNotificationStatusText } from '../../../utils/erp'
getNotificationStatusColor,
getNotificationStatusText,
} from "../../../utils/erp";
interface ChangeNotificationStatusModalProps { interface ChangeNotificationStatusModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (statusChange: { onSave: (statusChange: {
notificationIds: string[]; notificationIds: string[]
status: NotificationStatusEnum; status: NotificationStatusEnum
notes?: string; notes?: string
}) => void; }) => void
notifications: PmFaultNotification[]; notifications: PmFaultNotification[]
} }
const ChangeNotificationStatusModal: React.FC< const ChangeNotificationStatusModal: React.FC<ChangeNotificationStatusModalProps> = ({
ChangeNotificationStatusModalProps isOpen,
> = ({ isOpen, onClose, onSave, notifications }) => { onClose,
onSave,
notifications,
}) => {
const [newStatus, setNewStatus] = useState<NotificationStatusEnum>( const [newStatus, setNewStatus] = useState<NotificationStatusEnum>(
NotificationStatusEnum.InProgress NotificationStatusEnum.InProgress,
); )
const [notes, setNotes] = useState(""); const [notes, setNotes] = useState('')
const [errors, setErrors] = useState<Record<string, string>>({}); const [errors, setErrors] = useState<Record<string, string>>({})
if (!isOpen || notifications.length === 0) return null; if (!isOpen || notifications.length === 0) return null
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (!newStatus) { if (!newStatus) {
newErrors.status = "Durum seçimi gerekli"; newErrors.status = 'Durum seçimi gerekli'
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleSave = () => { const handleSave = () => {
if (validateForm()) { if (validateForm()) {
@ -45,42 +45,40 @@ const ChangeNotificationStatusModal: React.FC<
notificationIds: notifications.map((n) => n.id), notificationIds: notifications.map((n) => n.id),
status: newStatus, status: newStatus,
notes: notes.trim() || undefined, notes: notes.trim() || undefined,
}; }
onSave(statusChangeData); onSave(statusChangeData)
onClose(); onClose()
// Reset form // Reset form
setNewStatus(NotificationStatusEnum.InProgress); setNewStatus(NotificationStatusEnum.InProgress)
setNotes(""); setNotes('')
setErrors({}); setErrors({})
} }
}; }
const getCurrentStatuses = () => { const getCurrentStatuses = () => {
const statusCounts = notifications.reduce((acc, notification) => { const statusCounts = notifications.reduce(
acc[notification.status] = (acc[notification.status] || 0) + 1; (acc, notification) => {
return acc; acc[notification.status] = (acc[notification.status] || 0) + 1
}, {} as Record<NotificationStatusEnum, number>); return acc
},
{} as Record<NotificationStatusEnum, number>,
)
return Object.entries(statusCounts).map(([status, count]) => ({ return Object.entries(statusCounts).map(([status, count]) => ({
status: status as NotificationStatusEnum, status: status as NotificationStatusEnum,
count, count,
})); }))
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <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"> <div className="bg-white rounded-lg w-full max-w-2xl mx-4 max-h-[90vh] overflow-y-auto">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">Durum Değiştir</h2>
Durum Değiştir <button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors">
</h2>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors"
>
<FaTimes className="w-6 h-6" /> <FaTimes className="w-6 h-6" />
</button> </button>
</div> </div>
@ -95,20 +93,18 @@ const ChangeNotificationStatusModal: React.FC<
<div className="space-y-1"> <div className="space-y-1">
{notifications.map((notification) => ( {notifications.map((notification) => (
<div key={notification.id} className="text-sm text-blue-700"> <div key={notification.id} className="text-sm text-blue-700">
<span className="font-medium"> <span className="font-medium">{notification.notificationCode}</span>
{notification.notificationCode} {' - '}
</span>
{" - "}
<span>{notification.title}</span> <span>{notification.title}</span>
{" ("} {' ('}
<span <span
className={`px-2 py-1 rounded-full text-xs ${getNotificationStatusColor( className={`px-2 py-1 rounded-full text-xs ${getNotificationStatusColor(
notification.status notification.status,
)}`} )}`}
> >
{getNotificationStatusText(notification.status)} {getNotificationStatusText(notification.status)}
</span> </span>
{")"} {')'}
</div> </div>
))} ))}
</div> </div>
@ -116,15 +112,13 @@ const ChangeNotificationStatusModal: React.FC<
{/* Current Status Summary */} {/* Current Status Summary */}
<div className="bg-gray-50 border border-gray-200 rounded-lg p-3"> <div className="bg-gray-50 border border-gray-200 rounded-lg p-3">
<h4 className="text-xs font-medium text-gray-800 mb-2"> <h4 className="text-xs font-medium text-gray-800 mb-2">Mevcut Durumlar</h4>
Mevcut Durumlar
</h4>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{getCurrentStatuses().map(({ status, count }) => ( {getCurrentStatuses().map(({ status, count }) => (
<span <span
key={status} key={status}
className={`px-2 py-1 rounded-full text-xs font-medium ${getNotificationStatusColor( className={`px-2 py-1 rounded-full text-xs font-medium ${getNotificationStatusColor(
status status,
)}`} )}`}
> >
{getNotificationStatusText(status)}: {count} {getNotificationStatusText(status)}: {count}
@ -135,32 +129,22 @@ const ChangeNotificationStatusModal: React.FC<
{/* New Status Selection */} {/* New Status Selection */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Yeni Durum *</label>
Yeni Durum *
</label>
<select <select
value={newStatus} value={newStatus}
onChange={(e) => onChange={(e) => setNewStatus(e.target.value as NotificationStatusEnum)}
setNewStatus(e.target.value as NotificationStatusEnum)
}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.status ? "border-red-500" : "border-gray-300" errors.status ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
<option value={NotificationStatusEnum.Open}>ık</option> <option value={NotificationStatusEnum.Open}>ık</option>
<option value={NotificationStatusEnum.Assigned}>Atandı</option> <option value={NotificationStatusEnum.Assigned}>Atandı</option>
<option value={NotificationStatusEnum.InProgress}> <option value={NotificationStatusEnum.InProgress}>Devam Ediyor</option>
Devam Ediyor
</option>
<option value={NotificationStatusEnum.Resolved}>Çözüldü</option> <option value={NotificationStatusEnum.Resolved}>Çözüldü</option>
<option value={NotificationStatusEnum.Closed}>Kapatıldı</option> <option value={NotificationStatusEnum.Closed}>Kapatıldı</option>
<option value={NotificationStatusEnum.Rejected}> <option value={NotificationStatusEnum.Rejected}>Reddedildi</option>
Reddedildi
</option>
</select> </select>
{errors.status && ( {errors.status && <p className="text-red-500 text-sm mt-1">{errors.status}</p>}
<p className="text-red-500 text-sm mt-1">{errors.status}</p>
)}
</div> </div>
{/* Status Change Preview */} {/* Status Change Preview */}
@ -168,18 +152,16 @@ const ChangeNotificationStatusModal: React.FC<
<div className="flex items-start space-x-3"> <div className="flex items-start space-x-3">
<FaExclamationTriangle className="w-5 h-5 text-green-600 mt-0.5" /> <FaExclamationTriangle className="w-5 h-5 text-green-600 mt-0.5" />
<div className="flex-1"> <div className="flex-1">
<h4 className="text-sm font-medium text-green-800 mb-1"> <h4 className="text-sm font-medium text-green-800 mb-1">Durum Değişikliği</h4>
Durum Değişikliği
</h4>
<p className="text-sm text-green-700"> <p className="text-sm text-green-700">
<strong>{notifications.length}</strong> arıza bildirimi{" "} <strong>{notifications.length}</strong> arıza bildirimi{' '}
<span <span
className={`px-2 py-1 rounded-full text-xs ${getNotificationStatusColor( className={`px-2 py-1 rounded-full text-xs ${getNotificationStatusColor(
newStatus newStatus,
)}`} )}`}
> >
{getNotificationStatusText(newStatus)} {getNotificationStatusText(newStatus)}
</span>{" "} </span>{' '}
durumuna geçirilecek. durumuna geçirilecek.
</p> </p>
</div> </div>
@ -207,12 +189,10 @@ const ChangeNotificationStatusModal: React.FC<
<div className="flex items-start space-x-3"> <div className="flex items-start space-x-3">
<FaExclamationTriangle className="w-5 h-5 text-yellow-600 mt-0.5" /> <FaExclamationTriangle className="w-5 h-5 text-yellow-600 mt-0.5" />
<div className="flex-1"> <div className="flex-1">
<h4 className="text-sm font-medium text-yellow-800 mb-1"> <h4 className="text-sm font-medium text-yellow-800 mb-1">Dikkat!</h4>
Dikkat!
</h4>
<p className="text-sm text-yellow-700"> <p className="text-sm text-yellow-700">
Bu durum değişikliği kalıcıdır ve bildirimlerin aktif Bu durum değişikliği kalıcıdır ve bildirimlerin aktif süreçlerden çıkarılmasına
süreçlerden çıkarılmasına neden olabilir. neden olabilir.
</p> </p>
</div> </div>
</div> </div>
@ -238,7 +218,7 @@ const ChangeNotificationStatusModal: React.FC<
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default ChangeNotificationStatusModal; export default ChangeNotificationStatusModal

View file

@ -1,32 +1,23 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { import { FaTimes, FaExchangeAlt, FaCheck, FaPause, FaTimesCircle } from 'react-icons/fa'
FaTimes, import { PmMaintenanceWorkOrder, WorkOrderStatusEnum } from '../../../types/pm'
FaExchangeAlt,
FaCheck,
FaPause,
FaTimesCircle,
} from "react-icons/fa";
import { PmMaintenanceWorkOrder, WorkOrderStatusEnum } from "../../../types/pm";
import { import {
getWorkOrderStatusColor, getWorkOrderStatusColor,
getWorkOrderStatusText, getWorkOrderStatusText,
getWorkOrderStatusIcon, getWorkOrderStatusIcon,
} from "../../../utils/erp"; } from '../../../utils/erp'
interface ChangeWorkOrderStatusModalProps { interface ChangeWorkOrderStatusModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onStatusChange: ( onStatusChange: (workOrders: PmMaintenanceWorkOrder[], statusData: StatusChangeData) => void
workOrders: PmMaintenanceWorkOrder[], workOrders: PmMaintenanceWorkOrder[]
statusData: StatusChangeData
) => void;
workOrders: PmMaintenanceWorkOrder[];
} }
interface StatusChangeData { interface StatusChangeData {
newStatus: WorkOrderStatusEnum; newStatus: WorkOrderStatusEnum
notes?: string; notes?: string
completionNotes?: string; completionNotes?: string
} }
const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
@ -37,47 +28,40 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
}) => { }) => {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
newStatus: WorkOrderStatusEnum.InProgress, newStatus: WorkOrderStatusEnum.InProgress,
notes: "", notes: '',
completionNotes: "", completionNotes: '',
}); })
const [errors, setErrors] = useState<Record<string, string>>({}); const [errors, setErrors] = useState<Record<string, string>>({})
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if ( if (formData.newStatus === WorkOrderStatusEnum.Completed && !formData.completionNotes.trim()) {
formData.newStatus === WorkOrderStatusEnum.Completed && newErrors.completionNotes = 'Tamamlanan iş emirleri için tamamlanma notları zorunludur'
!formData.completionNotes.trim()
) {
newErrors.completionNotes =
"Tamamlanan iş emirleri için tamamlanma notları zorunludur";
} }
if ( if (formData.newStatus === WorkOrderStatusEnum.Cancelled && !formData.notes.trim()) {
formData.newStatus === WorkOrderStatusEnum.Cancelled && newErrors.notes = 'İptal edilen iş emirleri için iptal nedeni zorunludur'
!formData.notes.trim()
) {
newErrors.notes = "İptal edilen iş emirleri için iptal nedeni zorunludur";
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault()
if (!validateForm()) return; if (!validateForm()) return
const statusData: StatusChangeData = { const statusData: StatusChangeData = {
newStatus: formData.newStatus, newStatus: formData.newStatus,
notes: formData.notes || undefined, notes: formData.notes || undefined,
completionNotes: formData.completionNotes || undefined, completionNotes: formData.completionNotes || undefined,
}; }
onStatusChange(workOrders, statusData); onStatusChange(workOrders, statusData)
onClose(); onClose()
}; }
const getStatusCounts = () => { const getStatusCounts = () => {
const counts: Record<WorkOrderStatusEnum, number> = { const counts: Record<WorkOrderStatusEnum, number> = {
@ -88,43 +72,42 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
[WorkOrderStatusEnum.OnHold]: 0, [WorkOrderStatusEnum.OnHold]: 0,
[WorkOrderStatusEnum.Completed]: 0, [WorkOrderStatusEnum.Completed]: 0,
[WorkOrderStatusEnum.Cancelled]: 0, [WorkOrderStatusEnum.Cancelled]: 0,
}; }
workOrders.forEach((wo) => { workOrders.forEach((wo) => {
counts[wo.status]++; counts[wo.status]++
}); })
return counts; return counts
}; }
const canChangeToStatus = (status: WorkOrderStatusEnum) => { const canChangeToStatus = (status: WorkOrderStatusEnum) => {
// İş emirlerinin mevcut durumlarına göre hangi durumlara geçebileceğini kontrol et // İş emirlerinin mevcut durumlarına göre hangi durumlara geçebileceğini kontrol et
return workOrders.some((wo) => { return workOrders.some((wo) => {
switch (status) { switch (status) {
case WorkOrderStatusEnum.Planned: case WorkOrderStatusEnum.Planned:
return wo.status === WorkOrderStatusEnum.Created; return wo.status === WorkOrderStatusEnum.Created
case WorkOrderStatusEnum.Released: case WorkOrderStatusEnum.Released:
return wo.status === WorkOrderStatusEnum.Planned; return wo.status === WorkOrderStatusEnum.Planned
case WorkOrderStatusEnum.InProgress: case WorkOrderStatusEnum.InProgress:
return ( return (
wo.status === WorkOrderStatusEnum.Released || wo.status === WorkOrderStatusEnum.Released || wo.status === WorkOrderStatusEnum.OnHold
wo.status === WorkOrderStatusEnum.OnHold )
);
case WorkOrderStatusEnum.OnHold: case WorkOrderStatusEnum.OnHold:
return wo.status === WorkOrderStatusEnum.InProgress; return wo.status === WorkOrderStatusEnum.InProgress
case WorkOrderStatusEnum.Completed: case WorkOrderStatusEnum.Completed:
return wo.status === WorkOrderStatusEnum.InProgress; return wo.status === WorkOrderStatusEnum.InProgress
case WorkOrderStatusEnum.Cancelled: case WorkOrderStatusEnum.Cancelled:
return wo.status !== WorkOrderStatusEnum.Completed; return wo.status !== WorkOrderStatusEnum.Completed
default: default:
return false; return false
} }
}); })
}; }
if (!isOpen) return null; if (!isOpen) return null
const statusCounts = getStatusCounts(); const statusCounts = getStatusCounts()
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -134,10 +117,7 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
<FaExchangeAlt className="w-5 h-5 mr-2 text-orange-600" /> <FaExchangeAlt className="w-5 h-5 mr-2 text-orange-600" />
İş Emri Durumunu Değiştir İş Emri Durumunu Değiştir
</h3> </h3>
<button <button onClick={onClose} className="text-gray-400 hover:text-gray-600">
onClick={onClose}
className="text-gray-400 hover:text-gray-600"
>
<FaTimes className="w-6 h-6" /> <FaTimes className="w-6 h-6" />
</button> </button>
</div> </div>
@ -150,46 +130,36 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
{/* Current Status Distribution */} {/* Current Status Distribution */}
<div className="mb-4"> <div className="mb-4">
<h5 className="text-sm font-medium text-gray-700 mb-2"> <h5 className="text-sm font-medium text-gray-700 mb-2">Mevcut Durum Dağılımı</h5>
Mevcut Durum Dağılımı
</h5>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{Object.entries(statusCounts).map(([status, count]) => { {Object.entries(statusCounts).map(([status, count]) => {
if (count === 0) return null; if (count === 0) return null
return ( return (
<span <span
key={status} key={status}
className={`px-2 py-1 rounded-full text-xs font-medium ${getWorkOrderStatusColor( className={`px-2 py-1 rounded-full text-xs font-medium ${getWorkOrderStatusColor(
status as WorkOrderStatusEnum status as WorkOrderStatusEnum,
)}`} )}`}
> >
{getWorkOrderStatusText(status as WorkOrderStatusEnum)}:{" "} {getWorkOrderStatusText(status as WorkOrderStatusEnum)}: {count}
{count}
</span> </span>
); )
})} })}
</div> </div>
</div> </div>
<div className="max-h-40 overflow-y-auto border border-gray-200 rounded-lg"> <div className="max-h-40 overflow-y-auto border border-gray-200 rounded-lg">
{workOrders.map((workOrder) => ( {workOrders.map((workOrder) => (
<div <div key={workOrder.id} className="p-2 border-b border-gray-100 last:border-b-0">
key={workOrder.id}
className="p-2 border-b border-gray-100 last:border-b-0"
>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<p className="font-medium text-gray-900"> <p className="font-medium text-gray-900">{workOrder.workOrderNumber}</p>
{workOrder.workOrderNumber} <p className="text-sm text-gray-600 truncate">{workOrder.description}</p>
</p>
<p className="text-sm text-gray-600 truncate">
{workOrder.description}
</p>
</div> </div>
<div className="text-right"> <div className="text-right">
<span <span
className={`px-2 py-1 rounded-full text-xs font-medium ${getWorkOrderStatusColor( className={`px-2 py-1 rounded-full text-xs font-medium ${getWorkOrderStatusColor(
workOrder.status workOrder.status,
)}`} )}`}
> >
{getWorkOrderStatusText(workOrder.status)} {getWorkOrderStatusText(workOrder.status)}
@ -204,9 +174,7 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
<form onSubmit={handleSubmit} className="space-y-4"> <form onSubmit={handleSubmit} className="space-y-4">
{/* New Status Selection */} {/* New Status Selection */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-3"> <label className="block text-sm font-medium text-gray-700 mb-3">Yeni Durum *</label>
Yeni Durum *
</label>
<div className="grid grid-cols-2 md:grid-cols-4 gap-3"> <div className="grid grid-cols-2 md:grid-cols-4 gap-3">
{[ {[
WorkOrderStatusEnum.Planned, WorkOrderStatusEnum.Planned,
@ -234,19 +202,17 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
<div <div
className={`p-2 border-2 rounded-lg cursor-pointer transition-colors ${ className={`p-2 border-2 rounded-lg cursor-pointer transition-colors ${
formData.newStatus === status formData.newStatus === status
? "border-blue-500 bg-blue-50" ? 'border-blue-500 bg-blue-50'
: canChangeToStatus(status) : canChangeToStatus(status)
? "border-gray-300 bg-white hover:bg-gray-50" ? 'border-gray-300 bg-white hover:bg-gray-50'
: "border-gray-200 bg-gray-50 cursor-not-allowed" : 'border-gray-200 bg-gray-50 cursor-not-allowed'
}`} }`}
> >
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
{getWorkOrderStatusIcon(status)} {getWorkOrderStatusIcon(status)}
<span <span
className={`text-sm font-medium ${ className={`text-sm font-medium ${
canChangeToStatus(status) canChangeToStatus(status) ? 'text-gray-900' : 'text-gray-400'
? "text-gray-900"
: "text-gray-400"
}`} }`}
> >
{getWorkOrderStatusText(status)} {getWorkOrderStatusText(status)}
@ -266,19 +232,15 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
</label> </label>
<textarea <textarea
value={formData.completionNotes} value={formData.completionNotes}
onChange={(e) => onChange={(e) => setFormData({ ...formData, completionNotes: e.target.value })}
setFormData({ ...formData, completionNotes: e.target.value })
}
rows={3} rows={3}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.completionNotes ? "border-red-500" : "border-gray-300" errors.completionNotes ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="İş emirlerinin nasıl tamamlandığına dair detaylar..." placeholder="İş emirlerinin nasıl tamamlandığına dair detaylar..."
/> />
{errors.completionNotes && ( {errors.completionNotes && (
<p className="mt-1 text-sm text-red-600"> <p className="mt-1 text-sm text-red-600">{errors.completionNotes}</p>
{errors.completionNotes}
</p>
)} )}
</div> </div>
)} )}
@ -287,27 +249,23 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">
{formData.newStatus === WorkOrderStatusEnum.Cancelled {formData.newStatus === WorkOrderStatusEnum.Cancelled
? "İptal Nedeni *" ? 'İptal Nedeni *'
: "Durum Değişikliği Notları"} : 'Durum Değişikliği Notları'}
</label> </label>
<textarea <textarea
value={formData.notes} value={formData.notes}
onChange={(e) => onChange={(e) => setFormData({ ...formData, notes: e.target.value })}
setFormData({ ...formData, notes: e.target.value })
}
rows={3} rows={3}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.notes ? "border-red-500" : "border-gray-300" errors.notes ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder={ placeholder={
formData.newStatus === WorkOrderStatusEnum.Cancelled formData.newStatus === WorkOrderStatusEnum.Cancelled
? "İptal nedenini açıklayın..." ? 'İptal nedenini açıklayın...'
: "Durum değişikliği ile ilgili notlar..." : 'Durum değişikliği ile ilgili notlar...'
} }
/> />
{errors.notes && ( {errors.notes && <p className="mt-1 text-sm text-red-600">{errors.notes}</p>}
<p className="mt-1 text-sm text-red-600">{errors.notes}</p>
)}
</div> </div>
{/* Status Change Warnings */} {/* Status Change Warnings */}
@ -318,8 +276,8 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
<div> <div>
<h5 className="font-medium text-red-800 mb-1">Uyarı</h5> <h5 className="font-medium text-red-800 mb-1">Uyarı</h5>
<p className="text-red-700 text-sm"> <p className="text-red-700 text-sm">
İş emirleri iptal edilecek. Bu işlem geri alınamaz ve tüm İş emirleri iptal edilecek. Bu işlem geri alınamaz ve tüm aktiviteler
aktiviteler durdurulacak. durdurulacak.
</p> </p>
</div> </div>
</div> </div>
@ -333,8 +291,8 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
<div> <div>
<h5 className="font-medium text-green-800 mb-1">Bilgi</h5> <h5 className="font-medium text-green-800 mb-1">Bilgi</h5>
<p className="text-green-700 text-sm"> <p className="text-green-700 text-sm">
İş emirleri tamamlandı olarak işaretlenecek. Gerçek bitiş İş emirleri tamamlandı olarak işaretlenecek. Gerçek bitiş tarihi otomatik olarak
tarihi otomatik olarak şu an olarak ayarlanacak. şu an olarak ayarlanacak.
</p> </p>
</div> </div>
</div> </div>
@ -348,8 +306,8 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
<div> <div>
<h5 className="font-medium text-yellow-800 mb-1">Bilgi</h5> <h5 className="font-medium text-yellow-800 mb-1">Bilgi</h5>
<p className="text-yellow-700 text-sm"> <p className="text-yellow-700 text-sm">
İş emirleri beklemede durumuna alınacak. Aktiviteler İş emirleri beklemede durumuna alınacak. Aktiviteler durdurulacak ancak daha
durdurulacak ancak daha sonra devam ettirilebilir. sonra devam ettirilebilir.
</p> </p>
</div> </div>
</div> </div>
@ -358,9 +316,7 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
{/* Change Preview */} {/* Change Preview */}
<div className="bg-gray-50 rounded-lg p-3"> <div className="bg-gray-50 rounded-lg p-3">
<h5 className="font-medium text-sm text-gray-900 mb-2"> <h5 className="font-medium text-sm text-gray-900 mb-2">Durum Değişikliği Önizlemesi</h5>
Durum Değişikliği Önizlemesi
</h5>
<div className="space-y-2 text-sm"> <div className="space-y-2 text-sm">
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600">Etkilenen İş Emri Sayısı:</span> <span className="text-gray-600">Etkilenen İş Emri Sayısı:</span>
@ -370,7 +326,7 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
<span className="text-gray-600">Yeni Durum:</span> <span className="text-gray-600">Yeni Durum:</span>
<span <span
className={`font-medium px-2 py-1 rounded text-xs ${getWorkOrderStatusColor( className={`font-medium px-2 py-1 rounded text-xs ${getWorkOrderStatusColor(
formData.newStatus formData.newStatus,
)}`} )}`}
> >
{getWorkOrderStatusText(formData.newStatus)} {getWorkOrderStatusText(formData.newStatus)}
@ -379,10 +335,10 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600">Değişiklik Tarihi:</span> <span className="text-gray-600">Değişiklik Tarihi:</span>
<span className="font-medium"> <span className="font-medium">
{new Date().toLocaleDateString("tr-TR")}{" "} {new Date().toLocaleDateString('tr-TR')}{' '}
{new Date().toLocaleTimeString("tr-TR", { {new Date().toLocaleTimeString('tr-TR', {
hour: "2-digit", hour: '2-digit',
minute: "2-digit", minute: '2-digit',
})} })}
</span> </span>
</div> </div>
@ -402,10 +358,10 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
type="submit" type="submit"
className={`px-4 py-1.5 text-sm text-white rounded-lg flex items-center space-x-2 ${ className={`px-4 py-1.5 text-sm text-white rounded-lg flex items-center space-x-2 ${
formData.newStatus === WorkOrderStatusEnum.Cancelled formData.newStatus === WorkOrderStatusEnum.Cancelled
? "bg-red-600 hover:bg-red-700" ? 'bg-red-600 hover:bg-red-700'
: formData.newStatus === WorkOrderStatusEnum.Completed : formData.newStatus === WorkOrderStatusEnum.Completed
? "bg-green-600 hover:bg-green-700" ? 'bg-green-600 hover:bg-green-700'
: "bg-orange-600 hover:bg-orange-700" : 'bg-orange-600 hover:bg-orange-700'
}`} }`}
> >
<FaExchangeAlt className="w-4 h-4" /> <FaExchangeAlt className="w-4 h-4" />
@ -415,7 +371,7 @@ const ChangeWorkOrderStatusModal: React.FC<ChangeWorkOrderStatusModalProps> = ({
</form> </form>
</div> </div>
</div> </div>
); )
}; }
export default ChangeWorkOrderStatusModal; export default ChangeWorkOrderStatusModal

View file

@ -1,73 +1,74 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaSave, FaExclamationTriangle } from "react-icons/fa"; import { FaTimes, FaSave, FaExclamationTriangle } from 'react-icons/fa'
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from '../../../mocks/mockEmployees'
import { mockMaintenanceTeams } from "../../../mocks/mockMaintenanceTeams"; import { mockMaintenanceTeams } from '../../../mocks/mockMaintenanceTeams'
import { PmFaultNotification, WorkOrderTypeEnum } from "../../../types/pm"; import { PmFaultNotification, WorkOrderTypeEnum } from '../../../types/pm'
import { MrpWorkOrder } from "../../../types/mrp"; import { MrpWorkOrder } from '../../../types/mrp'
import { PriorityEnum } from "../../../types/common"; import { PriorityEnum } from '../../../types/common'
interface CreateWorkOrderFromNotificationModalProps { interface CreateWorkOrderFromNotificationModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (workOrderData: MrpWorkOrder) => void; onSave: (workOrderData: MrpWorkOrder) => void
notifications: PmFaultNotification[]; notifications: PmFaultNotification[]
} }
const CreateWorkOrderFromNotificationModal: React.FC< const CreateWorkOrderFromNotificationModal: React.FC<CreateWorkOrderFromNotificationModalProps> = ({
CreateWorkOrderFromNotificationModalProps isOpen,
> = ({ isOpen, onClose, onSave, notifications }) => { onClose,
onSave,
notifications,
}) => {
const [workOrderData, setWorkOrderData] = useState({ const [workOrderData, setWorkOrderData] = useState({
workOrderNumber: `WO-${new Date().getFullYear()}-${String(Date.now()).slice( workOrderNumber: `WO-${new Date().getFullYear()}-${String(Date.now()).slice(-3)}`,
-3
)}`,
orderType: WorkOrderTypeEnum.Corrective, orderType: WorkOrderTypeEnum.Corrective,
priority: PriorityEnum.Normal, priority: PriorityEnum.Normal,
description: "", description: '',
assignedTo: "", assignedTo: '',
maintenanceTeamId: "", maintenanceTeamId: '',
scheduledStart: "", scheduledStart: '',
scheduledEnd: "", scheduledEnd: '',
estimatedCost: 0, estimatedCost: 0,
notes: "", notes: '',
}); })
const [errors, setErrors] = useState<Record<string, string>>({}); const [errors, setErrors] = useState<Record<string, string>>({})
if (!isOpen || notifications.length === 0) return null; if (!isOpen || notifications.length === 0) return null
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (!workOrderData.description.trim()) { if (!workOrderData.description.trim()) {
newErrors.description = "Açıklama gerekli"; newErrors.description = 'Açıklama gerekli'
} }
if (!workOrderData.assignedTo && !workOrderData.maintenanceTeamId) { if (!workOrderData.assignedTo && !workOrderData.maintenanceTeamId) {
newErrors.assignment = "Kişi veya ekip ataması gerekli"; newErrors.assignment = 'Kişi veya ekip ataması gerekli'
} }
if (!workOrderData.scheduledStart) { if (!workOrderData.scheduledStart) {
newErrors.scheduledStart = "Başlangıç tarihi gerekli"; newErrors.scheduledStart = 'Başlangıç tarihi gerekli'
} }
if (!workOrderData.scheduledEnd) { if (!workOrderData.scheduledEnd) {
newErrors.scheduledEnd = "Bitiş tarihi gerekli"; newErrors.scheduledEnd = 'Bitiş tarihi gerekli'
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleInputChange = (field: string, value: string | number) => { const handleInputChange = (field: string, value: string | number) => {
setWorkOrderData((prev) => ({ setWorkOrderData((prev) => ({
...prev, ...prev,
[field]: value, [field]: value,
})); }))
// Clear error when user starts typing // Clear error when user starts typing
if (errors[field]) { if (errors[field]) {
setErrors((prev) => ({ setErrors((prev) => ({
...prev, ...prev,
[field]: "", [field]: '',
})); }))
} }
}; }
const handleSave = () => { const handleSave = () => {
if (validateForm()) { if (validateForm()) {
@ -79,42 +80,35 @@ const CreateWorkOrderFromNotificationModal: React.FC<
reportedBy: notifications[0].reportedBy, reportedBy: notifications[0].reportedBy,
creationTime: new Date(), creationTime: new Date(),
lastModificationTime: new Date(), lastModificationTime: new Date(),
}; }
onSave(workOrderToSave); onSave(workOrderToSave)
onClose(); onClose()
// Reset form // Reset form
setWorkOrderData({ setWorkOrderData({
workOrderNumber: `WO-${new Date().getFullYear()}-${String( workOrderNumber: `WO-${new Date().getFullYear()}-${String(Date.now()).slice(-3)}`,
Date.now()
).slice(-3)}`,
orderType: WorkOrderTypeEnum.Corrective, orderType: WorkOrderTypeEnum.Corrective,
priority: PriorityEnum.Normal, priority: PriorityEnum.Normal,
description: "", description: '',
assignedTo: "", assignedTo: '',
maintenanceTeamId: "", maintenanceTeamId: '',
scheduledStart: "", scheduledStart: '',
scheduledEnd: "", scheduledEnd: '',
estimatedCost: 0, estimatedCost: 0,
notes: "", notes: '',
}); })
setErrors({}); setErrors({})
} }
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <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"> <div className="bg-white rounded-lg w-full max-w-3xl max-h-[90vh] overflow-y-auto">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">İş Emri Oluştur</h2>
İş Emri Oluştur <button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors">
</h2>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors"
>
<FaTimes className="w-6 h-6" /> <FaTimes className="w-6 h-6" />
</button> </button>
</div> </div>
@ -131,18 +125,13 @@ const CreateWorkOrderFromNotificationModal: React.FC<
</h4> </h4>
<div className="space-y-1"> <div className="space-y-1">
{notifications.map((notification) => ( {notifications.map((notification) => (
<div <div key={notification.id} className="text-sm text-blue-700">
key={notification.id} <span className="font-medium">{notification.notificationCode}</span>
className="text-sm text-blue-700" {' - '}
>
<span className="font-medium">
{notification.notificationCode}
</span>
{" - "}
<span>{notification.title}</span> <span>{notification.title}</span>
{" ("} {' ('}
<span>{notification.workCenter.code}</span> <span>{notification.workCenter.code}</span>
{")"} {')'}
</div> </div>
))} ))}
</div> </div>
@ -159,55 +148,36 @@ const CreateWorkOrderFromNotificationModal: React.FC<
<input <input
type="text" type="text"
value={workOrderData.workOrderNumber} value={workOrderData.workOrderNumber}
onChange={(e) => onChange={(e) => handleInputChange('workOrderNumber', e.target.value)}
handleInputChange("workOrderNumber", 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" 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="WO-2024-001" placeholder="WO-2024-001"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">İş Emri Türü</label>
İş Emri Türü
</label>
<select <select
value={workOrderData.orderType} value={workOrderData.orderType}
onChange={(e) => onChange={(e) =>
handleInputChange( handleInputChange('orderType', e.target.value as WorkOrderTypeEnum)
"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" 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={WorkOrderTypeEnum.Preventive}> <option value={WorkOrderTypeEnum.Preventive}>Önleyici Bakım</option>
Önleyici Bakım <option value={WorkOrderTypeEnum.Corrective}>Düzeltici Bakım</option>
</option> <option value={WorkOrderTypeEnum.Emergency}>Acil Müdahale</option>
<option value={WorkOrderTypeEnum.Corrective}>
Düzeltici Bakım
</option>
<option value={WorkOrderTypeEnum.Emergency}>
Acil Müdahale
</option>
<option value={WorkOrderTypeEnum.Inspection}>İnceleme</option> <option value={WorkOrderTypeEnum.Inspection}>İnceleme</option>
<option value={WorkOrderTypeEnum.Calibration}> <option value={WorkOrderTypeEnum.Calibration}>Kalibrasyon</option>
Kalibrasyon
</option>
</select> </select>
</div> </div>
</div> </div>
{/* Priority */} {/* Priority */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Öncelik</label>
Öncelik
</label>
<select <select
value={workOrderData.priority} value={workOrderData.priority}
onChange={(e) => onChange={(e) => handleInputChange('priority', e.target.value as PriorityEnum)}
handleInputChange("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" 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.Low}>Düşük</option>
@ -219,15 +189,13 @@ const CreateWorkOrderFromNotificationModal: React.FC<
{/* Description */} {/* Description */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">ıklama *</label>
ıklama *
</label>
<textarea <textarea
value={workOrderData.description} value={workOrderData.description}
onChange={(e) => handleInputChange("description", e.target.value)} onChange={(e) => handleInputChange('description', e.target.value)}
rows={4} rows={4}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.description ? "border-red-500" : "border-gray-300" errors.description ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="İş emri detayları ve yapılacak işlemler" placeholder="İş emri detayları ve yapılacak işlemler"
/> />
@ -239,15 +207,13 @@ const CreateWorkOrderFromNotificationModal: React.FC<
{/* Assignment */} {/* Assignment */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Atanan Kişi</label>
Atanan Kişi
</label>
<select <select
value={workOrderData.assignedTo} value={workOrderData.assignedTo}
onChange={(e) => { onChange={(e) => {
handleInputChange("assignedTo", e.target.value); handleInputChange('assignedTo', e.target.value)
if (e.target.value) { if (e.target.value) {
handleInputChange("maintenanceTeamId", ""); handleInputChange('maintenanceTeamId', '')
} }
}} }}
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" 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"
@ -262,15 +228,13 @@ const CreateWorkOrderFromNotificationModal: React.FC<
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Atanan Ekip</label>
Atanan Ekip
</label>
<select <select
value={workOrderData.maintenanceTeamId} value={workOrderData.maintenanceTeamId}
onChange={(e) => { onChange={(e) => {
handleInputChange("maintenanceTeamId", e.target.value); handleInputChange('maintenanceTeamId', e.target.value)
if (e.target.value) { if (e.target.value) {
handleInputChange("assignedTo", ""); handleInputChange('assignedTo', '')
} }
}} }}
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" 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"
@ -284,9 +248,7 @@ const CreateWorkOrderFromNotificationModal: React.FC<
</select> </select>
</div> </div>
</div> </div>
{errors.assignment && ( {errors.assignment && <p className="text-red-500 text-sm mt-1">{errors.assignment}</p>}
<p className="text-red-500 text-sm mt-1">{errors.assignment}</p>
)}
{/* Schedule */} {/* Schedule */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
@ -297,17 +259,13 @@ const CreateWorkOrderFromNotificationModal: React.FC<
<input <input
type="datetime-local" type="datetime-local"
value={workOrderData.scheduledStart} value={workOrderData.scheduledStart}
onChange={(e) => onChange={(e) => handleInputChange('scheduledStart', e.target.value)}
handleInputChange("scheduledStart", e.target.value)
}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.scheduledStart ? "border-red-500" : "border-gray-300" errors.scheduledStart ? 'border-red-500' : 'border-gray-300'
}`} }`}
/> />
{errors.scheduledStart && ( {errors.scheduledStart && (
<p className="text-red-500 text-sm mt-1"> <p className="text-red-500 text-sm mt-1">{errors.scheduledStart}</p>
{errors.scheduledStart}
</p>
)} )}
</div> </div>
@ -318,17 +276,13 @@ const CreateWorkOrderFromNotificationModal: React.FC<
<input <input
type="datetime-local" type="datetime-local"
value={workOrderData.scheduledEnd} value={workOrderData.scheduledEnd}
onChange={(e) => onChange={(e) => handleInputChange('scheduledEnd', e.target.value)}
handleInputChange("scheduledEnd", e.target.value)
}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.scheduledEnd ? "border-red-500" : "border-gray-300" errors.scheduledEnd ? 'border-red-500' : 'border-gray-300'
}`} }`}
/> />
{errors.scheduledEnd && ( {errors.scheduledEnd && (
<p className="text-red-500 text-sm mt-1"> <p className="text-red-500 text-sm mt-1">{errors.scheduledEnd}</p>
{errors.scheduledEnd}
</p>
)} )}
</div> </div>
</div> </div>
@ -341,12 +295,7 @@ const CreateWorkOrderFromNotificationModal: React.FC<
<input <input
type="number" type="number"
value={workOrderData.estimatedCost} value={workOrderData.estimatedCost}
onChange={(e) => onChange={(e) => handleInputChange('estimatedCost', parseFloat(e.target.value) || 0)}
handleInputChange(
"estimatedCost",
parseFloat(e.target.value) || 0
)
}
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" 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="0.00" placeholder="0.00"
min="0" min="0"
@ -356,12 +305,10 @@ const CreateWorkOrderFromNotificationModal: React.FC<
{/* Notes */} {/* Notes */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Notlar</label>
Notlar
</label>
<textarea <textarea
value={workOrderData.notes} value={workOrderData.notes}
onChange={(e) => handleInputChange("notes", e.target.value)} onChange={(e) => handleInputChange('notes', e.target.value)}
rows={3} rows={3}
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" 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="Ek notlar ve özel talimatlar" placeholder="Ek notlar ve özel talimatlar"
@ -387,7 +334,7 @@ const CreateWorkOrderFromNotificationModal: React.FC<
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default CreateWorkOrderFromNotificationModal; export default CreateWorkOrderFromNotificationModal

View file

@ -1,20 +1,20 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaSave, FaExclamationTriangle } from "react-icons/fa"; import { FaTimes, FaSave, FaExclamationTriangle } from 'react-icons/fa'
import { import {
PmMaintenancePlan, PmMaintenancePlan,
PmMaintenanceWorkOrder, PmMaintenanceWorkOrder,
WorkOrderStatusEnum, WorkOrderStatusEnum,
WorkOrderTypeEnum, WorkOrderTypeEnum,
} from "../../../types/pm"; } from '../../../types/pm'
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from '../../../mocks/mockEmployees'
import { PriorityEnum } from "../../../types/common"; import { PriorityEnum } from '../../../types/common'
import { getPriorityColor } from "../../../utils/erp"; import { getPriorityColor } from '../../../utils/erp'
interface CreateWorkOrderModalProps { interface CreateWorkOrderModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (workOrders: Partial<PmMaintenanceWorkOrder>[]) => void; onSave: (workOrders: Partial<PmMaintenanceWorkOrder>[]) => void
selectedPlans: PmMaintenancePlan[]; selectedPlans: PmMaintenancePlan[]
} }
const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
@ -24,64 +24,54 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
selectedPlans, selectedPlans,
}) => { }) => {
const [commonSettings, setCommonSettings] = useState({ const [commonSettings, setCommonSettings] = useState({
scheduledStartDate: new Date().toISOString().split("T")[0], scheduledStartDate: new Date().toISOString().split('T')[0],
priority: PriorityEnum.Normal, priority: PriorityEnum.Normal,
assignedTo: "", assignedTo: '',
notes: "", notes: '',
createSeparateOrders: true, createSeparateOrders: true,
}); })
const [individualSettings, setIndividualSettings] = useState<{ const [individualSettings, setIndividualSettings] = useState<{
[key: string]: { [key: string]: {
scheduledStartDate?: string; scheduledStartDate?: string
priority?: PriorityEnum; priority?: PriorityEnum
assignedTo?: string; assignedTo?: string
notes?: string; notes?: string
}; }
}>({}); }>({})
if (!isOpen) return null; if (!isOpen) return null
const handleCommonChange = ( const handleCommonChange = (field: string, value: string | PriorityEnum | boolean) => {
field: string,
value: string | PriorityEnum | boolean
) => {
setCommonSettings((prev) => ({ setCommonSettings((prev) => ({
...prev, ...prev,
[field]: value, [field]: value,
})); }))
}; }
const handleIndividualChange = ( const handleIndividualChange = (planId: string, field: string, value: string | PriorityEnum) => {
planId: string,
field: string,
value: string | PriorityEnum
) => {
setIndividualSettings((prev) => ({ setIndividualSettings((prev) => ({
...prev, ...prev,
[planId]: { [planId]: {
...prev[planId], ...prev[planId],
[field]: value, [field]: value,
}, },
})); }))
}; }
const generateWorkOrderCode = (plan: PmMaintenancePlan, index: number) => { const generateWorkOrderCode = (plan: PmMaintenancePlan, index: number) => {
const date = new Date(); const date = new Date()
const dateStr = date.toISOString().slice(0, 10).replace(/-/g, ""); const dateStr = date.toISOString().slice(0, 10).replace(/-/g, '')
return `WO-${plan.planCode}-${dateStr}-${String(index + 1).padStart( return `WO-${plan.planCode}-${dateStr}-${String(index + 1).padStart(3, '0')}`
3, }
"0"
)}`;
};
const handleSave = () => { const handleSave = () => {
const workOrders: Partial<PmMaintenanceWorkOrder>[] = []; const workOrders: Partial<PmMaintenanceWorkOrder>[] = []
if (commonSettings.createSeparateOrders) { if (commonSettings.createSeparateOrders) {
// Her plan için ayrı iş emri oluştur // Her plan için ayrı iş emri oluştur
selectedPlans.forEach((plan, index) => { selectedPlans.forEach((plan, index) => {
const individual = individualSettings[plan.id] || {}; const individual = individualSettings[plan.id] || {}
const workOrder: Partial<PmMaintenanceWorkOrder> = { const workOrder: Partial<PmMaintenanceWorkOrder> = {
workOrderNumber: generateWorkOrderCode(plan, index), workOrderNumber: generateWorkOrderCode(plan, index),
planId: plan.id, planId: plan.id,
@ -91,16 +81,14 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
status: WorkOrderStatusEnum.Planned, status: WorkOrderStatusEnum.Planned,
description: `${plan.description} - Bakım Planı: ${plan.planCode}`, description: `${plan.description} - Bakım Planı: ${plan.planCode}`,
scheduledStart: new Date( scheduledStart: new Date(
individual.scheduledStartDate || commonSettings.scheduledStartDate individual.scheduledStartDate || commonSettings.scheduledStartDate,
), ),
scheduledEnd: new Date( scheduledEnd: new Date(
new Date( new Date(individual.scheduledStartDate || commonSettings.scheduledStartDate).getTime() +
individual.scheduledStartDate || commonSettings.scheduledStartDate plan.estimatedDuration * 60000,
).getTime() +
plan.estimatedDuration * 60000
), ),
assignedTo: individual.assignedTo || commonSettings.assignedTo, assignedTo: individual.assignedTo || commonSettings.assignedTo,
reportedBy: "System", reportedBy: 'System',
estimatedCost: 0, estimatedCost: 0,
actualCost: 0, actualCost: 0,
materials: [], materials: [],
@ -108,25 +96,20 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
notes: individual.notes || commonSettings.notes, notes: individual.notes || commonSettings.notes,
creationTime: new Date(), creationTime: new Date(),
lastModificationTime: new Date(), lastModificationTime: new Date(),
}; }
workOrders.push(workOrder); workOrders.push(workOrder)
}); })
} else { } else {
// Tek bir toplu iş emri oluştur // Tek bir toplu iş emri oluştur
const combinedPlanCodes = selectedPlans.map((p) => p.planCode).join(", "); const combinedPlanCodes = selectedPlans.map((p) => p.planCode).join(', ')
const combinedWorkCenterIds = [ const combinedWorkCenterIds = [...new Set(selectedPlans.map((p) => p.workCenterId))]
...new Set(selectedPlans.map((p) => p.workCenterId)), const totalDuration = selectedPlans.reduce((sum, plan) => sum + plan.estimatedDuration, 0)
];
const totalDuration = selectedPlans.reduce(
(sum, plan) => sum + plan.estimatedDuration,
0
);
const workOrder: Partial<PmMaintenanceWorkOrder> = { const workOrder: Partial<PmMaintenanceWorkOrder> = {
workOrderNumber: `WO-BULK-${new Date() workOrderNumber: `WO-BULK-${new Date()
.toISOString() .toISOString()
.slice(0, 10) .slice(0, 10)
.replace(/-/g, "")}-${String(Date.now()).slice(-3)}`, .replace(/-/g, '')}-${String(Date.now()).slice(-3)}`,
workCenterId: combinedWorkCenterIds[0], // Ana İş merkezleri workCenterId: combinedWorkCenterIds[0], // Ana İş merkezleri
orderType: WorkOrderTypeEnum.Preventive, orderType: WorkOrderTypeEnum.Preventive,
priority: commonSettings.priority, priority: commonSettings.priority,
@ -134,34 +117,33 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
description: `Toplu Bakım İş Emri - Planlar: ${combinedPlanCodes}`, description: `Toplu Bakım İş Emri - Planlar: ${combinedPlanCodes}`,
scheduledStart: new Date(commonSettings.scheduledStartDate), scheduledStart: new Date(commonSettings.scheduledStartDate),
scheduledEnd: new Date( scheduledEnd: new Date(
new Date(commonSettings.scheduledStartDate).getTime() + new Date(commonSettings.scheduledStartDate).getTime() + totalDuration * 60000,
totalDuration * 60000
), ),
reportedBy: "System", reportedBy: 'System',
estimatedCost: 0, estimatedCost: 0,
actualCost: 0, actualCost: 0,
materials: [], materials: [],
activities: [], activities: [],
notes: `${commonSettings.notes}\n\nPlan Talimatları:\n${selectedPlans notes: `${commonSettings.notes}\n\nPlan Talimatları:\n${selectedPlans
.map((p) => `${p.planCode}: ${p.instructions || "Talimat yok"}`) .map((p) => `${p.planCode}: ${p.instructions || 'Talimat yok'}`)
.join("\n")}`, .join('\n')}`,
creationTime: new Date(), creationTime: new Date(),
lastModificationTime: new Date(), lastModificationTime: new Date(),
}; }
workOrders.push(workOrder); workOrders.push(workOrder)
} }
onSave(workOrders); onSave(workOrders)
setCommonSettings({ setCommonSettings({
scheduledStartDate: new Date().toISOString().split("T")[0], scheduledStartDate: new Date().toISOString().split('T')[0],
priority: PriorityEnum.Normal, priority: PriorityEnum.Normal,
assignedTo: "", assignedTo: '',
notes: "", notes: '',
createSeparateOrders: true, createSeparateOrders: true,
}); })
setIndividualSettings({}); setIndividualSettings({})
onClose(); onClose()
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -169,17 +151,12 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<div> <div>
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">İş Emri Oluştur</h2>
İş Emri Oluştur
</h2>
<p className="text-sm text-gray-600"> <p className="text-sm text-gray-600">
{selectedPlans.length} plan için emri oluşturuluyor {selectedPlans.length} plan için emri oluşturuluyor
</p> </p>
</div> </div>
<button <button onClick={onClose} className="p-2 hover:bg-gray-100 rounded-lg transition-colors">
onClick={onClose}
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
>
<FaTimes className="w-5 h-5 text-gray-500" /> <FaTimes className="w-5 h-5 text-gray-500" />
</button> </button>
</div> </div>
@ -188,24 +165,16 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
<div className="p-4 space-y-4"> <div className="p-4 space-y-4">
{/* Selected Plans Summary */} {/* Selected Plans Summary */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Seçili Bakım Planları</h3>
Seçili Bakım Planları
</h3>
<div className="bg-gray-50 rounded-lg p-3"> <div className="bg-gray-50 rounded-lg p-3">
<div className="grid grid-cols-1 md:grid-cols-2 gap-3"> <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{selectedPlans.map((plan) => ( {selectedPlans.map((plan) => (
<div key={plan.id} className="flex items-center space-x-3"> <div key={plan.id} className="flex items-center space-x-3">
<div className="flex-1"> <div className="flex-1">
<span className="text-sm font-medium text-gray-900"> <span className="text-sm font-medium text-gray-900">{plan.planCode}</span>
{plan.planCode} <span className="text-xs text-gray-500 ml-2">({plan.workCenterId})</span>
</span>
<span className="text-xs text-gray-500 ml-2">
({plan.workCenterId})
</span>
</div> </div>
<span <span className={`text-xs ${getPriorityColor(plan.priority)}`}>
className={`text-xs ${getPriorityColor(plan.priority)}`}
>
{plan.priority} {plan.priority}
</span> </span>
</div> </div>
@ -216,24 +185,18 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
{/* Work Order Type Selection */} {/* Work Order Type Selection */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">İş Emri Türü</h3>
İş Emri Türü
</h3>
<div className="space-y-3"> <div className="space-y-3">
<label className="flex items-center space-x-3"> <label className="flex items-center space-x-3">
<input <input
type="radio" type="radio"
name="orderType" name="orderType"
checked={commonSettings.createSeparateOrders} checked={commonSettings.createSeparateOrders}
onChange={() => onChange={() => handleCommonChange('createSeparateOrders', true)}
handleCommonChange("createSeparateOrders", true)
}
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300" className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300"
/> />
<div> <div>
<span className="text-sm font-medium text-gray-900"> <span className="text-sm font-medium text-gray-900">Ayrı İş Emirleri</span>
Ayrı İş Emirleri
</span>
<p className="text-sm text-gray-600"> <p className="text-sm text-gray-600">
Her bakım planı için ayrı bir emri oluşturulur Her bakım planı için ayrı bir emri oluşturulur
</p> </p>
@ -244,15 +207,11 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
type="radio" type="radio"
name="orderType" name="orderType"
checked={!commonSettings.createSeparateOrders} checked={!commonSettings.createSeparateOrders}
onChange={() => onChange={() => handleCommonChange('createSeparateOrders', false)}
handleCommonChange("createSeparateOrders", false)
}
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300" className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300"
/> />
<div> <div>
<span className="text-sm font-medium text-gray-900"> <span className="text-sm font-medium text-gray-900">Toplu İş Emri</span>
Toplu İş Emri
</span>
<p className="text-sm text-gray-600"> <p className="text-sm text-gray-600">
Tüm seçili planlar için tek bir emri oluşturulur Tüm seçili planlar için tek bir emri oluşturulur
</p> </p>
@ -263,9 +222,7 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
{/* Common Settings */} {/* Common Settings */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Ortak Ayarlar</h3>
Ortak Ayarlar
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">
@ -274,25 +231,16 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
<input <input
type="date" type="date"
value={commonSettings.scheduledStartDate} value={commonSettings.scheduledStartDate}
onChange={(e) => onChange={(e) => handleCommonChange('scheduledStartDate', e.target.value)}
handleCommonChange("scheduledStartDate", 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" 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"
required required
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Öncelik</label>
Öncelik
</label>
<select <select
value={commonSettings.priority} value={commonSettings.priority}
onChange={(e) => onChange={(e) => handleCommonChange('priority', e.target.value as PriorityEnum)}
handleCommonChange(
"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" 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.Low}>Düşük</option>
@ -302,14 +250,10 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Atanan Kişi</label>
Atanan Kişi
</label>
<select <select
value={commonSettings.assignedTo} value={commonSettings.assignedTo}
onChange={(e) => onChange={(e) => handleCommonChange('assignedTo', e.target.value)}
handleCommonChange("assignedTo", 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" 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="">Teknisyen seçin</option> <option value="">Teknisyen seçin</option>
@ -321,12 +265,10 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Notlar</label>
Notlar
</label>
<textarea <textarea
value={commonSettings.notes} value={commonSettings.notes}
onChange={(e) => handleCommonChange("notes", e.target.value)} onChange={(e) => handleCommonChange('notes', e.target.value)}
rows={1} 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" 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="Ek notlar ve talimatlar..." placeholder="Ek notlar ve talimatlar..."
@ -346,12 +288,9 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
</h3> </h3>
<div className="space-y-4"> <div className="space-y-4">
{selectedPlans.map((plan) => { {selectedPlans.map((plan) => {
const individual = individualSettings[plan.id] || {}; const individual = individualSettings[plan.id] || {}
return ( return (
<div <div key={plan.id} className="border border-gray-200 rounded-lg p-3">
key={plan.id}
className="border border-gray-200 rounded-lg p-3"
>
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
<h4 className="text-sm font-medium text-gray-900"> <h4 className="text-sm font-medium text-gray-900">
{plan.planCode} - {plan.description} {plan.planCode} - {plan.description}
@ -367,13 +306,9 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
</label> </label>
<input <input
type="date" type="date"
value={individual.scheduledStartDate || ""} value={individual.scheduledStartDate || ''}
onChange={(e) => onChange={(e) =>
handleIndividualChange( handleIndividualChange(plan.id, 'scheduledStartDate', e.target.value)
plan.id,
"scheduledStartDate",
e.target.value
)
} }
className="w-full px-2 py-1 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 focus:border-blue-500" className="w-full px-2 py-1 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 focus:border-blue-500"
/> />
@ -383,12 +318,12 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
Öncelik Öncelik
</label> </label>
<select <select
value={individual.priority || ""} value={individual.priority || ''}
onChange={(e) => onChange={(e) =>
handleIndividualChange( handleIndividualChange(
plan.id, plan.id,
"priority", 'priority',
e.target.value as PriorityEnum e.target.value as PriorityEnum,
) )
} }
className="w-full px-2 py-1 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 focus:border-blue-500" className="w-full px-2 py-1 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 focus:border-blue-500"
@ -405,22 +340,15 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
Atanan Kişi Atanan Kişi
</label> </label>
<select <select
value={individual.assignedTo || ""} value={individual.assignedTo || ''}
onChange={(e) => onChange={(e) =>
handleIndividualChange( handleIndividualChange(plan.id, 'assignedTo', e.target.value)
plan.id,
"assignedTo",
e.target.value
)
} }
className="w-full px-2 py-1 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 focus:border-blue-500" className="w-full px-2 py-1 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 focus:border-blue-500"
> >
<option value="">Teknisyen seçin</option> <option value="">Teknisyen seçin</option>
{mockEmployees.map((employee) => ( {mockEmployees.map((employee) => (
<option <option key={employee.id} value={employee.fullName}>
key={employee.id}
value={employee.fullName}
>
{employee.fullName} ({employee.code}) {employee.fullName} ({employee.code})
</option> </option>
))} ))}
@ -428,7 +356,7 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
})} })}
</div> </div>
</div> </div>
@ -440,13 +368,11 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
<div className="flex items-start space-x-3"> <div className="flex items-start space-x-3">
<FaExclamationTriangle className="w-5 h-5 text-yellow-600 mt-0.5" /> <FaExclamationTriangle className="w-5 h-5 text-yellow-600 mt-0.5" />
<div> <div>
<h4 className="text-sm font-medium text-yellow-800"> <h4 className="text-sm font-medium text-yellow-800">Toplu İş Emri Uyarısı</h4>
Toplu İş Emri Uyarısı
</h4>
<p className="text-sm text-yellow-700 mt-1"> <p className="text-sm text-yellow-700 mt-1">
Toplu emri oluşturulduğunda, farklı merkezleri ve Toplu emri oluşturulduğunda, farklı merkezleri ve planlar tek bir emri
planlar tek bir emri altında birleştirilecektir. Bu durum altında birleştirilecektir. Bu durum takip ve raporlama ısından karmaşıklığa
takip ve raporlama ısından karmaşıklığa neden olabilir. neden olabilir.
</p> </p>
</div> </div>
</div> </div>
@ -469,15 +395,12 @@ const CreateWorkOrderModal: React.FC<CreateWorkOrderModalProps> = ({
className="flex items-center space-x-2 px-3 py-1.5 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors" className="flex items-center space-x-2 px-3 py-1.5 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
> >
<FaSave className="w-4 h-4" /> <FaSave className="w-4 h-4" />
<span> <span>İş {commonSettings.createSeparateOrders ? 'Emirlerini' : 'Emrini'} Oluştur</span>
İş {commonSettings.createSeparateOrders ? "Emirlerini" : "Emrini"}{" "}
Oluştur
</span>
</button> </button>
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default CreateWorkOrderModal; export default CreateWorkOrderModal

View file

@ -1,20 +1,20 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from 'react'
import { FaTimes, FaSave, FaUpload, FaMinus } from "react-icons/fa"; import { FaTimes, FaSave, FaUpload, FaMinus } from 'react-icons/fa'
import { import {
PmFaultNotification, PmFaultNotification,
FaultTypeEnum, FaultTypeEnum,
CriticalityLevelEnum, CriticalityLevelEnum,
NotificationStatusEnum, NotificationStatusEnum,
} from "../../../types/pm"; } from '../../../types/pm'
import { mockWorkCenters } from "../../../mocks/mockWorkCenters"; import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from '../../../mocks/mockEmployees'
import { PriorityEnum } from "../../../types/common"; import { PriorityEnum } from '../../../types/common'
interface EditFaultNotificationModalProps { interface EditFaultNotificationModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (notification: PmFaultNotification) => void; onSave: (notification: PmFaultNotification) => void
notification: PmFaultNotification | null; notification: PmFaultNotification | null
} }
const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
@ -23,65 +23,61 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
onSave, onSave,
notification, notification,
}) => { }) => {
const [notificationData, setNotificationData] = useState< const [notificationData, setNotificationData] = useState<Partial<PmFaultNotification>>({})
Partial<PmFaultNotification> const [errors, setErrors] = useState<Record<string, string>>({})
>({}); const [uploadedImages, setUploadedImages] = useState<string[]>([])
const [errors, setErrors] = useState<Record<string, string>>({});
const [uploadedImages, setUploadedImages] = useState<string[]>([]);
useEffect(() => { useEffect(() => {
if (notification && isOpen) { if (notification && isOpen) {
setNotificationData(notification); setNotificationData(notification)
setUploadedImages(notification.images || []); setUploadedImages(notification.images || [])
} }
}, [notification, isOpen]); }, [notification, isOpen])
if (!isOpen || !notification) return null; if (!isOpen || !notification) return null
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (!notificationData.workCenterId) { if (!notificationData.workCenterId) {
newErrors.workCenterId = "İş Merkezi seçimi gerekli"; newErrors.workCenterId = 'İş Merkezi seçimi gerekli'
} }
if (!notificationData.title?.trim()) { if (!notificationData.title?.trim()) {
newErrors.title = "Başlık gerekli"; newErrors.title = 'Başlık gerekli'
} }
if (!notificationData.description?.trim()) { if (!notificationData.description?.trim()) {
newErrors.description = "Açıklama gerekli"; newErrors.description = 'Açıklama gerekli'
} }
if (!notificationData.location?.trim()) { if (!notificationData.location?.trim()) {
newErrors.location = "Konum gerekli"; newErrors.location = 'Konum gerekli'
} }
if (!notificationData.reportedBy?.trim()) { if (!notificationData.reportedBy?.trim()) {
newErrors.reportedBy = "Bildiren kişi gerekli"; newErrors.reportedBy = 'Bildiren kişi gerekli'
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleInputChange = ( const handleInputChange = (
field: keyof PmFaultNotification, field: keyof PmFaultNotification,
value: string | number | boolean | undefined value: string | number | boolean | undefined,
) => { ) => {
setNotificationData((prev) => ({ setNotificationData((prev) => ({
...prev, ...prev,
[field]: value, [field]: value,
})); }))
// Clear error when user starts typing // Clear error when user starts typing
if (errors[field]) { if (errors[field]) {
setErrors((prev) => ({ setErrors((prev) => ({
...prev, ...prev,
[field]: "", [field]: '',
})); }))
} }
}; }
const handleWorkCenterChange = (workCenterId: string) => { const handleWorkCenterChange = (workCenterId: string) => {
const selectedWorkCenter = mockWorkCenters.find( const selectedWorkCenter = mockWorkCenters.find((eq) => eq.id === workCenterId)
(eq) => eq.id === workCenterId
);
if (selectedWorkCenter) { if (selectedWorkCenter) {
setNotificationData((prev) => ({ setNotificationData((prev) => ({
...prev, ...prev,
@ -89,29 +85,29 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
workCenterCode: selectedWorkCenter.code, workCenterCode: selectedWorkCenter.code,
workCenterName: selectedWorkCenter.name, workCenterName: selectedWorkCenter.name,
location: selectedWorkCenter.location, location: selectedWorkCenter.location,
})); }))
} }
}; }
const handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => { const handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const files = event.target.files; const files = event.target.files
if (files) { if (files) {
const imageNames = Array.from(files).map((file) => file.name); const imageNames = Array.from(files).map((file) => file.name)
setUploadedImages((prev) => [...prev, ...imageNames]); setUploadedImages((prev) => [...prev, ...imageNames])
setNotificationData((prev) => ({ setNotificationData((prev) => ({
...prev, ...prev,
images: [...(prev.images || []), ...imageNames], images: [...(prev.images || []), ...imageNames],
})); }))
} }
}; }
const removeImage = (index: number) => { const removeImage = (index: number) => {
setUploadedImages((prev) => prev.filter((_, i) => i !== index)); setUploadedImages((prev) => prev.filter((_, i) => i !== index))
setNotificationData((prev) => ({ setNotificationData((prev) => ({
...prev, ...prev,
images: prev.images?.filter((_, i) => i !== index) || [], images: prev.images?.filter((_, i) => i !== index) || [],
})); }))
}; }
const handleSave = () => { const handleSave = () => {
if (validateForm()) { if (validateForm()) {
@ -119,25 +115,20 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
...notification, ...notification,
...notificationData, ...notificationData,
lastModificationTime: new Date(), lastModificationTime: new Date(),
}; }
onSave(updatedNotification); onSave(updatedNotification)
onClose(); onClose()
} }
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <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"> <div className="bg-white rounded-lg w-full max-w-3xl max-h-[90vh] overflow-y-auto">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">Arıza Bildirimini Düzenle</h2>
Arıza Bildirimini Düzenle <button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors">
</h2>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors"
>
<FaTimes className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>
@ -152,24 +143,20 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
</label> </label>
<input <input
type="text" type="text"
value={notificationData.notificationCode || ""} value={notificationData.notificationCode || ''}
onChange={(e) => onChange={(e) => handleInputChange('notificationCode', e.target.value)}
handleInputChange("notificationCode", 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" 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="ARZ-2024-001" placeholder="ARZ-2024-001"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">İş Merkezi *</label>
İş Merkezi *
</label>
<select <select
value={notificationData.workCenterId || ""} value={notificationData.workCenterId || ''}
onChange={(e) => handleWorkCenterChange(e.target.value)} onChange={(e) => handleWorkCenterChange(e.target.value)}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.workCenterId ? "border-red-500" : "border-gray-300" errors.workCenterId ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
<option value="">İş merkezi seçin</option> <option value="">İş merkezi seçin</option>
@ -180,9 +167,7 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
))} ))}
</select> </select>
{errors.workCenterId && ( {errors.workCenterId && (
<p className="text-red-500 text-sm mt-1"> <p className="text-red-500 text-sm mt-1">{errors.workCenterId}</p>
{errors.workCenterId}
</p>
)} )}
</div> </div>
</div> </div>
@ -195,16 +180,14 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
</label> </label>
<input <input
type="text" type="text"
value={notificationData.title || ""} value={notificationData.title || ''}
onChange={(e) => handleInputChange("title", e.target.value)} onChange={(e) => handleInputChange('title', e.target.value)}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.title ? "border-red-500" : "border-gray-300" errors.title ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Arıza başlığı" placeholder="Arıza başlığı"
/> />
{errors.title && ( {errors.title && <p className="text-red-500 text-sm mt-1">{errors.title}</p>}
<p className="text-red-500 text-sm mt-1">{errors.title}</p>
)}
</div> </div>
<div> <div>
@ -212,20 +195,16 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
Detaylı ıklama * Detaylı ıklama *
</label> </label>
<textarea <textarea
value={notificationData.description || ""} value={notificationData.description || ''}
onChange={(e) => onChange={(e) => handleInputChange('description', e.target.value)}
handleInputChange("description", e.target.value)
}
rows={3} rows={3}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.description ? "border-red-500" : "border-gray-300" errors.description ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Arızanın detaylııklaması, belirtiler ve gözlemler" placeholder="Arızanın detaylııklaması, belirtiler ve gözlemler"
/> />
{errors.description && ( {errors.description && (
<p className="text-red-500 text-sm mt-1"> <p className="text-red-500 text-sm mt-1">{errors.description}</p>
{errors.description}
</p>
)} )}
</div> </div>
</div> </div>
@ -233,21 +212,17 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
{/* Location and Reporter */} {/* Location and Reporter */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Konum *</label>
Konum *
</label>
<input <input
type="text" type="text"
value={notificationData.location || ""} value={notificationData.location || ''}
onChange={(e) => handleInputChange("location", e.target.value)} onChange={(e) => handleInputChange('location', e.target.value)}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.location ? "border-red-500" : "border-gray-300" errors.location ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Atölye A - Hat 1" placeholder="Atölye A - Hat 1"
/> />
{errors.location && ( {errors.location && <p className="text-red-500 text-sm mt-1">{errors.location}</p>}
<p className="text-red-500 text-sm mt-1">{errors.location}</p>
)}
</div> </div>
<div> <div>
@ -255,12 +230,10 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
Bildiren Kişi * Bildiren Kişi *
</label> </label>
<select <select
value={notificationData.reportedBy || ""} value={notificationData.reportedBy || ''}
onChange={(e) => onChange={(e) => handleInputChange('reportedBy', e.target.value)}
handleInputChange("reportedBy", e.target.value)
}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.reportedBy ? "border-red-500" : "border-gray-300" errors.reportedBy ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
<option value="">Bildiren kişi seçin</option> <option value="">Bildiren kişi seçin</option>
@ -279,41 +252,28 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
{/* Status and Assignment */} {/* Status and Assignment */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Durum</label>
Durum
</label>
<select <select
value={notificationData.status || NotificationStatusEnum.Open} value={notificationData.status || NotificationStatusEnum.Open}
onChange={(e) => onChange={(e) =>
handleInputChange( handleInputChange('status', e.target.value as NotificationStatusEnum)
"status",
e.target.value as NotificationStatusEnum
)
} }
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" 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={NotificationStatusEnum.Open}>ık</option> <option value={NotificationStatusEnum.Open}>ık</option>
<option value={NotificationStatusEnum.Assigned}>Atandı</option> <option value={NotificationStatusEnum.Assigned}>Atandı</option>
<option value={NotificationStatusEnum.InProgress}> <option value={NotificationStatusEnum.InProgress}>Devam Ediyor</option>
Devam Ediyor
</option>
<option value={NotificationStatusEnum.Resolved}>Çözüldü</option> <option value={NotificationStatusEnum.Resolved}>Çözüldü</option>
<option value={NotificationStatusEnum.Closed}>Kapatıldı</option> <option value={NotificationStatusEnum.Closed}>Kapatıldı</option>
<option value={NotificationStatusEnum.Rejected}> <option value={NotificationStatusEnum.Rejected}>Reddedildi</option>
Reddedildi
</option>
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Atanan Kişi</label>
Atanan Kişi
</label>
<select <select
value={notificationData.assignedTo || ""} value={notificationData.assignedTo || ''}
onChange={(e) => onChange={(e) => handleInputChange('assignedTo', e.target.value)}
handleInputChange("assignedTo", 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" 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="">Atama yapın</option> <option value="">Atama yapın</option>
@ -328,17 +288,10 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
<div className="grid grid-cols-1 md:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Arıza Türü</label>
Arıza Türü
</label>
<select <select
value={notificationData.faultType || FaultTypeEnum.Mechanical} value={notificationData.faultType || FaultTypeEnum.Mechanical}
onChange={(e) => onChange={(e) => handleInputChange('faultType', e.target.value as FaultTypeEnum)}
handleInputChange(
"faultType",
e.target.value as FaultTypeEnum
)
}
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" 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={FaultTypeEnum.Mechanical}>Mekanik</option> <option value={FaultTypeEnum.Mechanical}>Mekanik</option>
@ -353,14 +306,10 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Öncelik</label>
Öncelik
</label>
<select <select
value={notificationData.priority || PriorityEnum.Normal} value={notificationData.priority || PriorityEnum.Normal}
onChange={(e) => onChange={(e) => handleInputChange('priority', e.target.value as PriorityEnum)}
handleInputChange("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" 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.Low}>Düşük</option>
@ -371,16 +320,11 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Kritiklik</label>
Kritiklik
</label>
<select <select
value={notificationData.severity || CriticalityLevelEnum.Medium} value={notificationData.severity || CriticalityLevelEnum.Medium}
onChange={(e) => onChange={(e) =>
handleInputChange( handleInputChange('severity', e.target.value as CriticalityLevelEnum)
"severity",
e.target.value as CriticalityLevelEnum
)
} }
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" 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"
> >
@ -400,12 +344,9 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
</label> </label>
<input <input
type="number" type="number"
value={notificationData.estimatedRepairTime || ""} value={notificationData.estimatedRepairTime || ''}
onChange={(e) => onChange={(e) =>
handleInputChange( handleInputChange('estimatedRepairTime', parseInt(e.target.value) || undefined)
"estimatedRepairTime",
parseInt(e.target.value) || undefined
)
} }
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" 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="120" placeholder="120"
@ -419,12 +360,9 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
</label> </label>
<input <input
type="number" type="number"
value={notificationData.actualRepairTime || ""} value={notificationData.actualRepairTime || ''}
onChange={(e) => onChange={(e) =>
handleInputChange( handleInputChange('actualRepairTime', parseInt(e.target.value) || undefined)
"actualRepairTime",
parseInt(e.target.value) || undefined
)
} }
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" 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="150" placeholder="150"
@ -435,13 +373,11 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
{/* Work Order ID */} {/* Work Order ID */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">İş Emri ID</label>
İş Emri ID
</label>
<input <input
type="text" type="text"
value={notificationData.workOrderId || ""} value={notificationData.workOrderId || ''}
onChange={(e) => handleInputChange("workOrderId", e.target.value)} onChange={(e) => handleInputChange('workOrderId', 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" 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="WO-2024-001" placeholder="WO-2024-001"
/> />
@ -449,14 +385,10 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
{/* Resolution Notes */} {/* Resolution Notes */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Çözüm Notları</label>
Çözüm Notları
</label>
<textarea <textarea
value={notificationData.resolutionNotes || ""} value={notificationData.resolutionNotes || ''}
onChange={(e) => onChange={(e) => handleInputChange('resolutionNotes', e.target.value)}
handleInputChange("resolutionNotes", e.target.value)
}
rows={3} rows={3}
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" 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="Çözüm detayları ve yapılan işlemler" placeholder="Çözüm detayları ve yapılan işlemler"
@ -469,9 +401,7 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
<input <input
type="checkbox" type="checkbox"
checked={notificationData.followUpRequired || false} checked={notificationData.followUpRequired || false}
onChange={(e) => onChange={(e) => handleInputChange('followUpRequired', e.target.checked)}
handleInputChange("followUpRequired", e.target.checked)
}
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50" className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
/> />
<span className="ml-2 text-sm text-gray-700">Takip gerekli</span> <span className="ml-2 text-sm text-gray-700">Takip gerekli</span>
@ -480,9 +410,7 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
{/* Image Upload */} {/* Image Upload */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Fotoğraflar</label>
Fotoğraflar
</label>
<div className="border-2 border-dashed border-gray-300 rounded-lg p-4"> <div className="border-2 border-dashed border-gray-300 rounded-lg p-4">
<div className="text-center"> <div className="text-center">
<FaUpload className="mx-auto h-10 w-10 text-gray-400" /> <FaUpload className="mx-auto h-10 w-10 text-gray-400" />
@ -510,9 +438,7 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
{uploadedImages.length > 0 && ( {uploadedImages.length > 0 && (
<div className="mt-4"> <div className="mt-4">
<h4 className="text-sm font-medium text-gray-700 mb-2"> <h4 className="text-sm font-medium text-gray-700 mb-2">Mevcut Fotoğraflar:</h4>
Mevcut Fotoğraflar:
</h4>
<div className="space-y-2"> <div className="space-y-2">
{uploadedImages.map((image, index) => ( {uploadedImages.map((image, index) => (
<div <div
@ -553,7 +479,7 @@ const EditFaultNotificationModal: React.FC<EditFaultNotificationModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default EditFaultNotificationModal; export default EditFaultNotificationModal

View file

@ -1,21 +1,21 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from 'react'
import { FaTimes, FaSave, FaPlus, FaMinus } from "react-icons/fa"; import { FaTimes, FaSave, FaPlus, FaMinus } from 'react-icons/fa'
import { import {
PmMaintenancePlan, PmMaintenancePlan,
MaintenancePlanTypeEnum, MaintenancePlanTypeEnum,
FrequencyUnitEnum, FrequencyUnitEnum,
PmPlanMaterial, PmPlanMaterial,
} from "../../../types/pm"; } from '../../../types/pm'
import { mockWorkCenters } from "../../../mocks/mockWorkCenters"; import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
import { mockMaterials } from "../../../mocks/mockMaterials"; import { mockMaterials } from '../../../mocks/mockMaterials'
import { mockUnits } from "../../../mocks/mockUnits"; import { mockUnits } from '../../../mocks/mockUnits'
import { PriorityEnum } from "../../../types/common"; import { PriorityEnum } from '../../../types/common'
interface EditMaintenancePlanModalProps { interface EditMaintenancePlanModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (plan: PmMaintenancePlan) => void; onSave: (plan: PmMaintenancePlan) => void
plan: PmMaintenancePlan | null; plan: PmMaintenancePlan | null
} }
const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
@ -24,82 +24,67 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
onSave, onSave,
plan, plan,
}) => { }) => {
const [planData, setPlanData] = useState<Partial<PmMaintenancePlan>>({}); const [planData, setPlanData] = useState<Partial<PmMaintenancePlan>>({})
const [requiredSkills, setRequiredSkills] = useState<string[]>([]); const [requiredSkills, setRequiredSkills] = useState<string[]>([])
const [requiredMaterials, setRequiredMaterials] = useState<PmPlanMaterial[]>( const [requiredMaterials, setRequiredMaterials] = useState<PmPlanMaterial[]>([])
[] const [newSkill, setNewSkill] = useState('')
);
const [newSkill, setNewSkill] = useState("");
useEffect(() => { useEffect(() => {
if (plan) { if (plan) {
setPlanData({ setPlanData({
...plan, ...plan,
nextDue: plan.nextDue ? new Date(plan.nextDue) : new Date(), nextDue: plan.nextDue ? new Date(plan.nextDue) : new Date(),
}); })
setRequiredSkills(plan.requiredSkills || []); setRequiredSkills(plan.requiredSkills || [])
setRequiredMaterials(plan.requiredMaterials || []); setRequiredMaterials(plan.requiredMaterials || [])
} }
}, [plan]); }, [plan])
if (!isOpen || !plan) return null; if (!isOpen || !plan) return null
const handleInputChange = ( const handleInputChange = (
e: React.ChangeEvent< e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>,
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
>
) => { ) => {
const { name, value, type } = e.target; const { name, value, type } = e.target
setPlanData((prev) => ({ setPlanData((prev) => ({
...prev, ...prev,
[name]: [name]: type === 'date' ? new Date(value) : type === 'number' ? Number(value) : value,
type === "date" }))
? new Date(value) }
: type === "number"
? Number(value)
: value,
}));
};
const addSkill = () => { const addSkill = () => {
if (newSkill.trim() && !requiredSkills.includes(newSkill.trim())) { if (newSkill.trim() && !requiredSkills.includes(newSkill.trim())) {
setRequiredSkills([...requiredSkills, newSkill.trim()]); setRequiredSkills([...requiredSkills, newSkill.trim()])
setNewSkill(""); setNewSkill('')
} }
}; }
const removeSkill = (skillToRemove: string) => { const removeSkill = (skillToRemove: string) => {
setRequiredSkills( setRequiredSkills(requiredSkills.filter((skill) => skill !== skillToRemove))
requiredSkills.filter((skill) => skill !== skillToRemove) }
);
};
const addMaterial = () => { const addMaterial = () => {
const newMaterial: PmPlanMaterial = { const newMaterial: PmPlanMaterial = {
id: `MAT${Date.now()}`, id: `MAT${Date.now()}`,
planId: plan.id, planId: plan.id,
materialId: "", materialId: '',
quantity: 1, quantity: 1,
unitId: "", unitId: '',
isRequired: true, isRequired: true,
}; }
setRequiredMaterials([...requiredMaterials, newMaterial]); setRequiredMaterials([...requiredMaterials, newMaterial])
}; }
const removeMaterial = (index: number) => { const removeMaterial = (index: number) => {
setRequiredMaterials(requiredMaterials.filter((_, i) => i !== index)); setRequiredMaterials(requiredMaterials.filter((_, i) => i !== index))
}; }
const updateMaterial = ( const updateMaterial = (index: number, field: string, value: string | number | boolean) => {
index: number,
field: string,
value: string | number | boolean
) => {
const updated = requiredMaterials.map((material, i) => const updated = requiredMaterials.map((material, i) =>
i === index ? { ...material, [field]: value } : material i === index ? { ...material, [field]: value } : material,
); )
setRequiredMaterials(updated); setRequiredMaterials(updated)
}; }
const handleSave = () => { const handleSave = () => {
const updatedPlan: PmMaintenancePlan = { const updatedPlan: PmMaintenancePlan = {
@ -108,11 +93,11 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
requiredSkills, requiredSkills,
requiredMaterials, requiredMaterials,
lastModificationTime: new Date(), lastModificationTime: new Date(),
} as PmMaintenancePlan; } as PmMaintenancePlan
onSave(updatedPlan); onSave(updatedPlan)
onClose(); onClose()
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -122,10 +107,7 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">
Bakım Planı Düzenle - {plan.planCode} Bakım Planı Düzenle - {plan.planCode}
</h2> </h2>
<button <button onClick={onClose} className="p-1 hover:bg-gray-100 rounded-lg transition-colors">
onClick={onClose}
className="p-1 hover:bg-gray-100 rounded-lg transition-colors"
>
<FaTimes className="w-4 h-4 text-gray-500" /> <FaTimes className="w-4 h-4 text-gray-500" />
</button> </button>
</div> </div>
@ -134,30 +116,24 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
<div className="p-4 space-y-4"> <div className="p-4 space-y-4">
{/* Basic Information */} {/* Basic Information */}
<div> <div>
<h3 className="text-lg font-medium text-gray-900 mb-4"> <h3 className="text-lg font-medium text-gray-900 mb-4">Temel Bilgiler</h3>
Temel Bilgiler
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Plan Kodu *</label>
Plan Kodu *
</label>
<input <input
type="text" type="text"
name="planCode" name="planCode"
value={planData.planCode || ""} value={planData.planCode || ''}
onChange={handleInputChange} 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" 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"
required required
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">İş Merkezi *</label>
İş Merkezi *
</label>
<select <select
name="workCenterId" name="workCenterId"
value={planData.workCenterId || ""} value={planData.workCenterId || ''}
onChange={handleInputChange} 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" 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"
required required
@ -171,35 +147,21 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Plan Tipi *</label>
Plan Tipi *
</label>
<select <select
name="planType" name="planType"
value={ value={planData.planType || MaintenancePlanTypeEnum.Preventive}
planData.planType || MaintenancePlanTypeEnum.Preventive
}
onChange={handleInputChange} 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" 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={MaintenancePlanTypeEnum.Preventive}> <option value={MaintenancePlanTypeEnum.Preventive}>Önleyici Bakım</option>
Önleyici Bakım <option value={MaintenancePlanTypeEnum.Predictive}>Kestirimci Bakım</option>
</option> <option value={MaintenancePlanTypeEnum.Corrective}>Düzeltici Bakım</option>
<option value={MaintenancePlanTypeEnum.Predictive}> <option value={MaintenancePlanTypeEnum.Condition}>Durum Bazlı Bakım</option>
Kestirimci Bakım
</option>
<option value={MaintenancePlanTypeEnum.Corrective}>
Düzeltici Bakım
</option>
<option value={MaintenancePlanTypeEnum.Condition}>
Durum Bazlı Bakım
</option>
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Öncelik</label>
Öncelik
</label>
<select <select
name="priority" name="priority"
value={planData.priority || PriorityEnum.Normal} value={planData.priority || PriorityEnum.Normal}
@ -213,12 +175,10 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
</select> </select>
</div> </div>
<div className="md:col-span-2"> <div className="md:col-span-2">
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">ıklama *</label>
ıklama *
</label>
<textarea <textarea
name="description" name="description"
value={planData.description || ""} value={planData.description || ''}
onChange={handleInputChange} onChange={handleInputChange}
rows={2} 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" 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"
@ -230,14 +190,10 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
{/* Frequency Settings */} {/* Frequency Settings */}
<div> <div>
<h3 className="text-lg font-medium text-gray-900 mb-4"> <h3 className="text-lg font-medium text-gray-900 mb-4">Sıklık Ayarları</h3>
Sıklık Ayarları
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Sıklık *</label>
Sıklık *
</label>
<input <input
type="number" type="number"
name="frequency" name="frequency"
@ -287,11 +243,7 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
<input <input
type="date" type="date"
name="nextDue" name="nextDue"
value={ value={planData.nextDue ? planData.nextDue.toISOString().split('T')[0] : ''}
planData.nextDue
? planData.nextDue.toISOString().split("T")[0]
: ""
}
onChange={handleInputChange} 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" 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"
/> />
@ -310,9 +262,7 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
} }
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/> />
<span className="text-sm font-medium text-gray-700"> <span className="text-sm font-medium text-gray-700">Plan Aktif</span>
Plan Aktif
</span>
</label> </label>
</div> </div>
</div> </div>
@ -320,12 +270,10 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
{/* Instructions */} {/* Instructions */}
<div> <div>
<h3 className="text-lg font-medium text-gray-900 mb-4"> <h3 className="text-lg font-medium text-gray-900 mb-4">Bakım Talimatları</h3>
Bakım Talimatları
</h3>
<textarea <textarea
name="instructions" name="instructions"
value={planData.instructions || ""} value={planData.instructions || ''}
onChange={handleInputChange} onChange={handleInputChange}
rows={3} rows={3}
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" 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"
@ -336,9 +284,7 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
{/* Required Skills */} {/* Required Skills */}
<div> <div>
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-medium text-gray-900"> <h3 className="text-lg font-medium text-gray-900">Gerekli Yetenekler</h3>
Gerekli Yetenekler
</h3>
<div className="flex space-x-2"> <div className="flex space-x-2">
<input <input
type="text" type="text"
@ -346,7 +292,7 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
onChange={(e) => setNewSkill(e.target.value)} onChange={(e) => setNewSkill(e.target.value)}
placeholder="Yetenek ekle" placeholder="Yetenek ekle"
className="px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" className="px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
onKeyPress={(e) => e.key === "Enter" && addSkill()} onKeyPress={(e) => e.key === 'Enter' && addSkill()}
/> />
<button <button
type="button" type="button"
@ -379,9 +325,7 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
{/* Required Materials */} {/* Required Materials */}
<div> <div>
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-medium text-gray-900"> <h3 className="text-lg font-medium text-gray-900">Gerekli Malzemeler</h3>
Gerekli Malzemeler
</h3>
<button <button
type="button" type="button"
onClick={addMaterial} onClick={addMaterial}
@ -393,23 +337,14 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
</div> </div>
<div className="space-y-3"> <div className="space-y-3">
{requiredMaterials.map((material, index) => ( {requiredMaterials.map((material, index) => (
<div <div key={index} className="flex items-center space-x-2 p-2 bg-gray-50 rounded-lg">
key={index}
className="flex items-center space-x-2 p-2 bg-gray-50 rounded-lg"
>
<select <select
value={material.materialId} value={material.materialId}
onChange={(e) => { onChange={(e) => {
const selectedMaterial = mockMaterials.find( const selectedMaterial = mockMaterials.find((m) => m.id === e.target.value)
(m) => m.id === e.target.value updateMaterial(index, 'materialId', e.target.value)
);
updateMaterial(index, "materialId", e.target.value);
if (selectedMaterial) { if (selectedMaterial) {
updateMaterial( updateMaterial(index, 'unitId', selectedMaterial.baseUnitId)
index,
"unitId",
selectedMaterial.baseUnitId
);
} }
}} }}
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" 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"
@ -424,18 +359,14 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
<input <input
type="number" type="number"
value={material.quantity} value={material.quantity}
onChange={(e) => onChange={(e) => updateMaterial(index, 'quantity', Number(e.target.value))}
updateMaterial(index, "quantity", Number(e.target.value))
}
placeholder="Miktar" placeholder="Miktar"
min="1" min="1"
className="w-20 px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" className="w-20 px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/> />
<select <select
value={material.unitId} value={material.unitId}
onChange={(e) => onChange={(e) => updateMaterial(index, 'unitId', e.target.value)}
updateMaterial(index, "unitId", e.target.value)
}
className="w-24 px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" className="w-24 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="">Birim</option> <option value="">Birim</option>
@ -448,29 +379,25 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
{material.materialId && {material.materialId &&
(() => { (() => {
const selectedMaterial = mockMaterials.find( const selectedMaterial = mockMaterials.find(
(m) => m.id === material.materialId (m) => m.id === material.materialId,
); )
const baseUnit = selectedMaterial?.baseUnit; const baseUnit = selectedMaterial?.baseUnit
const existsInList = mockUnits.some( const existsInList = mockUnits.some((unit) => unit.id === baseUnit?.id)
(unit) => unit.id === baseUnit?.id
);
if (baseUnit && !existsInList) { if (baseUnit && !existsInList) {
return ( return (
<option key={baseUnit.id} value={baseUnit.id}> <option key={baseUnit.id} value={baseUnit.id}>
{baseUnit.code} {baseUnit.code}
</option> </option>
); )
} }
return null; return null
})()} })()}
</select> </select>
<label className="flex items-center space-x-2"> <label className="flex items-center space-x-2">
<input <input
type="checkbox" type="checkbox"
checked={material.isRequired} checked={material.isRequired}
onChange={(e) => onChange={(e) => updateMaterial(index, 'isRequired', e.target.checked)}
updateMaterial(index, "isRequired", e.target.checked)
}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/> />
<span className="text-sm text-gray-700">Zorunlu</span> <span className="text-sm text-gray-700">Zorunlu</span>
@ -486,8 +413,8 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
))} ))}
{requiredMaterials.length === 0 && ( {requiredMaterials.length === 0 && (
<p className="text-gray-500 text-center py-4"> <p className="text-gray-500 text-center py-4">
Henüz malzeme eklenmedi. "Malzeme Ekle" butonunu kullanarak Henüz malzeme eklenmedi. "Malzeme Ekle" butonunu kullanarak malzeme
malzeme ekleyebilirsiniz. ekleyebilirsiniz.
</p> </p>
)} )}
</div> </div>
@ -512,7 +439,7 @@ const EditMaintenancePlanModal: React.FC<EditMaintenancePlanModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default EditMaintenancePlanModal; export default EditMaintenancePlanModal

View file

@ -1,164 +1,143 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from 'react'
import { FaTimes, FaSave, FaPlus, FaMinus } from "react-icons/fa"; import { FaTimes, FaSave, FaPlus, FaMinus } from 'react-icons/fa'
import MultiSelectEmployee from "../../../components/common/MultiSelectEmployee"; import MultiSelectEmployee from '../../../components/common/MultiSelectEmployee'
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from '../../../mocks/mockEmployees'
import { Team, TeamMember, TeamRoleEnum } from "../../../types/common"; import { Team, TeamMember, TeamRoleEnum } from '../../../types/common'
interface EditTeamModalProps { interface EditTeamModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (team: Team) => void; onSave: (team: Team) => void
team: Team | null; team: Team | null
} }
const EditTeamModal: React.FC<EditTeamModalProps> = ({ const EditTeamModal: React.FC<EditTeamModalProps> = ({ isOpen, onClose, onSave, team }) => {
isOpen,
onClose,
onSave,
team,
}) => {
const [teamData, setTeamData] = useState<Partial<Team>>({ const [teamData, setTeamData] = useState<Partial<Team>>({
code: "", code: '',
name: "", name: '',
description: "", description: '',
isActive: true, isActive: true,
specializations: [], specializations: [],
members: [], members: [],
}); })
const [selectedEmployees, setSelectedEmployees] = useState<string[]>([]); const [selectedEmployees, setSelectedEmployees] = useState<string[]>([])
const [newSpecialization, setNewSpecialization] = useState(""); const [newSpecialization, setNewSpecialization] = useState('')
const [errors, setErrors] = useState<Record<string, string>>({}); const [errors, setErrors] = useState<Record<string, string>>({})
useEffect(() => { useEffect(() => {
if (team && isOpen) { if (team && isOpen) {
setTeamData(team); setTeamData(team)
const employeeNames = team.members const employeeNames = team.members
.filter((m) => m.isActive) .filter((m) => m.isActive)
.map((m) => m.employee?.firstName + " " + m.employee?.lastName || ""); .map((m) => m.employee?.firstName + ' ' + m.employee?.lastName || '')
setSelectedEmployees(employeeNames); setSelectedEmployees(employeeNames)
} }
}, [team, isOpen]); }, [team, isOpen])
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (!teamData.code?.trim()) { if (!teamData.code?.trim()) {
newErrors.teamCode = "Ekip kodu gerekli"; newErrors.teamCode = 'Ekip kodu gerekli'
} }
if (!teamData.name?.trim()) { if (!teamData.name?.trim()) {
newErrors.teamName = "Ekip adı gerekli"; newErrors.teamName = 'Ekip adı gerekli'
} }
if (!teamData.description?.trim()) { if (!teamData.description?.trim()) {
newErrors.description = "Açıklama gerekli"; newErrors.description = 'Açıklama gerekli'
} }
if (!teamData.managerId) { if (!teamData.managerId) {
newErrors.leaderId = "Ekip lideri seçilmeli"; newErrors.leaderId = 'Ekip lideri seçilmeli'
} }
if (selectedEmployees.length === 0) { if (selectedEmployees.length === 0) {
newErrors.members = "En az bir ekip üyesi seçilmeli"; newErrors.members = 'En az bir ekip üyesi seçilmeli'
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleInputChange = ( const handleInputChange = (field: keyof Team, value: string | boolean | string[]) => {
field: keyof Team,
value: string | boolean | string[]
) => {
setTeamData((prev) => ({ setTeamData((prev) => ({
...prev, ...prev,
[field]: value, [field]: value,
})); }))
// Clear error when user starts typing // Clear error when user starts typing
if (errors[field]) { if (errors[field]) {
setErrors((prev) => ({ setErrors((prev) => ({
...prev, ...prev,
[field]: "", [field]: '',
})); }))
} }
}; }
const addSpecialization = () => { const addSpecialization = () => {
if ( if (newSpecialization.trim() && !teamData.specializations?.includes(newSpecialization.trim())) {
newSpecialization.trim() &&
!teamData.specializations?.includes(newSpecialization.trim())
) {
setTeamData((prev) => ({ setTeamData((prev) => ({
...prev, ...prev,
specializations: [ specializations: [...(prev.specializations || []), newSpecialization.trim()],
...(prev.specializations || []), }))
newSpecialization.trim(), setNewSpecialization('')
],
}));
setNewSpecialization("");
} }
}; }
const removeSpecialization = (index: number) => { const removeSpecialization = (index: number) => {
setTeamData((prev) => ({ setTeamData((prev) => ({
...prev, ...prev,
specializations: specializations: prev.specializations?.filter((_, i) => i !== index) || [],
prev.specializations?.filter((_, i) => i !== index) || [], }))
})); }
};
const handleEmployeeSelection = (employees: string[]) => { const handleEmployeeSelection = (employees: string[]) => {
setSelectedEmployees(employees); setSelectedEmployees(employees)
if (errors.members) { if (errors.members) {
setErrors((prev) => ({ setErrors((prev) => ({
...prev, ...prev,
members: "", members: '',
})); }))
} }
}; }
const handleMemberRoleChange = (employeeName: string, role: TeamRoleEnum) => { const handleMemberRoleChange = (employeeName: string, role: TeamRoleEnum) => {
const employee = mockEmployees.find((emp) => emp.fullName === employeeName); const employee = mockEmployees.find((emp) => emp.fullName === employeeName)
if (role === TeamRoleEnum.Lead && employee) { if (role === TeamRoleEnum.Lead && employee) {
handleInputChange("managerId", employee.id); handleInputChange('managerId', employee.id)
} }
}; }
const handleSave = () => { const handleSave = () => {
if (validateForm()) { if (validateForm()) {
const members: TeamMember[] = selectedEmployees.map( const members: TeamMember[] = selectedEmployees.map((employeeName, index) => {
(employeeName, index) => { const employee = mockEmployees.find((emp) => emp.fullName === employeeName)
const employee = mockEmployees.find( const existingMember = team?.members.find(
(emp) => emp.fullName === employeeName (m) => m.employee?.firstName + ' ' + m.employee?.lastName === employeeName,
); )
const existingMember = team?.members.find( const isLeader = teamData.managerId === employee?.id
(m) =>
m.employee?.firstName + " " + m.employee?.lastName ===
employeeName
);
const isLeader = teamData.managerId === employee?.id;
return { return {
id: existingMember?.id || `TM${Date.now()}-${index}`, id: existingMember?.id || `TM${Date.now()}-${index}`,
teamId: team?.id || "", teamId: team?.id || '',
employeeId: employee?.id || "", employeeId: employee?.id || '',
employee: mockEmployees.find((emp) => emp.id === employee?.id), employee: mockEmployees.find((emp) => emp.id === employee?.id),
role: isLeader ? TeamRoleEnum.Lead : TeamRoleEnum.Member, role: isLeader ? TeamRoleEnum.Lead : TeamRoleEnum.Member,
joinDate: existingMember?.joinDate || new Date(), joinDate: existingMember?.joinDate || new Date(),
isActive: true, isActive: true,
};
} }
); })
const updatedTeam: Team = { const updatedTeam: Team = {
...team!, ...team!,
...teamData, ...teamData,
managerId: teamData.managerId || "", managerId: teamData.managerId || '',
members, members,
lastModificationTime: new Date(), lastModificationTime: new Date(),
}; }
onSave(updatedTeam); onSave(updatedTeam)
onClose(); onClose()
} }
}; }
return ( return (
isOpen && isOpen &&
@ -181,91 +160,69 @@ const EditTeamModal: React.FC<EditTeamModalProps> = ({
{/* Basic Info */} {/* Basic Info */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Ekip Kodu *</label>
Ekip Kodu *
</label>
<input <input
type="text" type="text"
value={teamData.code || ""} value={teamData.code || ''}
onChange={(e) => handleInputChange("code", e.target.value)} onChange={(e) => handleInputChange('code', e.target.value)}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.code ? "border-red-500" : "border-gray-300" errors.code ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="MEC-001" placeholder="MEC-001"
/> />
{errors.code && ( {errors.code && <p className="text-red-500 text-sm mt-1">{errors.code}</p>}
<p className="text-red-500 text-sm mt-1">{errors.code}</p>
)}
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Ekip Adı *</label>
Ekip Adı *
</label>
<input <input
type="text" type="text"
value={teamData.name || ""} value={teamData.name || ''}
onChange={(e) => handleInputChange("name", e.target.value)} onChange={(e) => handleInputChange('name', e.target.value)}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.name ? "border-red-500" : "border-gray-300" errors.name ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Mekanik Bakım Ekibi" placeholder="Mekanik Bakım Ekibi"
/> />
{errors.name && ( {errors.name && <p className="text-red-500 text-sm mt-1">{errors.name}</p>}
<p className="text-red-500 text-sm mt-1">{errors.name}</p>
)}
</div> </div>
</div> </div>
{/* Description */} {/* Description */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">ıklama *</label>
ıklama *
</label>
<textarea <textarea
value={teamData.description || ""} value={teamData.description || ''}
onChange={(e) => onChange={(e) => handleInputChange('description', e.target.value)}
handleInputChange("description", e.target.value)
}
rows={2} 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 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.description ? "border-red-500" : "border-gray-300" errors.description ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Ekip açıklaması ve sorumlulukları" placeholder="Ekip açıklaması ve sorumlulukları"
/> />
{errors.description && ( {errors.description && (
<p className="text-red-500 text-sm mt-1"> <p className="text-red-500 text-sm mt-1">{errors.description}</p>
{errors.description}
</p>
)} )}
</div> </div>
{/* Team Members */} {/* Team Members */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Ekip Üyeleri *</label>
Ekip Üyeleri *
</label>
<MultiSelectEmployee <MultiSelectEmployee
selectedEmployees={selectedEmployees} selectedEmployees={selectedEmployees}
onChange={handleEmployeeSelection} onChange={handleEmployeeSelection}
placeholder="Ekip üyelerini seçin" placeholder="Ekip üyelerini seçin"
className={errors.members ? "border-red-500" : ""} className={errors.members ? 'border-red-500' : ''}
/> />
{errors.members && ( {errors.members && <p className="text-red-500 text-sm mt-1">{errors.members}</p>}
<p className="text-red-500 text-sm mt-1">{errors.members}</p>
)}
{/* Selected Members Display */} {/* Selected Members Display */}
{selectedEmployees.length > 0 && ( {selectedEmployees.length > 0 && (
<div className="mt-3 p-3 bg-gray-50 rounded-lg"> <div className="mt-3 p-3 bg-gray-50 rounded-lg">
<h4 className="text-sm font-medium text-gray-700 mb-2"> <h4 className="text-sm font-medium text-gray-700 mb-2">Seçili Ekip Üyeleri:</h4>
Seçili Ekip Üyeleri:
</h4>
<div className="space-y-2"> <div className="space-y-2">
{selectedEmployees.map((employeeName, index) => { {selectedEmployees.map((employeeName, index) => {
const employee = mockEmployees.find( const employee = mockEmployees.find((emp) => emp.fullName === employeeName)
(emp) => emp.fullName === employeeName
);
return ( return (
<div <div
key={index} key={index}
@ -279,12 +236,8 @@ const EditTeamModal: React.FC<EditTeamModalProps> = ({
</span> </span>
</div> </div>
<div> <div>
<p className="text-sm font-medium text-gray-900"> <p className="text-sm font-medium text-gray-900">{employeeName}</p>
{employeeName} <p className="text-sm text-gray-600">{employee?.jobPosition?.name}</p>
</p>
<p className="text-sm text-gray-600">
{employee?.jobPosition?.name}
</p>
</div> </div>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
@ -295,22 +248,17 @@ const EditTeamModal: React.FC<EditTeamModalProps> = ({
: TeamRoleEnum.Member : TeamRoleEnum.Member
} }
onChange={(e) => onChange={(e) =>
handleMemberRoleChange( handleMemberRoleChange(employeeName, e.target.value as TeamRoleEnum)
employeeName,
e.target.value as TeamRoleEnum
)
} }
className="text-xs px-2 py-1 border border-gray-300 rounded" className="text-xs px-2 py-1 border border-gray-300 rounded"
> >
<option value={TeamRoleEnum.Member}>Üye</option> <option value={TeamRoleEnum.Member}>Üye</option>
<option value={TeamRoleEnum.Lead}>Lider</option> <option value={TeamRoleEnum.Lead}>Lider</option>
<option value={TeamRoleEnum.Specialist}> <option value={TeamRoleEnum.Specialist}>Uzman</option>
Uzman
</option>
</select> </select>
</div> </div>
</div> </div>
); )
})} })}
</div> </div>
</div> </div>
@ -331,9 +279,9 @@ const EditTeamModal: React.FC<EditTeamModalProps> = ({
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" 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"
placeholder="Uzmanlık alanı ekle" placeholder="Uzmanlık alanı ekle"
onKeyPress={(e) => { onKeyPress={(e) => {
if (e.key === "Enter") { if (e.key === 'Enter') {
e.preventDefault(); e.preventDefault()
addSpecialization(); addSpecialization()
} }
}} }}
/> />
@ -345,26 +293,25 @@ const EditTeamModal: React.FC<EditTeamModalProps> = ({
<FaPlus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
</button> </button>
</div> </div>
{teamData.specializations && {teamData.specializations && teamData.specializations.length > 0 && (
teamData.specializations.length > 0 && ( <div className="flex flex-wrap gap-2">
<div className="flex flex-wrap gap-2"> {teamData.specializations.map((spec, index) => (
{teamData.specializations.map((spec, index) => ( <span
<span key={index}
key={index} className="inline-flex items-center px-2 py-1 rounded-full text-xs bg-blue-100 text-blue-800"
className="inline-flex items-center px-2 py-1 rounded-full text-xs bg-blue-100 text-blue-800" >
{spec}
<button
type="button"
onClick={() => removeSpecialization(index)}
className="ml-2 text-blue-600 hover:text-blue-800"
> >
{spec} <FaMinus className="w-3 h-3" />
<button </button>
type="button" </span>
onClick={() => removeSpecialization(index)} ))}
className="ml-2 text-blue-600 hover:text-blue-800" </div>
> )}
<FaMinus className="w-3 h-3" />
</button>
</span>
))}
</div>
)}
</div> </div>
</div> </div>
@ -374,9 +321,7 @@ const EditTeamModal: React.FC<EditTeamModalProps> = ({
<input <input
type="checkbox" type="checkbox"
checked={teamData.isActive || false} checked={teamData.isActive || false}
onChange={(e) => onChange={(e) => handleInputChange('isActive', e.target.checked)}
handleInputChange("isActive", e.target.checked)
}
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50" className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
/> />
<span className="ml-2 text-sm text-gray-700">Ekip aktif</span> <span className="ml-2 text-sm text-gray-700">Ekip aktif</span>
@ -403,7 +348,7 @@ const EditTeamModal: React.FC<EditTeamModalProps> = ({
</div> </div>
</div> </div>
) )
); )
}; }
export default EditTeamModal; export default EditTeamModal

View file

@ -1,18 +1,18 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaSave, FaPlus, FaMinus } from "react-icons/fa"; import { FaTimes, FaSave, FaPlus, FaMinus } from 'react-icons/fa'
import { import {
PmWorkCenter, PmWorkCenter,
WorkCenterStatusEnum, WorkCenterStatusEnum,
CriticalityLevelEnum, CriticalityLevelEnum,
PmWorkCenterSpecification, PmWorkCenterSpecification,
} from "../../../types/pm"; } from '../../../types/pm'
import { mockDepartments } from "../../../mocks/mockDepartments"; import { mockDepartments } from '../../../mocks/mockDepartments'
interface EditWorkCenterModalProps { interface EditWorkCenterModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (workCenter: PmWorkCenter) => void; onSave: (workCenter: PmWorkCenter) => void
workCenter: PmWorkCenter; workCenter: PmWorkCenter
} }
const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
@ -21,61 +21,55 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
onSave, onSave,
workCenter, workCenter,
}) => { }) => {
const [formData, setFormData] = useState<PmWorkCenter>(workCenter); const [formData, setFormData] = useState<PmWorkCenter>(workCenter)
const [specifications, setSpecifications] = useState< const [specifications, setSpecifications] = useState<PmWorkCenterSpecification[]>(
PmWorkCenterSpecification[] workCenter.specifications || [],
>(workCenter.specifications || []); )
if (!isOpen || !workCenter) return null; if (!isOpen || !workCenter) return null
const handleInputChange = ( const handleInputChange = (
e: React.ChangeEvent< e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>,
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
>
) => { ) => {
const { name, value, type } = e.target; const { name, value, type } = e.target
setFormData((prev) => ({ setFormData((prev) => ({
...prev, ...prev,
[name]: type === "date" ? new Date(value) : value, [name]: type === 'date' ? new Date(value) : value,
})); }))
}; }
const addSpecification = () => { const addSpecification = () => {
const newSpec: PmWorkCenterSpecification = { const newSpec: PmWorkCenterSpecification = {
id: `SPEC${Date.now()}`, id: `SPEC${Date.now()}`,
workCenterId: workCenter.id, workCenterId: workCenter.id,
specificationName: "", specificationName: '',
specificationValue: "", specificationValue: '',
unit: "", unit: '',
isRequired: false, isRequired: false,
}; }
setSpecifications([...specifications, newSpec]); setSpecifications([...specifications, newSpec])
}; }
const removeSpecification = (index: number) => { const removeSpecification = (index: number) => {
setSpecifications(specifications.filter((_, i) => i !== index)); setSpecifications(specifications.filter((_, i) => i !== index))
}; }
const updateSpecification = ( const updateSpecification = (index: number, field: string, value: string | boolean) => {
index: number,
field: string,
value: string | boolean
) => {
const updated = specifications.map((spec, i) => const updated = specifications.map((spec, i) =>
i === index ? { ...spec, [field]: value } : spec i === index ? { ...spec, [field]: value } : spec,
); )
setSpecifications(updated); setSpecifications(updated)
}; }
const handleSave = () => { const handleSave = () => {
const updatedWorkCenter = { const updatedWorkCenter = {
...formData, ...formData,
specifications, specifications,
lastModificationTime: new Date(), lastModificationTime: new Date(),
}; }
onSave(updatedWorkCenter); onSave(updatedWorkCenter)
onClose(); onClose()
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -85,10 +79,7 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">
İş Merkezi Düzenle - {workCenter.code} İş Merkezi Düzenle - {workCenter.code}
</h2> </h2>
<button <button onClick={onClose} className="p-1 hover:bg-gray-100 rounded-lg transition-colors">
onClick={onClose}
className="p-1 hover:bg-gray-100 rounded-lg transition-colors"
>
<FaTimes className="w-4 h-4 text-gray-500" /> <FaTimes className="w-4 h-4 text-gray-500" />
</button> </button>
</div> </div>
@ -97,9 +88,7 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
<div className="p-4 space-y-4"> <div className="p-4 space-y-4">
{/* Basic Information */} {/* Basic Information */}
<div> <div>
<h3 className="text-lg font-medium text-gray-900 mb-4"> <h3 className="text-lg font-medium text-gray-900 mb-4">Temel Bilgiler</h3>
Temel Bilgiler
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">
@ -130,12 +119,10 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
/> />
</div> </div>
<div className="md:col-span-2"> <div className="md:col-span-2">
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">ıklama</label>
ıklama
</label>
<textarea <textarea
name="description" name="description"
value={formData.description || ""} value={formData.description || ''}
onChange={handleInputChange} onChange={handleInputChange}
rows={2} 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" 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"
@ -145,17 +132,13 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
</div> </div>
</div> </div>
<h3 className="text-lg font-medium text-gray-900 mb-4"> <h3 className="text-lg font-medium text-gray-900 mb-4">Teknik Özellikler</h3>
Teknik Özellikler
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Makine Türü</label>
Makine Türü
</label>
<select <select
name="machineType" name="machineType"
value={formData.machineType || "Manual"} value={formData.machineType || 'Manual'}
onChange={handleInputChange} 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" 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"
> >
@ -166,9 +149,7 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Departman</label>
Departman
</label>
<select <select
value={formData.departmentId} value={formData.departmentId}
@ -215,26 +196,22 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
<div> <div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Üretici</label>
Üretici
</label>
<input <input
type="text" type="text"
name="manufacturer" name="manufacturer"
value={formData.manufacturer || ""} value={formData.manufacturer || ''}
onChange={handleInputChange} 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" 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="örn: HAAS Automation" placeholder="örn: HAAS Automation"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Model</label>
Model
</label>
<input <input
type="text" type="text"
name="model" name="model"
value={formData.model || ""} value={formData.model || ''}
onChange={handleInputChange} 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" 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="örn: ST-30" placeholder="örn: ST-30"
@ -247,7 +224,7 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
<input <input
type="text" type="text"
name="serialNumber" name="serialNumber"
value={formData.serialNumber || ""} value={formData.serialNumber || ''}
onChange={handleInputChange} 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" 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="örn: SN123456789" placeholder="örn: SN123456789"
@ -262,8 +239,8 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
name="installationDate" name="installationDate"
value={ value={
formData.installationDate formData.installationDate
? formData.installationDate.toISOString().split("T")[0] ? formData.installationDate.toISOString().split('T')[0]
: "" : ''
} }
onChange={handleInputChange} 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" 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"
@ -279,17 +256,15 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
name="warrantyExpiry" name="warrantyExpiry"
value={ value={
formData.warrantyExpiry formData.warrantyExpiry
? formData.warrantyExpiry.toISOString().split("T")[0] ? formData.warrantyExpiry.toISOString().split('T')[0]
: "" : ''
} }
onChange={handleInputChange} 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" 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>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Lokasyon *</label>
Lokasyon *
</label>
<input <input
type="text" type="text"
name="location" name="location"
@ -305,29 +280,19 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
{/* Status and Priority */} {/* Status and Priority */}
<div> <div>
<h3 className="text-lg font-medium text-gray-900 mb-4"> <h3 className="text-lg font-medium text-gray-900 mb-4">Durum ve Öncelik</h3>
Durum ve Öncelik
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Durum</label>
Durum
</label>
<select <select
name="status" name="status"
value={formData.status} value={formData.status}
onChange={handleInputChange} 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" 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={WorkCenterStatusEnum.Operational}> <option value={WorkCenterStatusEnum.Operational}>Operasyonel</option>
Operasyonel <option value={WorkCenterStatusEnum.UnderMaintenance}>Bakımda</option>
</option> <option value={WorkCenterStatusEnum.OutOfOrder}>Arızalı</option>
<option value={WorkCenterStatusEnum.UnderMaintenance}>
Bakımda
</option>
<option value={WorkCenterStatusEnum.OutOfOrder}>
Arızalı
</option>
<option value={WorkCenterStatusEnum.Retired}>Emekli</option> <option value={WorkCenterStatusEnum.Retired}>Emekli</option>
</select> </select>
</div> </div>
@ -348,16 +313,14 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Aktif Durum</label>
Aktif Durum
</label>
<select <select
name="isActive" name="isActive"
value={formData.isActive ? "true" : "false"} value={formData.isActive ? 'true' : 'false'}
onChange={(e) => onChange={(e) =>
setFormData((prev) => ({ setFormData((prev) => ({
...prev, ...prev,
isActive: e.target.value === "true", isActive: e.target.value === 'true',
})) }))
} }
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" 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"
@ -372,9 +335,7 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
{/* Specifications */} {/* Specifications */}
<div> <div>
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-medium text-gray-900"> <h3 className="text-lg font-medium text-gray-900">Teknik Özellikler</h3>
Teknik Özellikler
</h3>
<button <button
type="button" type="button"
onClick={addSpecification} onClick={addSpecification}
@ -386,19 +347,12 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
</div> </div>
<div className="space-y-3"> <div className="space-y-3">
{specifications.map((spec, index) => ( {specifications.map((spec, index) => (
<div <div key={index} className="flex items-center space-x-2 p-2 bg-gray-50 rounded-lg">
key={index}
className="flex items-center space-x-2 p-2 bg-gray-50 rounded-lg"
>
<input <input
type="text" type="text"
value={spec.specificationName} value={spec.specificationName}
onChange={(e) => onChange={(e) =>
updateSpecification( updateSpecification(index, 'specificationName', e.target.value)
index,
"specificationName",
e.target.value
)
} }
placeholder="Özellik adı" placeholder="Özellik adı"
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" 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"
@ -407,21 +361,15 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
type="text" type="text"
value={spec.specificationValue} value={spec.specificationValue}
onChange={(e) => onChange={(e) =>
updateSpecification( updateSpecification(index, 'specificationValue', e.target.value)
index,
"specificationValue",
e.target.value
)
} }
placeholder="Değer" placeholder="Değer"
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" 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"
/> />
<input <input
type="text" type="text"
value={spec.unit || ""} value={spec.unit || ''}
onChange={(e) => onChange={(e) => updateSpecification(index, 'unit', e.target.value)}
updateSpecification(index, "unit", e.target.value)
}
placeholder="Birim" placeholder="Birim"
className="w-20 px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" className="w-20 px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/> />
@ -429,13 +377,7 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
<input <input
type="checkbox" type="checkbox"
checked={spec.isRequired} checked={spec.isRequired}
onChange={(e) => onChange={(e) => updateSpecification(index, 'isRequired', e.target.checked)}
updateSpecification(
index,
"isRequired",
e.target.checked
)
}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/> />
<span className="text-sm text-gray-700">Zorunlu</span> <span className="text-sm text-gray-700">Zorunlu</span>
@ -451,8 +393,8 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
))} ))}
{specifications.length === 0 && ( {specifications.length === 0 && (
<p className="text-gray-500 text-center py-4"> <p className="text-gray-500 text-center py-4">
Henüz teknik özellik eklenmedi. "Özellik Ekle" butonunu Henüz teknik özellik eklenmedi. "Özellik Ekle" butonunu kullanarak özellik
kullanarak özellik ekleyebilirsiniz. ekleyebilirsiniz.
</p> </p>
)} )}
</div> </div>
@ -460,20 +402,18 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
{/* WorkCenter Information Summary */} {/* WorkCenter Information Summary */}
<div className="bg-gray-50 p-3 rounded-lg"> <div className="bg-gray-50 p-3 rounded-lg">
<h3 className="text-lg font-medium text-gray-900 mb-3"> <h3 className="text-lg font-medium text-gray-900 mb-3">İş Merkezi Bilgi Özeti</h3>
İş Merkezi Bilgi Özeti
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm"> <div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
<div> <div>
<span className="text-gray-600">Oluşturulma Tarihi:</span> <span className="text-gray-600">Oluşturulma Tarihi:</span>
<p className="font-medium text-gray-900"> <p className="font-medium text-gray-900">
{formData.creationTime.toLocaleDateString("tr-TR")} {formData.creationTime.toLocaleDateString('tr-TR')}
</p> </p>
</div> </div>
<div> <div>
<span className="text-gray-600">Son Güncelleme:</span> <span className="text-gray-600">Son Güncelleme:</span>
<p className="font-medium text-gray-900"> <p className="font-medium text-gray-900">
{formData.lastModificationTime.toLocaleDateString("tr-TR")} {formData.lastModificationTime.toLocaleDateString('tr-TR')}
</p> </p>
</div> </div>
</div> </div>
@ -500,7 +440,7 @@ const EditWorkCenterModal: React.FC<EditWorkCenterModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default EditWorkCenterModal; export default EditWorkCenterModal

View file

@ -1,30 +1,23 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from 'react'
import { import { FaTimes, FaPlus, FaTrash, FaCalendar, FaClock, FaSave } from 'react-icons/fa'
FaTimes,
FaPlus,
FaTrash,
FaCalendar,
FaClock,
FaSave,
} from "react-icons/fa";
import { import {
PmMaintenanceWorkOrder, PmMaintenanceWorkOrder,
WorkOrderTypeEnum, WorkOrderTypeEnum,
WorkOrderStatusEnum, WorkOrderStatusEnum,
PmWorkOrderMaterial, PmWorkOrderMaterial,
PmWorkOrderActivity, PmWorkOrderActivity,
} from "../../../types/pm"; } from '../../../types/pm'
import { mockWorkCenters } from "../../../mocks/mockWorkCenters"; import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
import { mockMaintenanceTeams } from "../../../mocks/mockMaintenanceTeams"; import { mockMaintenanceTeams } from '../../../mocks/mockMaintenanceTeams'
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from '../../../mocks/mockEmployees'
import { mockMaterials } from "../../../mocks/mockMaterials"; import { mockMaterials } from '../../../mocks/mockMaterials'
import { PriorityEnum } from "../../../types/common"; import { PriorityEnum } from '../../../types/common'
interface EditWorkOrderModalProps { interface EditWorkOrderModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (workOrder: PmMaintenanceWorkOrder) => void; onSave: (workOrder: PmMaintenanceWorkOrder) => void
workOrder: PmMaintenanceWorkOrder; workOrder: PmMaintenanceWorkOrder
} }
const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
@ -34,28 +27,28 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
workOrder, workOrder,
}) => { }) => {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
workOrderNumber: "", workOrderNumber: '',
workCenterId: "", workCenterId: '',
orderType: WorkOrderTypeEnum.Corrective, orderType: WorkOrderTypeEnum.Corrective,
priority: PriorityEnum.Normal, priority: PriorityEnum.Normal,
status: WorkOrderStatusEnum.Created, status: WorkOrderStatusEnum.Created,
description: "", description: '',
reportedBy: "", reportedBy: '',
assignedTo: "", assignedTo: '',
maintenanceTeamId: "", maintenanceTeamId: '',
scheduledStart: "", scheduledStart: '',
scheduledEnd: "", scheduledEnd: '',
actualStart: "", actualStart: '',
actualEnd: "", actualEnd: '',
estimatedCost: 0, estimatedCost: 0,
actualCost: 0, actualCost: 0,
notes: "", notes: '',
completionNotes: "", completionNotes: '',
}); })
const [materials, setMaterials] = useState<PmWorkOrderMaterial[]>([]); const [materials, setMaterials] = useState<PmWorkOrderMaterial[]>([])
const [activities, setActivities] = useState<PmWorkOrderActivity[]>([]); const [activities, setActivities] = useState<PmWorkOrderActivity[]>([])
const [errors, setErrors] = useState<Record<string, string>>({}); const [errors, setErrors] = useState<Record<string, string>>({})
useEffect(() => { useEffect(() => {
if (workOrder && isOpen) { if (workOrder && isOpen) {
@ -67,56 +60,52 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
status: workOrder.status, status: workOrder.status,
description: workOrder.description, description: workOrder.description,
reportedBy: workOrder.reportedBy, reportedBy: workOrder.reportedBy,
assignedTo: workOrder.assignedTo || "", assignedTo: workOrder.assignedTo || '',
maintenanceTeamId: workOrder.maintenanceTeamId || "", maintenanceTeamId: workOrder.maintenanceTeamId || '',
scheduledStart: workOrder.scheduledStart scheduledStart: workOrder.scheduledStart
? workOrder.scheduledStart.toISOString().slice(0, 16) ? workOrder.scheduledStart.toISOString().slice(0, 16)
: "", : '',
scheduledEnd: workOrder.scheduledEnd scheduledEnd: workOrder.scheduledEnd
? workOrder.scheduledEnd.toISOString().slice(0, 16) ? workOrder.scheduledEnd.toISOString().slice(0, 16)
: "", : '',
actualStart: workOrder.actualStart actualStart: workOrder.actualStart ? workOrder.actualStart.toISOString().slice(0, 16) : '',
? workOrder.actualStart.toISOString().slice(0, 16) actualEnd: workOrder.actualEnd ? workOrder.actualEnd.toISOString().slice(0, 16) : '',
: "",
actualEnd: workOrder.actualEnd
? workOrder.actualEnd.toISOString().slice(0, 16)
: "",
estimatedCost: workOrder.estimatedCost, estimatedCost: workOrder.estimatedCost,
actualCost: workOrder.actualCost, actualCost: workOrder.actualCost,
notes: workOrder.notes || "", notes: workOrder.notes || '',
completionNotes: workOrder.completionNotes || "", completionNotes: workOrder.completionNotes || '',
}); })
setMaterials(workOrder.materials); setMaterials(workOrder.materials)
setActivities(workOrder.activities); setActivities(workOrder.activities)
} }
}, [workOrder, isOpen]); }, [workOrder, isOpen])
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (!formData.description.trim()) { if (!formData.description.trim()) {
newErrors.description = "Açıklama alanı zorunludur"; newErrors.description = 'Açıklama alanı zorunludur'
} }
if (!formData.workCenterId) { if (!formData.workCenterId) {
newErrors.workCenterId = "İş merkezi seçimi zorunludur"; newErrors.workCenterId = 'İş merkezi seçimi zorunludur'
} }
if (!formData.reportedBy.trim()) { if (!formData.reportedBy.trim()) {
newErrors.reportedBy = "Bildiren kişi zorunludur"; newErrors.reportedBy = 'Bildiren kişi zorunludur'
} }
if (formData.estimatedCost < 0) { if (formData.estimatedCost < 0) {
newErrors.estimatedCost = "Tahmini maliyet negatif olamaz"; newErrors.estimatedCost = 'Tahmini maliyet negatif olamaz'
} }
if (formData.actualCost < 0) { if (formData.actualCost < 0) {
newErrors.actualCost = "Gerçek maliyet negatif olamaz"; newErrors.actualCost = 'Gerçek maliyet negatif olamaz'
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault()
if (!validateForm()) return; if (!validateForm()) return
const updatedWorkOrder: PmMaintenanceWorkOrder = { const updatedWorkOrder: PmMaintenanceWorkOrder = {
...workOrder, ...workOrder,
@ -129,15 +118,9 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
reportedBy: formData.reportedBy, reportedBy: formData.reportedBy,
assignedTo: formData.assignedTo || undefined, assignedTo: formData.assignedTo || undefined,
maintenanceTeamId: formData.maintenanceTeamId || undefined, maintenanceTeamId: formData.maintenanceTeamId || undefined,
scheduledStart: formData.scheduledStart scheduledStart: formData.scheduledStart ? new Date(formData.scheduledStart) : undefined,
? new Date(formData.scheduledStart) scheduledEnd: formData.scheduledEnd ? new Date(formData.scheduledEnd) : undefined,
: undefined, actualStart: formData.actualStart ? new Date(formData.actualStart) : undefined,
scheduledEnd: formData.scheduledEnd
? new Date(formData.scheduledEnd)
: undefined,
actualStart: formData.actualStart
? new Date(formData.actualStart)
: undefined,
actualEnd: formData.actualEnd ? new Date(formData.actualEnd) : undefined, actualEnd: formData.actualEnd ? new Date(formData.actualEnd) : undefined,
estimatedCost: formData.estimatedCost, estimatedCost: formData.estimatedCost,
actualCost: formData.actualCost, actualCost: formData.actualCost,
@ -146,39 +129,35 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
notes: formData.notes || undefined, notes: formData.notes || undefined,
completionNotes: formData.completionNotes || undefined, completionNotes: formData.completionNotes || undefined,
lastModificationTime: new Date(), lastModificationTime: new Date(),
}; }
onSave(updatedWorkOrder); onSave(updatedWorkOrder)
onClose(); onClose()
}; }
const addMaterial = () => { const addMaterial = () => {
const newMaterial: PmWorkOrderMaterial = { const newMaterial: PmWorkOrderMaterial = {
id: `mat-${Date.now()}`, id: `mat-${Date.now()}`,
workOrderId: workOrder.id, workOrderId: workOrder.id,
materialId: "", materialId: '',
materialCode: "", materialCode: '',
materialName: "", materialName: '',
plannedQuantity: 1, plannedQuantity: 1,
actualQuantity: 0, actualQuantity: 0,
unitCost: 0, unitCost: 0,
totalCost: 0, totalCost: 0,
}; }
setMaterials([...materials, newMaterial]); setMaterials([...materials, newMaterial])
}; }
const removeMaterial = (index: number) => { const removeMaterial = (index: number) => {
setMaterials(materials.filter((_, i) => i !== index)); setMaterials(materials.filter((_, i) => i !== index))
}; }
const updateMaterial = ( const updateMaterial = (index: number, field: string, value: string | number) => {
index: number, const updated = [...materials]
field: string, if (field === 'materialId') {
value: string | number const selectedMaterial = mockMaterials.find((m) => m.id === value)
) => {
const updated = [...materials];
if (field === "materialId") {
const selectedMaterial = mockMaterials.find((m) => m.id === value);
if (selectedMaterial) { if (selectedMaterial) {
updated[index] = { updated[index] = {
...updated[index], ...updated[index],
@ -186,75 +165,70 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
materialCode: selectedMaterial.code, materialCode: selectedMaterial.code,
materialName: selectedMaterial.name, materialName: selectedMaterial.name,
unitCost: selectedMaterial.costPrice, unitCost: selectedMaterial.costPrice,
totalCost: totalCost: updated[index].plannedQuantity * selectedMaterial.costPrice,
updated[index].plannedQuantity * selectedMaterial.costPrice, }
};
} }
} else { } else {
const material = updated[index]; const material = updated[index]
if (field === "plannedQuantity") { if (field === 'plannedQuantity') {
material.plannedQuantity = value as number; material.plannedQuantity = value as number
material.totalCost = material.plannedQuantity * material.unitCost; material.totalCost = material.plannedQuantity * material.unitCost
} else if (field === "actualQuantity") { } else if (field === 'actualQuantity') {
material.actualQuantity = value as number; material.actualQuantity = value as number
} else if (field === "unitCost") { } else if (field === 'unitCost') {
material.unitCost = value as number; material.unitCost = value as number
material.totalCost = material.plannedQuantity * material.unitCost; material.totalCost = material.plannedQuantity * material.unitCost
} }
} }
setMaterials(updated); setMaterials(updated)
}; }
const addActivity = () => { const addActivity = () => {
const newActivity: PmWorkOrderActivity = { const newActivity: PmWorkOrderActivity = {
id: `act-${Date.now()}`, id: `act-${Date.now()}`,
workOrderId: workOrder.id, workOrderId: workOrder.id,
activityDescription: "", activityDescription: '',
plannedDuration: 60, plannedDuration: 60,
actualDuration: 0, actualDuration: 0,
performedBy: "", performedBy: '',
notes: "", notes: '',
}; }
setActivities([...activities, newActivity]); setActivities([...activities, newActivity])
}; }
const removeActivity = (index: number) => { const removeActivity = (index: number) => {
setActivities(activities.filter((_, i) => i !== index)); setActivities(activities.filter((_, i) => i !== index))
}; }
const updateActivity = ( const updateActivity = (index: number, field: string, value: string | number) => {
index: number, const updated = [...activities]
field: string, const activity = updated[index]
value: string | number if (field === 'activityDescription') {
) => { activity.activityDescription = value as string
const updated = [...activities]; } else if (field === 'plannedDuration') {
const activity = updated[index]; activity.plannedDuration = value as number
if (field === "activityDescription") { } else if (field === 'actualDuration') {
activity.activityDescription = value as string; activity.actualDuration = value as number
} else if (field === "plannedDuration") { } else if (field === 'performedBy') {
activity.plannedDuration = value as number; activity.performedBy = value as string
} else if (field === "actualDuration") { } else if (field === 'notes') {
activity.actualDuration = value as number; activity.notes = value as string
} else if (field === "performedBy") {
activity.performedBy = value as string;
} else if (field === "notes") {
activity.notes = value as string;
} }
setActivities(updated); setActivities(updated)
}; }
const toggleActivityCompletion = (index: number) => { const toggleActivityCompletion = (index: number) => {
const updated = [...activities]; const updated = [...activities]
const activity = updated[index]; const activity = updated[index]
if (activity.completedAt) { if (activity.completedAt) {
activity.completedAt = undefined; activity.completedAt = undefined
} else { } else {
activity.completedAt = new Date(); activity.completedAt = new Date()
} }
setActivities(updated); setActivities(updated)
}; }
if (!isOpen) return null; if (!isOpen) return null
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -264,10 +238,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<FaSave className="w-5 h-5 mr-2 text-blue-600" /> <FaSave className="w-5 h-5 mr-2 text-blue-600" />
İş Emrini Düzenle İş Emrini Düzenle
</h3> </h3>
<button <button onClick={onClose} className="text-gray-400 hover:text-gray-600">
onClick={onClose}
className="text-gray-400 hover:text-gray-600"
>
<FaTimes className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>
@ -276,24 +247,18 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
{/* Basic Information */} {/* Basic Information */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">İş Emri No</label>
İş Emri No
</label>
<input <input
type="text" type="text"
value={formData.workOrderNumber} value={formData.workOrderNumber}
onChange={(e) => onChange={(e) => setFormData({ ...formData, workOrderNumber: e.target.value })}
setFormData({ ...formData, workOrderNumber: 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" 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 readOnly
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Durum</label>
Durum
</label>
<select <select
value={formData.status} value={formData.status}
onChange={(e) => onChange={(e) =>
@ -306,33 +271,21 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
> >
<option value={WorkOrderStatusEnum.Created}>Oluşturuldu</option> <option value={WorkOrderStatusEnum.Created}>Oluşturuldu</option>
<option value={WorkOrderStatusEnum.Planned}>Planlandı</option> <option value={WorkOrderStatusEnum.Planned}>Planlandı</option>
<option value={WorkOrderStatusEnum.Released}> <option value={WorkOrderStatusEnum.Released}>Serbest Bırakıldı</option>
Serbest Bırakıldı <option value={WorkOrderStatusEnum.InProgress}>Devam Ediyor</option>
</option>
<option value={WorkOrderStatusEnum.InProgress}>
Devam Ediyor
</option>
<option value={WorkOrderStatusEnum.OnHold}>Beklemede</option> <option value={WorkOrderStatusEnum.OnHold}>Beklemede</option>
<option value={WorkOrderStatusEnum.Completed}> <option value={WorkOrderStatusEnum.Completed}>Tamamlandı</option>
Tamamlandı <option value={WorkOrderStatusEnum.Cancelled}>İptal Edildi</option>
</option>
<option value={WorkOrderStatusEnum.Cancelled}>
İptal Edildi
</option>
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">İş Merkezi *</label>
İş Merkezi *
</label>
<select <select
value={formData.workCenterId} value={formData.workCenterId}
onChange={(e) => onChange={(e) => setFormData({ ...formData, workCenterId: e.target.value })}
setFormData({ ...formData, workCenterId: e.target.value })
}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.workCenterId ? "border-red-500" : "border-gray-300" errors.workCenterId ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
<option value="">İş Merkezi Seçin</option> <option value="">İş Merkezi Seçin</option>
@ -343,16 +296,12 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
))} ))}
</select> </select>
{errors.workCenterId && ( {errors.workCenterId && (
<p className="mt-1 text-sm text-red-600"> <p className="mt-1 text-sm text-red-600">{errors.workCenterId}</p>
{errors.workCenterId}
</p>
)} )}
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">İş Emri Tipi</label>
İş Emri Tipi
</label>
<select <select
value={formData.orderType} value={formData.orderType}
onChange={(e) => onChange={(e) =>
@ -367,16 +316,12 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<option value={WorkOrderTypeEnum.Corrective}>Düzeltici</option> <option value={WorkOrderTypeEnum.Corrective}>Düzeltici</option>
<option value={WorkOrderTypeEnum.Emergency}>Acil</option> <option value={WorkOrderTypeEnum.Emergency}>Acil</option>
<option value={WorkOrderTypeEnum.Inspection}>İnceleme</option> <option value={WorkOrderTypeEnum.Inspection}>İnceleme</option>
<option value={WorkOrderTypeEnum.Calibration}> <option value={WorkOrderTypeEnum.Calibration}>Kalibrasyon</option>
Kalibrasyon
</option>
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Öncelik</label>
Öncelik
</label>
<select <select
value={formData.priority} value={formData.priority}
onChange={(e) => onChange={(e) =>
@ -396,17 +341,13 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">ıklama *</label>
ıklama *
</label>
<textarea <textarea
value={formData.description} value={formData.description}
onChange={(e) => onChange={(e) => setFormData({ ...formData, description: e.target.value })}
setFormData({ ...formData, description: e.target.value })
}
rows={2} 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 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.description ? "border-red-500" : "border-gray-300" errors.description ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="İş emri açıklaması..." placeholder="İş emri açıklaması..."
/> />
@ -418,17 +359,13 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
{/* Assignment */} {/* Assignment */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6"> <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Bildiren *</label>
Bildiren *
</label>
<input <input
type="text" type="text"
value={formData.reportedBy} value={formData.reportedBy}
onChange={(e) => onChange={(e) => setFormData({ ...formData, reportedBy: e.target.value })}
setFormData({ ...formData, reportedBy: e.target.value })
}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.reportedBy ? "border-red-500" : "border-gray-300" errors.reportedBy ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Bildiren kişi adı" placeholder="Bildiren kişi adı"
/> />
@ -438,14 +375,10 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Atanan Kişi</label>
Atanan Kişi
</label>
<select <select
value={formData.assignedTo} value={formData.assignedTo}
onChange={(e) => onChange={(e) => setFormData({ ...formData, assignedTo: e.target.value })}
setFormData({ ...formData, assignedTo: 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" 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> <option value="">Kişi Seçin</option>
@ -458,9 +391,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Bakım Ekibi</label>
Bakım Ekibi
</label>
<select <select
value={formData.maintenanceTeamId} value={formData.maintenanceTeamId}
onChange={(e) => onChange={(e) =>
@ -491,9 +422,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<input <input
type="datetime-local" type="datetime-local"
value={formData.scheduledStart} value={formData.scheduledStart}
onChange={(e) => onChange={(e) => setFormData({ ...formData, scheduledStart: e.target.value })}
setFormData({ ...formData, scheduledStart: 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" 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>
@ -506,9 +435,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<input <input
type="datetime-local" type="datetime-local"
value={formData.scheduledEnd} value={formData.scheduledEnd}
onChange={(e) => onChange={(e) => setFormData({ ...formData, scheduledEnd: e.target.value })}
setFormData({ ...formData, scheduledEnd: 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" 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>
@ -521,9 +448,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<input <input
type="datetime-local" type="datetime-local"
value={formData.actualStart} value={formData.actualStart}
onChange={(e) => onChange={(e) => setFormData({ ...formData, actualStart: e.target.value })}
setFormData({ ...formData, actualStart: 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" 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>
@ -536,9 +461,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<input <input
type="datetime-local" type="datetime-local"
value={formData.actualEnd} value={formData.actualEnd}
onChange={(e) => onChange={(e) => setFormData({ ...formData, actualEnd: e.target.value })}
setFormData({ ...formData, actualEnd: 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" 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>
@ -562,21 +485,17 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
}) })
} }
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.estimatedCost ? "border-red-500" : "border-gray-300" errors.estimatedCost ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="0.00" placeholder="0.00"
/> />
{errors.estimatedCost && ( {errors.estimatedCost && (
<p className="mt-1 text-sm text-red-600"> <p className="mt-1 text-sm text-red-600">{errors.estimatedCost}</p>
{errors.estimatedCost}
</p>
)} )}
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Gerçek Maliyet</label>
Gerçek Maliyet
</label>
<input <input
type="number" type="number"
min="0" min="0"
@ -589,7 +508,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
}) })
} }
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.actualCost ? "border-red-500" : "border-gray-300" errors.actualCost ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="0.00" placeholder="0.00"
/> />
@ -614,20 +533,13 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</div> </div>
{materials.map((material, index) => ( {materials.map((material, index) => (
<div <div key={material.id || index} className="bg-gray-50 p-3 rounded-lg mb-2">
key={material.id || index}
className="bg-gray-50 p-3 rounded-lg mb-2"
>
<div className="grid grid-cols-1 md:grid-cols-6 gap-4"> <div className="grid grid-cols-1 md:grid-cols-6 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Malzeme</label>
Malzeme
</label>
<select <select
value={material.materialId} value={material.materialId}
onChange={(e) => onChange={(e) => updateMaterial(index, 'materialId', e.target.value)}
updateMaterial(index, "materialId", 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" 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> <option value="">Malzeme Seçin</option>
@ -647,11 +559,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
min="0" min="0"
value={material.plannedQuantity} value={material.plannedQuantity}
onChange={(e) => onChange={(e) =>
updateMaterial( updateMaterial(index, 'plannedQuantity', parseInt(e.target.value) || 0)
index,
"plannedQuantity",
parseInt(e.target.value) || 0
)
} }
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" 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"
/> />
@ -665,11 +573,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
min="0" min="0"
value={material.actualQuantity} value={material.actualQuantity}
onChange={(e) => onChange={(e) =>
updateMaterial( updateMaterial(index, 'actualQuantity', parseInt(e.target.value) || 0)
index,
"actualQuantity",
parseInt(e.target.value) || 0
)
} }
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" 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"
/> />
@ -684,19 +588,13 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
step="0.01" step="0.01"
value={material.unitCost} value={material.unitCost}
onChange={(e) => onChange={(e) =>
updateMaterial( updateMaterial(index, 'unitCost', parseFloat(e.target.value) || 0)
index,
"unitCost",
parseFloat(e.target.value) || 0
)
} }
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" 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>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Toplam</label>
Toplam
</label>
<input <input
type="text" type="text"
value={`${material.totalCost.toFixed(2)}`} value={`${material.totalCost.toFixed(2)}`}
@ -733,10 +631,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</div> </div>
{activities.map((activity, index) => ( {activities.map((activity, index) => (
<div <div key={activity.id || index} className="bg-gray-50 p-3 rounded-lg mb-2">
key={activity.id || index}
className="bg-gray-50 p-3 rounded-lg mb-2"
>
<div className="grid grid-cols-1 md:grid-cols-6 gap-4"> <div className="grid grid-cols-1 md:grid-cols-6 gap-4">
<div className="md:col-span-2"> <div className="md:col-span-2">
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">
@ -745,13 +640,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<input <input
type="text" type="text"
value={activity.activityDescription} value={activity.activityDescription}
onChange={(e) => onChange={(e) => updateActivity(index, 'activityDescription', e.target.value)}
updateActivity(
index,
"activityDescription",
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" 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ı" placeholder="Aktivite açıklaması"
/> />
@ -766,11 +655,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
min="0" min="0"
value={activity.plannedDuration} value={activity.plannedDuration}
onChange={(e) => onChange={(e) =>
updateActivity( updateActivity(index, 'plannedDuration', parseInt(e.target.value) || 0)
index,
"plannedDuration",
parseInt(e.target.value) || 0
)
} }
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" 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"
/> />
@ -785,25 +670,17 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
min="0" min="0"
value={activity.actualDuration} value={activity.actualDuration}
onChange={(e) => onChange={(e) =>
updateActivity( updateActivity(index, 'actualDuration', parseInt(e.target.value) || 0)
index,
"actualDuration",
parseInt(e.target.value) || 0
)
} }
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" 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>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Yapan</label>
Yapan
</label>
<input <input
type="text" type="text"
value={activity.performedBy} value={activity.performedBy}
onChange={(e) => onChange={(e) => updateActivity(index, 'performedBy', e.target.value)}
updateActivity(index, "performedBy", 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" 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" placeholder="Yapan kişi"
/> />
@ -814,11 +691,11 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
onClick={() => toggleActivityCompletion(index)} onClick={() => toggleActivityCompletion(index)}
className={`px-3 py-2 rounded text-xs ${ className={`px-3 py-2 rounded text-xs ${
activity.completedAt activity.completedAt
? "bg-green-600 text-white" ? 'bg-green-600 text-white'
: "bg-gray-300 text-gray-700" : 'bg-gray-300 text-gray-700'
}`} }`}
> >
{activity.completedAt ? "Tamamlandı" : "Bekliyor"} {activity.completedAt ? 'Tamamlandı' : 'Bekliyor'}
</button> </button>
<button <button
type="button" type="button"
@ -836,9 +713,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</label> </label>
<textarea <textarea
value={activity.notes} value={activity.notes}
onChange={(e) => onChange={(e) => updateActivity(index, 'notes', e.target.value)}
updateActivity(index, "notes", e.target.value)
}
rows={1} 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" 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..." placeholder="Aktivite hakkında notlar..."
@ -857,9 +732,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</label> </label>
<textarea <textarea
value={formData.notes} value={formData.notes}
onChange={(e) => onChange={(e) => setFormData({ ...formData, notes: e.target.value })}
setFormData({ ...formData, notes: e.target.value })
}
rows={2} 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" 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..." placeholder="Genel notlar..."
@ -872,9 +745,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</label> </label>
<textarea <textarea
value={formData.completionNotes} value={formData.completionNotes}
onChange={(e) => onChange={(e) => setFormData({ ...formData, completionNotes: e.target.value })}
setFormData({ ...formData, completionNotes: e.target.value })
}
rows={2} 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" 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..." placeholder="Tamamlanma ile ilgili notlar..."
@ -902,7 +773,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</form> </form>
</div> </div>
</div> </div>
); )
}; }
export default EditWorkOrderModal; export default EditWorkOrderModal

View file

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { import {
FaPlus, FaPlus,
FaSearch, FaSearch,
@ -13,21 +13,17 @@ import {
FaFileAlt, FaFileAlt,
FaCamera, FaCamera,
FaPhone, FaPhone,
} from "react-icons/fa"; } from 'react-icons/fa'
import { import { NotificationStatusEnum, PmFaultNotification, PmWorkCenter } from '../../../types/pm'
NotificationStatusEnum, import { mockFaultNotifications } from '../../../mocks/mockFaultNotifications'
PmFaultNotification, import NewFaultNotificationModal from './NewFaultNotificationModal'
PmWorkCenter, import ViewFaultNotificationModal from './ViewFaultNotificationModal'
} from "../../../types/pm"; import EditFaultNotificationModal from './EditFaultNotificationModal'
import { mockFaultNotifications } from "../../../mocks/mockFaultNotifications"; import CreateWorkOrderFromNotificationModal from './CreateWorkOrderFromNotificationModal'
import NewFaultNotificationModal from "./NewFaultNotificationModal"; import AssignNotificationModal from './AssignNotificationModal'
import ViewFaultNotificationModal from "./ViewFaultNotificationModal"; import ChangeNotificationStatusModal from './ChangeNotificationStatusModal'
import EditFaultNotificationModal from "./EditFaultNotificationModal"; import Widget from '../../../components/common/Widget'
import CreateWorkOrderFromNotificationModal from "./CreateWorkOrderFromNotificationModal"; import { PriorityEnum } from '../../../types/common'
import AssignNotificationModal from "./AssignNotificationModal";
import ChangeNotificationStatusModal from "./ChangeNotificationStatusModal";
import Widget from "../../../components/common/Widget";
import { PriorityEnum } from "../../../types/common";
import { import {
getFaultTypeColor, getFaultTypeColor,
getFaultTypeText, getFaultTypeText,
@ -37,139 +33,116 @@ import {
getNotificationStatusColor, getNotificationStatusColor,
getNotificationStatusIcon, getNotificationStatusIcon,
getNotificationStatusText, getNotificationStatusText,
} from "../../../utils/erp"; } from '../../../utils/erp'
import { Container } from '@/components/shared'
interface AssignmentData { interface AssignmentData {
notificationIds: string[]; notificationIds: string[]
assignedTo?: string; assignedTo?: string
teamId?: string; teamId?: string
} }
interface StatusChangeData { interface StatusChangeData {
notificationIds: string[]; notificationIds: string[]
status: NotificationStatusEnum; status: NotificationStatusEnum
} }
const FaultNotifications: React.FC = () => { const FaultNotifications: React.FC = () => {
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState('')
const [statusFilter, setStatusFilter] = useState< const [statusFilter, setStatusFilter] = useState<NotificationStatusEnum | 'all'>('all')
NotificationStatusEnum | "all" const [priorityFilter, setPriorityFilter] = useState<PriorityEnum | 'all'>('all')
>("all"); const [showModal, setShowModal] = useState(false)
const [priorityFilter, setPriorityFilter] = useState<PriorityEnum | "all">( const [editingNotification, setEditingNotification] = useState<PmFaultNotification | null>(null)
"all" const [viewingNotification, setViewingNotification] = useState<PmFaultNotification | null>(null)
); const [selectedNotifications, setSelectedNotifications] = useState<string[]>([])
const [showModal, setShowModal] = useState(false); const [showCreateWorkOrderModal, setShowCreateWorkOrderModal] = useState(false)
const [editingNotification, setEditingNotification] = const [showAssignModal, setShowAssignModal] = useState(false)
useState<PmFaultNotification | null>(null); const [showStatusChangeModal, setShowStatusChangeModal] = useState(false)
const [viewingNotification, setViewingNotification] =
useState<PmFaultNotification | null>(null);
const [selectedNotifications, setSelectedNotifications] = useState<string[]>(
[]
);
const [showCreateWorkOrderModal, setShowCreateWorkOrderModal] =
useState(false);
const [showAssignModal, setShowAssignModal] = useState(false);
const [showStatusChangeModal, setShowStatusChangeModal] = useState(false);
// Mock data - replace with actual API calls // Mock data - replace with actual API calls
const [notifications, setNotifications] = useState<PmFaultNotification[]>( const [notifications, setNotifications] = useState<PmFaultNotification[]>(mockFaultNotifications)
mockFaultNotifications
);
const filteredNotifications = notifications.filter((notification) => { const filteredNotifications = notifications.filter((notification) => {
const matchesSearch = const matchesSearch =
notification.notificationCode notification.notificationCode.toLowerCase().includes(searchTerm.toLowerCase()) ||
.toLowerCase()
.includes(searchTerm.toLowerCase()) ||
notification.title.toLowerCase().includes(searchTerm.toLowerCase()) || notification.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
notification.workCenter.code notification.workCenter.code.toLowerCase().includes(searchTerm.toLowerCase()) ||
.toLowerCase() notification.reportedBy.toLowerCase().includes(searchTerm.toLowerCase())
.includes(searchTerm.toLowerCase()) || const matchesStatus = statusFilter === 'all' || notification.status === statusFilter
notification.reportedBy.toLowerCase().includes(searchTerm.toLowerCase()); const matchesPriority = priorityFilter === 'all' || notification.priority === priorityFilter
const matchesStatus = return matchesSearch && matchesStatus && matchesPriority
statusFilter === "all" || notification.status === statusFilter; })
const matchesPriority =
priorityFilter === "all" || notification.priority === priorityFilter;
return matchesSearch && matchesStatus && matchesPriority;
});
const getTimeAgo = (date: Date) => { const getTimeAgo = (date: Date) => {
const now = new Date(); const now = new Date()
const diffInMs = now.getTime() - date.getTime(); const diffInMs = now.getTime() - date.getTime()
const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60)); const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60))
const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24)); const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24))
if (diffInHours < 1) { if (diffInHours < 1) {
const diffInMinutes = Math.floor(diffInMs / (1000 * 60)); const diffInMinutes = Math.floor(diffInMs / (1000 * 60))
return `${diffInMinutes} dakika önce`; return `${diffInMinutes} dakika önce`
} else if (diffInHours < 24) { } else if (diffInHours < 24) {
return `${diffInHours} saat önce`; return `${diffInHours} saat önce`
} else { } else {
return `${diffInDays} gün önce`; return `${diffInDays} gün önce`
} }
}; }
const handleAddNotification = () => { const handleAddNotification = () => {
setEditingNotification(null); setEditingNotification(null)
setShowModal(true); setShowModal(true)
}; }
const handleEdit = (notification: PmFaultNotification) => { const handleEdit = (notification: PmFaultNotification) => {
setEditingNotification(notification); setEditingNotification(notification)
setShowModal(true); setShowModal(true)
}; }
const handleView = (notification: PmFaultNotification) => { const handleView = (notification: PmFaultNotification) => {
setViewingNotification(notification); setViewingNotification(notification)
}; }
const handleSelectNotification = (notificationId: string) => { const handleSelectNotification = (notificationId: string) => {
setSelectedNotifications((prev) => setSelectedNotifications((prev) =>
prev.includes(notificationId) prev.includes(notificationId)
? prev.filter((id) => id !== notificationId) ? prev.filter((id) => id !== notificationId)
: [...prev, notificationId] : [...prev, notificationId],
); )
}; }
const handleSaveNotification = ( const handleSaveNotification = (notificationData: Partial<PmFaultNotification>) => {
notificationData: Partial<PmFaultNotification>
) => {
if (editingNotification) { if (editingNotification) {
// Update existing notification // Update existing notification
setNotifications((prev) => setNotifications((prev) =>
prev.map((n) => prev.map((n) => (n.id === editingNotification.id ? { ...n, ...notificationData } : n)),
n.id === editingNotification.id ? { ...n, ...notificationData } : n )
)
);
} else { } else {
// Add new notification // Add new notification
setNotifications((prev) => [ setNotifications((prev) => [...prev, notificationData as PmFaultNotification])
...prev,
notificationData as PmFaultNotification,
]);
} }
}; }
const handleCreateWorkOrder = () => { const handleCreateWorkOrder = () => {
setShowCreateWorkOrderModal(true); setShowCreateWorkOrderModal(true)
}; }
const handleAssignNotifications = () => { const handleAssignNotifications = () => {
setShowAssignModal(true); setShowAssignModal(true)
}; }
const handleChangeStatus = () => { const handleChangeStatus = () => {
setShowStatusChangeModal(true); setShowStatusChangeModal(true)
}; }
const handleWorkOrderSave = (workOrderData: PmWorkCenter) => { const handleWorkOrderSave = (workOrderData: PmWorkCenter) => {
console.log("İş emri oluşturuldu:", workOrderData); console.log('İş emri oluşturuldu:', workOrderData)
// Here you would typically save to backend // Here you would typically save to backend
setSelectedNotifications([]); setSelectedNotifications([])
}; }
const handleAssignmentSave = (assignmentData: AssignmentData) => { const handleAssignmentSave = (assignmentData: AssignmentData) => {
console.log("Atama yapıldı:", assignmentData); console.log('Atama yapıldı:', assignmentData)
// Here you would typically save to backend // Here you would typically save to backend
// Update notifications with assignment // Update notifications with assignment
setNotifications((prev) => setNotifications((prev) =>
@ -180,14 +153,14 @@ const FaultNotifications: React.FC = () => {
assignedTo: assignmentData.assignedTo, assignedTo: assignmentData.assignedTo,
status: NotificationStatusEnum.Assigned, status: NotificationStatusEnum.Assigned,
} }
: n : n,
) ),
); )
setSelectedNotifications([]); setSelectedNotifications([])
}; }
const handleStatusChangeSave = (statusChangeData: StatusChangeData) => { const handleStatusChangeSave = (statusChangeData: StatusChangeData) => {
console.log("Durum değiştirildi:", statusChangeData); console.log('Durum değiştirildi:', statusChangeData)
// Here you would typically save to backend // Here you would typically save to backend
// Update notifications with new status // Update notifications with new status
setNotifications((prev) => setNotifications((prev) =>
@ -198,359 +171,322 @@ const FaultNotifications: React.FC = () => {
status: statusChangeData.status, status: statusChangeData.status,
lastModificationTime: new Date(), lastModificationTime: new Date(),
} }
: n : n,
) ),
); )
setSelectedNotifications([]); setSelectedNotifications([])
}; }
return ( return (
<div className="space-y-4 pt-2"> <Container>
{/* Header */} <div className="space-y-2">
<div className="flex items-center justify-between"> {/* Header */}
<div> <div className="flex items-center justify-between">
<h2 className="text-2xl font-bold text-gray-900"> <div>
Arıza Bildirimleri <h2 className="text-2xl font-bold text-gray-900">Arıza Bildirimleri</h2>
</h2> <p className="text-gray-600">İş merkezi arızalarını takip edin ve yönetin</p>
<p className="text-gray-600">
İş merkezi arızalarını takip edin ve yönetin
</p>
</div>
<button
onClick={handleAddNotification}
className="bg-blue-600 text-white px-3 py-1.5 rounded-lg hover:bg-blue-700 flex items-center space-x-2 text-sm"
>
<FaPlus className="w-4 h-4" />
<span>Yeni Bildirim</span>
</button>
</div>
{/* Summary Cards */}
<div className="grid grid-cols-1 md:grid-cols-5 gap-4">
<Widget
title="Toplam"
value={notifications.length}
color="gray"
icon="FaExclamationTriangle"
/>
<Widget
title="Açık"
value={
notifications.filter(
(n) => n.status === NotificationStatusEnum.Open
).length
}
color="red"
icon="FaExclamationTriangle"
/>
<Widget
title="Devam Ediyor"
value={
notifications.filter(
(n) => n.status === NotificationStatusEnum.InProgress
).length
}
color="orange"
icon="FaClock"
/>
<Widget
title="Çözüldü"
value={
notifications.filter(
(n) => n.status === NotificationStatusEnum.Resolved
).length
}
color="green"
icon="FaCheckCircle"
/>
<Widget
title="Acil"
value={
notifications.filter((n) => n.priority === PriorityEnum.Urgent)
.length
}
color="red"
icon="FaTimesCircle"
/>
</div>
{/* Filters */}
<div className="flex space-x-4">
<div className="flex-1 relative">
<FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5" />
<input
type="text"
placeholder="Bildirim ara..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-10 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<div className="relative">
<FaFilter className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5" />
<select
value={statusFilter}
onChange={(e) =>
setStatusFilter(e.target.value as NotificationStatusEnum | "all")
}
className="pl-10 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="all">Tüm Durumlar</option>
<option value={NotificationStatusEnum.Open}>ık</option>
<option value={NotificationStatusEnum.Assigned}>Atandı</option>
<option value={NotificationStatusEnum.InProgress}>
Devam Ediyor
</option>
<option value={NotificationStatusEnum.Resolved}>Çözüldü</option>
<option value={NotificationStatusEnum.Closed}>Kapatıldı</option>
</select>
</div>
<div className="relative">
<select
value={priorityFilter}
onChange={(e) =>
setPriorityFilter(e.target.value as PriorityEnum | "all")
}
className="pl-4 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="all">Tüm Öncelikler</option>
<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>
{/* Notifications List */}
<div className="space-y-3 pt-2">
{filteredNotifications.map((notification) => (
<div
key={notification.id}
className={`bg-white rounded-lg shadow-md border-l-4 p-4 hover:shadow-lg transition-shadow ${getCriticalityLevelColor(
notification.severity
)}`}
>
<div className="flex items-start justify-between">
<div className="flex items-start space-x-4 flex-1">
<input
type="checkbox"
checked={selectedNotifications.includes(notification.id)}
onChange={() => handleSelectNotification(notification.id)}
className="mt-1 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<div className="flex-1">
<div className="flex items-center space-x-3 mb-2">
<h3 className="text-lg font-semibold text-gray-900">
{notification.notificationCode}
</h3>
<span
className={`px-2 py-1 rounded-full text-xs font-medium flex items-center space-x-1 ${getNotificationStatusColor(
notification.status
)}`}
>
{getNotificationStatusIcon(notification.status)}
<span>
{getNotificationStatusText(notification.status)}
</span>
</span>
<span
className={`px-2 py-1 rounded-full text-xs font-medium ${getPriorityColor(
notification.priority
)}`}
>
{getPriorityText(notification.priority)}
</span>
<span
className={`px-2 py-1 rounded-full text-xs font-medium ${getFaultTypeColor(
notification.faultType
)}`}
>
{getFaultTypeText(notification.faultType)}
</span>
</div>
<h4 className="font-medium text-gray-800 mb-2">
{notification.title}
</h4>
<p className="text-sm text-gray-600 mb-3">
{notification.description.length > 150
? `${notification.description.substring(0, 150)}...`
: notification.description}
</p>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 text-sm mb-3">
<div>
<span className="text-gray-500">İş Merkezi:</span>
<p className="font-medium text-gray-900">
{notification.workCenter.code}
</p>
<p className="text-xs text-gray-600">
{notification.workCenter.name}
</p>
</div>
<div>
<span className="text-gray-500">Konum:</span>
<p className="font-medium text-gray-900 flex items-center">
<FaMapMarkerAlt className="w-3 h-3 mr-1" />
{notification.location}
</p>
</div>
<div>
<span className="text-gray-500">Bildiren:</span>
<p className="font-medium text-gray-900">
{notification.reportedBy}
</p>
</div>
<div>
<span className="text-gray-500">Süre:</span>
<p className="font-medium text-gray-900">
{notification.estimatedRepairTime
? `~${notification.estimatedRepairTime} dk`
: "-"}
</p>
</div>
</div>
{notification.assignedTo && (
<div className="bg-blue-50 rounded-lg p-3 mb-3">
<div className="flex items-center space-x-2 text-sm">
<FaUser className="w-4 h-4 text-blue-600" />
<span className="text-gray-600">Atanan:</span>
<span className="font-medium text-gray-900">
{notification.assignedTo}
</span>
</div>
</div>
)}
{notification.images && notification.images.length > 0 && (
<div className="flex items-center space-x-2 text-sm text-gray-500 mb-3">
<FaCamera className="w-4 h-4" />
<span>{notification.images.length} fotoğraf</span>
</div>
)}
{notification.resolutionNotes && (
<div className="bg-green-50 rounded-lg p-3 mb-3">
<div className="flex items-start space-x-2 text-sm">
<FaFileAlt className="w-4 h-4 text-green-600 mt-0.5" />
<div>
<span className="text-gray-600">Çözüm Notları:</span>
<p className="text-gray-900 mt-1">
{notification.resolutionNotes}
</p>
</div>
</div>
</div>
)}
<div className="flex items-center justify-between text-xs text-gray-500">
<div className="flex items-center space-x-2">
<FaClock className="w-3 h-3" />
<span>
Bildirilme: {getTimeAgo(notification.reportedAt)}
</span>
</div>
{notification.workOrderId && (
<div className="flex items-center space-x-2">
<span>İş Emri: {notification.workOrderId}</span>
</div>
)}
{notification.followUpRequired && (
<div className="flex items-center space-x-2 text-orange-600">
<FaExclamationTriangle className="w-3 h-3" />
<span>Takip Gerekli</span>
</div>
)}
</div>
</div>
</div>
<div className="flex space-x-1">
<button
onClick={() => handleView(notification)}
className="p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-md transition-colors"
>
<FaEye className="w-4 h-4" />
</button>
<button
onClick={() => handleEdit(notification)}
className="p-1.5 text-gray-400 hover:text-green-600 hover:bg-green-50 rounded-md transition-colors"
>
<FaEdit className="w-4 h-4" />
</button>
<button className="p-1.5 text-gray-400 hover:text-red-600 hover:bg-red-50 rounded-md transition-colors">
<FaTrash className="w-4 h-4" />
</button>
<button className="p-1.5 text-gray-400 hover:text-green-600 hover:bg-green-50 rounded-md transition-colors">
<FaPhone className="w-4 h-4" />
</button>
</div>
</div>
</div> </div>
))}
</div>
{filteredNotifications.length === 0 && (
<div className="text-center py-12">
<FaExclamationTriangle className="w-16 h-16 text-gray-400 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2">
Bildirim bulunamadı
</h3>
<p className="text-gray-500 mb-4">
Arama kriterlerinizi değiştirin veya yeni bir bildirim oluşturun.
</p>
<button <button
onClick={handleAddNotification} onClick={handleAddNotification}
className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700" className="bg-blue-600 text-white px-3 py-1.5 rounded-lg hover:bg-blue-700 flex items-center space-x-2 text-sm"
> >
Yeni Bildirim Oluştur <FaPlus className="w-4 h-4" />
<span>Yeni Bildirim</span>
</button> </button>
</div> </div>
)}
{/* Bulk Actions */} {/* Summary Cards */}
{selectedNotifications.length > 0 && ( <div className="grid grid-cols-1 md:grid-cols-5 gap-4">
<div className="fixed bottom-6 left-1/2 transform -translate-x-1/2 bg-white rounded-lg shadow-lg border border-gray-200 p-4"> <Widget
<div className="flex items-center space-x-4"> title="Toplam"
<span className="text-sm text-gray-600"> value={notifications.length}
{selectedNotifications.length} bildirim seçildi color="gray"
</span> icon="FaExclamationTriangle"
<div className="flex space-x-2"> />
<button
onClick={handleCreateWorkOrder} <Widget
className="bg-green-600 text-white px-3 py-2 rounded text-sm hover:bg-green-700" title="Açık"
> value={notifications.filter((n) => n.status === NotificationStatusEnum.Open).length}
İş Emri Oluştur color="red"
</button> icon="FaExclamationTriangle"
<button />
onClick={handleAssignNotifications}
className="bg-blue-600 text-white px-3 py-2 rounded text-sm hover:bg-blue-700" <Widget
> title="Devam Ediyor"
Atama Yap value={
</button> notifications.filter((n) => n.status === NotificationStatusEnum.InProgress).length
<button }
onClick={handleChangeStatus} color="orange"
className="bg-orange-600 text-white px-3 py-2 rounded text-sm hover:bg-orange-700" icon="FaClock"
> />
Durum Değiştir
</button> <Widget
<button title="Çözüldü"
onClick={() => setSelectedNotifications([])} value={notifications.filter((n) => n.status === NotificationStatusEnum.Resolved).length}
className="bg-gray-600 text-white px-3 py-2 rounded text-sm hover:bg-gray-700" color="green"
> icon="FaCheckCircle"
Temizle />
</button>
</div> <Widget
title="Acil"
value={notifications.filter((n) => n.priority === PriorityEnum.Urgent).length}
color="red"
icon="FaTimesCircle"
/>
</div>
{/* Filters */}
<div className="flex space-x-4">
<div className="flex-1 relative">
<FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5" />
<input
type="text"
placeholder="Bildirim ara..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-10 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<div className="relative">
<FaFilter className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5" />
<select
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value as NotificationStatusEnum | 'all')}
className="pl-10 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="all">Tüm Durumlar</option>
<option value={NotificationStatusEnum.Open}>ık</option>
<option value={NotificationStatusEnum.Assigned}>Atandı</option>
<option value={NotificationStatusEnum.InProgress}>Devam Ediyor</option>
<option value={NotificationStatusEnum.Resolved}>Çözüldü</option>
<option value={NotificationStatusEnum.Closed}>Kapatıldı</option>
</select>
</div>
<div className="relative">
<select
value={priorityFilter}
onChange={(e) => setPriorityFilter(e.target.value as PriorityEnum | 'all')}
className="pl-4 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="all">Tüm Öncelikler</option>
<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> </div>
)}
{/* Notifications List */}
<div className="space-y-3 pt-2">
{filteredNotifications.map((notification) => (
<div
key={notification.id}
className={`bg-white rounded-lg shadow-md border-l-4 p-4 hover:shadow-lg transition-shadow ${getCriticalityLevelColor(
notification.severity,
)}`}
>
<div className="flex items-start justify-between">
<div className="flex items-start space-x-4 flex-1">
<input
type="checkbox"
checked={selectedNotifications.includes(notification.id)}
onChange={() => handleSelectNotification(notification.id)}
className="mt-1 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<div className="flex-1">
<div className="flex items-center space-x-3 mb-2">
<h3 className="text-lg font-semibold text-gray-900">
{notification.notificationCode}
</h3>
<span
className={`px-2 py-1 rounded-full text-xs font-medium flex items-center space-x-1 ${getNotificationStatusColor(
notification.status,
)}`}
>
{getNotificationStatusIcon(notification.status)}
<span>{getNotificationStatusText(notification.status)}</span>
</span>
<span
className={`px-2 py-1 rounded-full text-xs font-medium ${getPriorityColor(
notification.priority,
)}`}
>
{getPriorityText(notification.priority)}
</span>
<span
className={`px-2 py-1 rounded-full text-xs font-medium ${getFaultTypeColor(
notification.faultType,
)}`}
>
{getFaultTypeText(notification.faultType)}
</span>
</div>
<h4 className="font-medium text-gray-800 mb-2">{notification.title}</h4>
<p className="text-sm text-gray-600 mb-3">
{notification.description.length > 150
? `${notification.description.substring(0, 150)}...`
: notification.description}
</p>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 text-sm mb-3">
<div>
<span className="text-gray-500">İş Merkezi:</span>
<p className="font-medium text-gray-900">{notification.workCenter.code}</p>
<p className="text-xs text-gray-600">{notification.workCenter.name}</p>
</div>
<div>
<span className="text-gray-500">Konum:</span>
<p className="font-medium text-gray-900 flex items-center">
<FaMapMarkerAlt className="w-3 h-3 mr-1" />
{notification.location}
</p>
</div>
<div>
<span className="text-gray-500">Bildiren:</span>
<p className="font-medium text-gray-900">{notification.reportedBy}</p>
</div>
<div>
<span className="text-gray-500">Süre:</span>
<p className="font-medium text-gray-900">
{notification.estimatedRepairTime
? `~${notification.estimatedRepairTime} dk`
: '-'}
</p>
</div>
</div>
{notification.assignedTo && (
<div className="bg-blue-50 rounded-lg p-3 mb-3">
<div className="flex items-center space-x-2 text-sm">
<FaUser className="w-4 h-4 text-blue-600" />
<span className="text-gray-600">Atanan:</span>
<span className="font-medium text-gray-900">
{notification.assignedTo}
</span>
</div>
</div>
)}
{notification.images && notification.images.length > 0 && (
<div className="flex items-center space-x-2 text-sm text-gray-500 mb-3">
<FaCamera className="w-4 h-4" />
<span>{notification.images.length} fotoğraf</span>
</div>
)}
{notification.resolutionNotes && (
<div className="bg-green-50 rounded-lg p-3 mb-3">
<div className="flex items-start space-x-2 text-sm">
<FaFileAlt className="w-4 h-4 text-green-600 mt-0.5" />
<div>
<span className="text-gray-600">Çözüm Notları:</span>
<p className="text-gray-900 mt-1">{notification.resolutionNotes}</p>
</div>
</div>
</div>
)}
<div className="flex items-center justify-between text-xs text-gray-500">
<div className="flex items-center space-x-2">
<FaClock className="w-3 h-3" />
<span>Bildirilme: {getTimeAgo(notification.reportedAt)}</span>
</div>
{notification.workOrderId && (
<div className="flex items-center space-x-2">
<span>İş Emri: {notification.workOrderId}</span>
</div>
)}
{notification.followUpRequired && (
<div className="flex items-center space-x-2 text-orange-600">
<FaExclamationTriangle className="w-3 h-3" />
<span>Takip Gerekli</span>
</div>
)}
</div>
</div>
</div>
<div className="flex space-x-1">
<button
onClick={() => handleView(notification)}
className="p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-md transition-colors"
>
<FaEye className="w-4 h-4" />
</button>
<button
onClick={() => handleEdit(notification)}
className="p-1.5 text-gray-400 hover:text-green-600 hover:bg-green-50 rounded-md transition-colors"
>
<FaEdit className="w-4 h-4" />
</button>
<button className="p-1.5 text-gray-400 hover:text-red-600 hover:bg-red-50 rounded-md transition-colors">
<FaTrash className="w-4 h-4" />
</button>
<button className="p-1.5 text-gray-400 hover:text-green-600 hover:bg-green-50 rounded-md transition-colors">
<FaPhone className="w-4 h-4" />
</button>
</div>
</div>
</div>
))}
</div>
{filteredNotifications.length === 0 && (
<div className="text-center py-12">
<FaExclamationTriangle className="w-16 h-16 text-gray-400 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2">Bildirim bulunamadı</h3>
<p className="text-gray-500 mb-4">
Arama kriterlerinizi değiştirin veya yeni bir bildirim oluşturun.
</p>
<button
onClick={handleAddNotification}
className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700"
>
Yeni Bildirim Oluştur
</button>
</div>
)}
{/* Bulk Actions */}
{selectedNotifications.length > 0 && (
<div className="fixed bottom-6 left-1/2 transform -translate-x-1/2 bg-white rounded-lg shadow-lg border border-gray-200 p-4">
<div className="flex items-center space-x-4">
<span className="text-sm text-gray-600">
{selectedNotifications.length} bildirim seçildi
</span>
<div className="flex space-x-2">
<button
onClick={handleCreateWorkOrder}
className="bg-green-600 text-white px-3 py-2 rounded text-sm hover:bg-green-700"
>
İş Emri Oluştur
</button>
<button
onClick={handleAssignNotifications}
className="bg-blue-600 text-white px-3 py-2 rounded text-sm hover:bg-blue-700"
>
Atama Yap
</button>
<button
onClick={handleChangeStatus}
className="bg-orange-600 text-white px-3 py-2 rounded text-sm hover:bg-orange-700"
>
Durum Değiştir
</button>
<button
onClick={() => setSelectedNotifications([])}
className="bg-gray-600 text-white px-3 py-2 rounded text-sm hover:bg-gray-700"
>
Temizle
</button>
</div>
</div>
</div>
)}
</div>
{/* Modals */} {/* Modals */}
{showModal && !editingNotification && ( {showModal && !editingNotification && (
@ -565,8 +501,8 @@ const FaultNotifications: React.FC = () => {
<EditFaultNotificationModal <EditFaultNotificationModal
isOpen={showModal} isOpen={showModal}
onClose={() => { onClose={() => {
setShowModal(false); setShowModal(false)
setEditingNotification(null); setEditingNotification(null)
}} }}
onSave={handleSaveNotification} onSave={handleSaveNotification}
notification={editingNotification} notification={editingNotification}
@ -578,9 +514,9 @@ const FaultNotifications: React.FC = () => {
isOpen={!!viewingNotification} isOpen={!!viewingNotification}
onClose={() => setViewingNotification(null)} onClose={() => setViewingNotification(null)}
onEdit={(notification) => { onEdit={(notification) => {
setViewingNotification(null); setViewingNotification(null)
setEditingNotification(notification); setEditingNotification(notification)
setShowModal(true); setShowModal(true)
}} }}
notification={viewingNotification} notification={viewingNotification}
/> />
@ -591,9 +527,7 @@ const FaultNotifications: React.FC = () => {
isOpen={showCreateWorkOrderModal} isOpen={showCreateWorkOrderModal}
onClose={() => setShowCreateWorkOrderModal(false)} onClose={() => setShowCreateWorkOrderModal(false)}
onSave={handleWorkOrderSave} onSave={handleWorkOrderSave}
notifications={notifications.filter((n) => notifications={notifications.filter((n) => selectedNotifications.includes(n.id))}
selectedNotifications.includes(n.id)
)}
/> />
)} )}
@ -602,9 +536,7 @@ const FaultNotifications: React.FC = () => {
isOpen={showAssignModal} isOpen={showAssignModal}
onClose={() => setShowAssignModal(false)} onClose={() => setShowAssignModal(false)}
onSave={handleAssignmentSave} onSave={handleAssignmentSave}
notifications={notifications.filter((n) => notifications={notifications.filter((n) => selectedNotifications.includes(n.id))}
selectedNotifications.includes(n.id)
)}
/> />
)} )}
@ -613,13 +545,11 @@ const FaultNotifications: React.FC = () => {
isOpen={showStatusChangeModal} isOpen={showStatusChangeModal}
onClose={() => setShowStatusChangeModal(false)} onClose={() => setShowStatusChangeModal(false)}
onSave={handleStatusChangeSave} onSave={handleStatusChangeSave}
notifications={notifications.filter((n) => notifications={notifications.filter((n) => selectedNotifications.includes(n.id))}
selectedNotifications.includes(n.id)
)}
/> />
)} )}
</div> </Container>
); )
}; }
export default FaultNotifications; export default FaultNotifications

View file

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { import {
FaCalendar, FaCalendar,
FaClock, FaClock,
@ -8,124 +8,109 @@ import {
FaChevronRight, FaChevronRight,
FaEdit, FaEdit,
FaUser, FaUser,
} from "react-icons/fa"; } from 'react-icons/fa'
import { import { WorkOrderStatusEnum, CalendarView, PmCalendarEvent } from '../../../types/pm'
WorkOrderStatusEnum, import { mockCalendarEvents } from '../../../mocks/mockMaintenanceCalendarEvent'
CalendarView, import NewCalendarEventModal from './NewCalendarEventModal'
PmCalendarEvent,
} from "../../../types/pm";
import { mockCalendarEvents } from "../../../mocks/mockMaintenanceCalendarEvent";
import NewCalendarEventModal from "./NewCalendarEventModal";
import { import {
getPriorityColor, getPriorityColor,
getWorkOrderStatusColor, getWorkOrderStatusColor,
getWorkOrderStatusIcon, getWorkOrderStatusIcon,
} from "../../../utils/erp"; } from '../../../utils/erp'
import { Container } from '@/components/shared'
const MaintenanceCalendar: React.FC = () => { const MaintenanceCalendar: React.FC = () => {
const [currentDate, setCurrentDate] = useState(new Date()); const [currentDate, setCurrentDate] = useState(new Date())
const [view, setView] = useState<CalendarView>("month"); const [view, setView] = useState<CalendarView>('month')
const [showEventDetailModal, setShowEventDetailModal] = useState(false); const [showEventDetailModal, setShowEventDetailModal] = useState(false)
const [showNewEventModal, setShowNewEventModal] = useState(false); const [showNewEventModal, setShowNewEventModal] = useState(false)
const [selectedEvent, setSelectedEvent] = useState<PmCalendarEvent | null>( const [selectedEvent, setSelectedEvent] = useState<PmCalendarEvent | null>(null)
null const [selectedDate, setSelectedDate] = useState<Date | null>(null)
); const [statusFilter, setStatusFilter] = useState<'all' | WorkOrderStatusEnum>('all')
const [selectedDate, setSelectedDate] = useState<Date | null>(null);
const [statusFilter, setStatusFilter] = useState<"all" | WorkOrderStatusEnum>(
"all"
);
// Mock data - replace with actual API calls // Mock data - replace with actual API calls
const [events, setEvents] = useState<PmCalendarEvent[]>(mockCalendarEvents); const [events, setEvents] = useState<PmCalendarEvent[]>(mockCalendarEvents)
const getDaysInMonth = (date: Date) => { const getDaysInMonth = (date: Date) => {
return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate(); return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate()
}; }
const getFirstDayOfMonth = (date: Date) => { const getFirstDayOfMonth = (date: Date) => {
return new Date(date.getFullYear(), date.getMonth(), 1).getDay(); return new Date(date.getFullYear(), date.getMonth(), 1).getDay()
}; }
const formatDate = (date: Date) => { const formatDate = (date: Date) => {
return date.toLocaleDateString("tr-TR", { return date.toLocaleDateString('tr-TR', {
year: "numeric", year: 'numeric',
month: "long", month: 'long',
}); })
}; }
const getEventsForDate = (date: Date) => { const getEventsForDate = (date: Date) => {
return events.filter((event) => { return events.filter((event) => {
const eventDate = new Date(event.date); const eventDate = new Date(event.date)
return eventDate.toDateString() === date.toDateString(); return eventDate.toDateString() === date.toDateString()
}); })
}; }
const navigateMonth = (direction: "prev" | "next") => { const navigateMonth = (direction: 'prev' | 'next') => {
const newDate = new Date(currentDate); const newDate = new Date(currentDate)
if (direction === "prev") { if (direction === 'prev') {
newDate.setMonth(newDate.getMonth() - 1); newDate.setMonth(newDate.getMonth() - 1)
} else { } else {
newDate.setMonth(newDate.getMonth() + 1); newDate.setMonth(newDate.getMonth() + 1)
} }
setCurrentDate(newDate); setCurrentDate(newDate)
}; }
const handleEventClick = (event: PmCalendarEvent) => { const handleEventClick = (event: PmCalendarEvent) => {
setSelectedEvent(event); setSelectedEvent(event)
setShowEventDetailModal(true); setShowEventDetailModal(true)
}; }
const handleDayClick = (date: Date) => { const handleDayClick = (date: Date) => {
setSelectedDate(date); setSelectedDate(date)
setShowNewEventModal(true); setShowNewEventModal(true)
}; }
const handleNewEventSave = (newEvent: Partial<PmCalendarEvent>) => { const handleNewEventSave = (newEvent: Partial<PmCalendarEvent>) => {
if (newEvent.id) { if (newEvent.id) {
setEvents((prevEvents) => [...prevEvents, newEvent as PmCalendarEvent]); setEvents((prevEvents) => [...prevEvents, newEvent as PmCalendarEvent])
} }
setShowNewEventModal(false); setShowNewEventModal(false)
setSelectedDate(null); setSelectedDate(null)
}; }
const renderMonthView = () => { const renderMonthView = () => {
const daysInMonth = getDaysInMonth(currentDate); const daysInMonth = getDaysInMonth(currentDate)
const firstDay = getFirstDayOfMonth(currentDate); const firstDay = getFirstDayOfMonth(currentDate)
const days = []; const days = []
// Empty cells for days before the first day of the month // Empty cells for days before the first day of the month
for (let i = 0; i < firstDay; i++) { for (let i = 0; i < firstDay; i++) {
days.push( days.push(<div key={`empty-${i}`} className="p-1 border border-gray-200"></div>)
<div key={`empty-${i}`} className="p-1 border border-gray-200"></div>
);
} }
// Days of the month // Days of the month
for (let day = 1; day <= daysInMonth; day++) { for (let day = 1; day <= daysInMonth; day++) {
const date = new Date( const date = new Date(currentDate.getFullYear(), currentDate.getMonth(), day)
currentDate.getFullYear(), const dayEvents = getEventsForDate(date)
currentDate.getMonth(),
day
);
const dayEvents = getEventsForDate(date);
const filteredDayEvents = dayEvents.filter( const filteredDayEvents = dayEvents.filter(
(event) => statusFilter === "all" || event.status === statusFilter (event) => statusFilter === 'all' || event.status === statusFilter,
); )
const isToday = date.toDateString() === new Date().toDateString(); const isToday = date.toDateString() === new Date().toDateString()
days.push( days.push(
<div <div
key={day} key={day}
className={`p-1.5 border border-gray-200 min-h-[100px] cursor-pointer hover:bg-gray-50 ${ className={`p-1.5 border border-gray-200 min-h-[100px] cursor-pointer hover:bg-gray-50 ${
isToday ? "bg-blue-50" : "bg-white" isToday ? 'bg-blue-50' : 'bg-white'
}`} }`}
onClick={() => handleDayClick(date)} onClick={() => handleDayClick(date)}
> >
<div <div
className={`text-xs font-medium mb-1 ${ className={`text-xs font-medium mb-1 ${isToday ? 'text-blue-600' : 'text-gray-900'}`}
isToday ? "text-blue-600" : "text-gray-900"
}`}
> >
{day} {day}
</div> </div>
@ -134,11 +119,11 @@ const MaintenanceCalendar: React.FC = () => {
<div <div
key={event.id} key={event.id}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation()
handleEventClick(event); handleEventClick(event)
}} }}
className={`text-xs p-0.5 rounded border-l-2 cursor-pointer hover:bg-gray-50 ${getPriorityColor( className={`text-xs p-0.5 rounded border-l-2 cursor-pointer hover:bg-gray-50 ${getPriorityColor(
event.priority event.priority,
)} ${getWorkOrderStatusColor(event.status)}`} )} ${getWorkOrderStatusColor(event.status)}`}
> >
<div className="font-medium truncate">{event.title}</div> <div className="font-medium truncate">{event.title}</div>
@ -146,9 +131,7 @@ const MaintenanceCalendar: React.FC = () => {
{getWorkOrderStatusIcon(event.status)} {getWorkOrderStatusIcon(event.status)}
<span>{event.startTime}</span> <span>{event.startTime}</span>
{event.workCenterCode && ( {event.workCenterCode && (
<span className="text-gray-500"> <span className="text-gray-500">({event.workCenterCode})</span>
({event.workCenterCode})
</span>
)} )}
</div> </div>
</div> </div>
@ -159,14 +142,14 @@ const MaintenanceCalendar: React.FC = () => {
</div> </div>
)} )}
</div> </div>
</div> </div>,
); )
} }
return ( return (
<div className="grid grid-cols-7 gap-0 bg-white rounded-lg shadow overflow-hidden"> <div className="grid grid-cols-7 gap-0 bg-white rounded-lg shadow overflow-hidden">
{/* Header */} {/* Header */}
{["Pzt", "Sal", "Çar", "Per", "Cum", "Cmt", "Paz"].map((day) => ( {['Pzt', 'Sal', 'Çar', 'Per', 'Cum', 'Cmt', 'Paz'].map((day) => (
<div <div
key={day} key={day}
className="p-2 bg-gray-50 text-center text-xs font-medium text-gray-700 border-r border-gray-200 last:border-r-0" className="p-2 bg-gray-50 text-center text-xs font-medium text-gray-700 border-r border-gray-200 last:border-r-0"
@ -176,261 +159,233 @@ const MaintenanceCalendar: React.FC = () => {
))} ))}
{days} {days}
</div> </div>
); )
}; }
const renderWeekView = () => { const renderWeekView = () => {
const startOfWeek = new Date(currentDate); const startOfWeek = new Date(currentDate)
startOfWeek.setDate(currentDate.getDate() - currentDate.getDay() + 1); // Start from Monday startOfWeek.setDate(currentDate.getDate() - currentDate.getDay() + 1) // Start from Monday
const weekDays: Date[] = []; const weekDays: Date[] = []
for (let i = 0; i < 7; i++) { for (let i = 0; i < 7; i++) {
const date = new Date(startOfWeek); const date = new Date(startOfWeek)
date.setDate(startOfWeek.getDate() + i); date.setDate(startOfWeek.getDate() + i)
weekDays.push(date); weekDays.push(date)
} }
return ( return (
<div className="bg-white rounded-lg shadow overflow-hidden"> <div className="bg-white rounded-lg shadow overflow-hidden">
<div className="grid grid-cols-8 border-b border-gray-200"> <div className="grid grid-cols-8 border-b border-gray-200">
<div className="p-2 bg-gray-50 text-xs font-medium text-gray-700"> <div className="p-2 bg-gray-50 text-xs font-medium text-gray-700">Saat</div>
Saat
</div>
{weekDays.map((date, index) => ( {weekDays.map((date, index) => (
<div <div key={index} className="p-2 bg-gray-50 text-center border-l border-gray-200">
key={index}
className="p-2 bg-gray-50 text-center border-l border-gray-200"
>
<div className="text-sm font-medium text-gray-700"> <div className="text-sm font-medium text-gray-700">
{date.toLocaleDateString("tr-TR", { weekday: "short" })} {date.toLocaleDateString('tr-TR', { weekday: 'short' })}
</div>
<div className="text-lg font-bold text-gray-900">
{date.getDate()}
</div> </div>
<div className="text-lg font-bold text-gray-900">{date.getDate()}</div>
</div> </div>
))} ))}
</div> </div>
<div className="max-h-96 overflow-y-auto"> <div className="max-h-96 overflow-y-auto">
{Array.from({ length: 12 }, (_, hour) => hour + 8).map((hour) => ( {Array.from({ length: 12 }, (_, hour) => hour + 8).map((hour) => (
<div <div key={hour} className="grid grid-cols-8 border-b border-gray-100">
key={hour}
className="grid grid-cols-8 border-b border-gray-100"
>
<div className="p-1.5 text-xs text-gray-500 bg-gray-50 border-r border-gray-200"> <div className="p-1.5 text-xs text-gray-500 bg-gray-50 border-r border-gray-200">
{hour}:00 {hour}:00
</div> </div>
{weekDays.map((date, dayIndex) => { {weekDays.map((date, dayIndex) => {
const dayEvents = getEventsForDate(date).filter((event) => { const dayEvents = getEventsForDate(date).filter((event) => {
const eventHour = parseInt( const eventHour = parseInt(event.startTime?.split(':')[0] || '0')
event.startTime?.split(":")[0] || "0"
);
return ( return (
eventHour === hour && eventHour === hour && (statusFilter === 'all' || event.status === statusFilter)
(statusFilter === "all" || event.status === statusFilter) )
); })
});
return ( return (
<div <div
key={dayIndex} key={dayIndex}
className="p-1 border-l border-gray-200 min-h-[50px] cursor-pointer hover:bg-gray-50" className="p-1 border-l border-gray-200 min-h-[50px] cursor-pointer hover:bg-gray-50"
onClick={() => { onClick={() => {
const selectedDateTime = new Date(date); const selectedDateTime = new Date(date)
selectedDateTime.setHours(hour, 0, 0, 0); selectedDateTime.setHours(hour, 0, 0, 0)
handleDayClick(selectedDateTime); handleDayClick(selectedDateTime)
}} }}
> >
{dayEvents.map((event) => ( {dayEvents.map((event) => (
<div <div
key={event.id} key={event.id}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation()
handleEventClick(event); handleEventClick(event)
}} }}
className={`text-xs p-1 rounded mb-1 border-l-2 cursor-pointer hover:bg-gray-50 ${getPriorityColor( className={`text-xs p-1 rounded mb-1 border-l-2 cursor-pointer hover:bg-gray-50 ${getPriorityColor(
event.priority event.priority,
)} ${getWorkOrderStatusColor(event.status)}`} )} ${getWorkOrderStatusColor(event.status)}`}
> >
<div className="font-medium truncate"> <div className="font-medium truncate">{event.title}</div>
{event.title}
</div>
<div className="text-gray-500"> <div className="text-gray-500">
{event.startTime}-{event.endTime} {event.startTime}-{event.endTime}
</div> </div>
</div> </div>
))} ))}
</div> </div>
); )
})} })}
</div> </div>
))} ))}
</div> </div>
</div> </div>
); )
}; }
const getTodayEvents = () => { const getTodayEvents = () => {
const today = new Date(); const today = new Date()
return getEventsForDate(today).filter( return getEventsForDate(today).filter(
(event) => statusFilter === "all" || event.status === statusFilter (event) => statusFilter === 'all' || event.status === statusFilter,
); )
}; }
return ( return (
<div className="space-y-4 pt-2"> <Container>
{/* Header */} <div className="space-y-2">
<div className="flex items-center justify-between"> {/* Header */}
<div> <div className="flex items-center justify-between">
<h2 className="text-2xl font-bold text-gray-900">Bakım Takvimi</h2> <div>
<p className="text-gray-600"> <h2 className="text-2xl font-bold text-gray-900">Bakım Takvimi</h2>
Bakım planları ve emirlerini takip edin. Yeni planlama için <p className="text-gray-600">
gün/saat seçin. Bakım planları ve emirlerini takip edin. Yeni planlama için gün/saat seçin.
</p> </p>
</div>
<button
onClick={() => setShowNewEventModal(true)}
className="bg-blue-600 text-white px-3 py-1.5 rounded-lg hover:bg-blue-700 flex items-center space-x-2 text-sm"
>
<FaPlus className="w-4 h-4" />
<span>Yeni Planlama</span>
</button>
</div>
{/* Calendar Controls */}
<div className="flex items-center justify-between">
<div className="flex items-center space-x-4">
<div className="flex items-center space-x-1">
<button
onClick={() => navigateMonth("prev")}
className="p-1.5 hover:bg-gray-100 rounded-md"
>
<FaChevronLeft className="w-4 h-4" />
</button>
<h3 className="text-base font-semibold text-gray-900 min-w-[180px] text-center">
{formatDate(currentDate)}
</h3>
<button
onClick={() => navigateMonth("next")}
className="p-1.5 hover:bg-gray-100 rounded-md"
>
<FaChevronRight className="w-4 h-4" />
</button>
</div>
<div className="flex space-x-1 bg-gray-100 rounded-lg p-1">
{(["month", "week"] as CalendarView[]).map((viewType) => (
<button
key={viewType}
onClick={() => setView(viewType)}
className={`px-3 py-1 rounded-md text-sm font-medium transition-colors ${
view === viewType
? "bg-white text-gray-900 shadow-sm"
: "text-gray-600 hover:text-gray-900"
}`}
>
{viewType === "month" ? "Ay" : "Hafta"}
</button>
))}
</div>
</div>
<div className="flex items-center space-x-3">
<div className="relative">
<FaFilter className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
<select
value={statusFilter}
onChange={(e) =>
setStatusFilter(e.target.value as "all" | WorkOrderStatusEnum)
}
className="pl-9 pr-4 py-1.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm"
>
<option value="all">Tüm Durumlar</option>
<option value="scheduled">Planlanmış</option>
<option value={WorkOrderStatusEnum.Created}>Oluşturuldu</option>
<option value={WorkOrderStatusEnum.InProgress}>
Devam Ediyor
</option>
<option value={WorkOrderStatusEnum.Completed}>Tamamlandı</option>
</select>
</div> </div>
<button <button
onClick={() => setCurrentDate(new Date())} onClick={() => setShowNewEventModal(true)}
className="px-3 py-1.5 text-sm text-blue-600 hover:bg-blue-50 rounded-lg" className="bg-blue-600 text-white px-3 py-1.5 rounded-lg hover:bg-blue-700 flex items-center space-x-2 text-sm"
> >
Bugün <FaPlus className="w-4 h-4" />
<span>Yeni Planlama</span>
</button> </button>
</div> </div>
</div>
{/* Calendar View */} {/* Calendar Controls */}
<div className="grid grid-cols-1 lg:grid-cols-4 gap-4"> <div className="flex items-center justify-between">
<div className="lg:col-span-3"> <div className="flex items-center space-x-4">
{view === "month" && renderMonthView()} <div className="flex items-center space-x-1">
{view === "week" && renderWeekView()} <button
onClick={() => navigateMonth('prev')}
className="p-1.5 hover:bg-gray-100 rounded-md"
>
<FaChevronLeft className="w-4 h-4" />
</button>
<h3 className="text-base font-semibold text-gray-900 min-w-[180px] text-center">
{formatDate(currentDate)}
</h3>
<button
onClick={() => navigateMonth('next')}
className="p-1.5 hover:bg-gray-100 rounded-md"
>
<FaChevronRight className="w-4 h-4" />
</button>
</div>
<div className="flex space-x-1 bg-gray-100 rounded-lg p-1">
{(['month', 'week'] as CalendarView[]).map((viewType) => (
<button
key={viewType}
onClick={() => setView(viewType)}
className={`px-3 py-1 rounded-md text-sm font-medium transition-colors ${
view === viewType
? 'bg-white text-gray-900 shadow-sm'
: 'text-gray-600 hover:text-gray-900'
}`}
>
{viewType === 'month' ? 'Ay' : 'Hafta'}
</button>
))}
</div>
</div>
<div className="flex items-center space-x-3">
<div className="relative">
<FaFilter className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
<select
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value as 'all' | WorkOrderStatusEnum)}
className="pl-9 pr-4 py-1.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-sm"
>
<option value="all">Tüm Durumlar</option>
<option value="scheduled">Planlanmış</option>
<option value={WorkOrderStatusEnum.Created}>Oluşturuldu</option>
<option value={WorkOrderStatusEnum.InProgress}>Devam Ediyor</option>
<option value={WorkOrderStatusEnum.Completed}>Tamamlandı</option>
</select>
</div>
<button
onClick={() => setCurrentDate(new Date())}
className="px-3 py-1.5 text-sm text-blue-600 hover:bg-blue-50 rounded-lg"
>
Bugün
</button>
</div>
</div> </div>
{/* Today's Events Sidebar */} {/* Calendar View */}
<div className="bg-white rounded-lg shadow p-4"> <div className="grid grid-cols-1 lg:grid-cols-4 gap-4">
<h4 className="text-base font-semibold text-gray-900 mb-3"> <div className="lg:col-span-3">
Bugünün Etkinlikleri {view === 'month' && renderMonthView()}
</h4> {view === 'week' && renderWeekView()}
<div className="space-y-3"> </div>
{getTodayEvents().map((event) => (
<div {/* Today's Events Sidebar */}
key={event.id} <div className="bg-white rounded-lg shadow p-4">
onClick={() => handleEventClick(event)} <h4 className="text-base font-semibold text-gray-900 mb-3">Bugünün Etkinlikleri</h4>
className={`p-2 border-l-4 rounded-r-lg cursor-pointer hover:bg-gray-50 ${getPriorityColor( <div className="space-y-3">
event.priority {getTodayEvents().map((event) => (
)}`} <div
> key={event.id}
<div className="flex items-start justify-between"> onClick={() => handleEventClick(event)}
<div className="flex-1"> className={`p-2 border-l-4 rounded-r-lg cursor-pointer hover:bg-gray-50 ${getPriorityColor(
<h5 className="text-sm font-medium text-gray-900"> event.priority,
{event.title} )}`}
</h5> >
<p className="text-xs text-gray-500 mt-1"> <div className="flex items-start justify-between">
{event.workCenterCode} <div className="flex-1">
</p> <h5 className="text-sm font-medium text-gray-900">{event.title}</h5>
<div className="flex items-center space-x-2 mt-2"> <p className="text-xs text-gray-500 mt-1">{event.workCenterCode}</p>
<FaClock className="w-3 h-3 text-gray-400" /> <div className="flex items-center space-x-2 mt-2">
<span className="text-xs text-gray-500"> <FaClock className="w-3 h-3 text-gray-400" />
{event.startTime} - {event.endTime}
</span>
</div>
{event.assignedTo && (
<div className="flex items-center space-x-2 mt-1">
<FaUser className="w-3 h-3 text-gray-400" />
<span className="text-xs text-gray-500"> <span className="text-xs text-gray-500">
{event.assignedTo} {event.startTime} - {event.endTime}
</span> </span>
</div> </div>
)} {event.assignedTo && (
<div className="flex items-center space-x-2 mt-1">
<FaUser className="w-3 h-3 text-gray-400" />
<span className="text-xs text-gray-500">{event.assignedTo}</span>
</div>
)}
</div>
<span
className={`px-2 py-1 text-xs font-semibold rounded-full ${getWorkOrderStatusColor(
event.status,
)}`}
>
{event.status === WorkOrderStatusEnum.Planned
? 'Planlandı'
: event.status === WorkOrderStatusEnum.InProgress
? 'Devam Ediyor'
: event.status === WorkOrderStatusEnum.Completed
? 'Tamamlandı'
: 'Bekliyor'}
</span>
</div> </div>
<span
className={`px-2 py-1 text-xs font-semibold rounded-full ${getWorkOrderStatusColor(
event.status
)}`}
>
{event.status === WorkOrderStatusEnum.Planned
? "Planlandı"
: event.status === WorkOrderStatusEnum.InProgress
? "Devam Ediyor"
: event.status === WorkOrderStatusEnum.Completed
? "Tamamlandı"
: "Bekliyor"}
</span>
</div> </div>
</div> ))}
))} {getTodayEvents().length === 0 && (
{getTodayEvents().length === 0 && ( <div className="text-center py-8">
<div className="text-center py-8"> <FaCalendar className="w-10 h-10 text-gray-400 mx-auto mb-2" />
<FaCalendar className="w-10 h-10 text-gray-400 mx-auto mb-2" /> <p className="text-sm text-gray-600">Bugün için planlanan etkinlik yok</p>
<p className="text-sm text-gray-600"> </div>
Bugün için planlanan etkinlik yok )}
</p> </div>
</div>
)}
</div> </div>
</div> </div>
</div> </div>
@ -441,12 +396,8 @@ const MaintenanceCalendar: React.FC = () => {
<div className="bg-white rounded-lg p-4 w-full max-w-lg mx-4"> <div className="bg-white rounded-lg p-4 w-full max-w-lg mx-4">
<div className="flex items-start justify-between mb-3"> <div className="flex items-start justify-between mb-3">
<div> <div>
<h3 className="text-base font-semibold text-gray-900"> <h3 className="text-base font-semibold text-gray-900">{selectedEvent.title}</h3>
{selectedEvent.title} <p className="text-sm text-gray-500 mt-1">{selectedEvent.workCenterCode}</p>
</h3>
<p className="text-sm text-gray-500 mt-1">
{selectedEvent.workCenterCode}
</p>
</div> </div>
<button <button
onClick={() => setShowEventDetailModal(false)} onClick={() => setShowEventDetailModal(false)}
@ -458,46 +409,34 @@ const MaintenanceCalendar: React.FC = () => {
<div className="grid grid-cols-2 gap-4 mb-4"> <div className="grid grid-cols-2 gap-4 mb-4">
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">Tarih & Saat</label>
Tarih & Saat
</label>
<p className="text-sm text-gray-900"> <p className="text-sm text-gray-900">
{selectedEvent.date.toLocaleDateString("tr-TR")} -{" "} {selectedEvent.date.toLocaleDateString('tr-TR')} - {selectedEvent.startTime} /{' '}
{selectedEvent.startTime} / {selectedEvent.endTime} {selectedEvent.endTime}
</p> </p>
</div> </div>
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">Süre</label>
Süre <p className="text-sm text-gray-900">{selectedEvent.duration} dakika</p>
</label>
<p className="text-sm text-gray-900">
{selectedEvent.duration} dakika
</p>
</div> </div>
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">Atanan Kişi</label>
Atanan Kişi <p className="text-sm text-gray-900">{selectedEvent.assignedTo || 'Atanmadı'}</p>
</label>
<p className="text-sm text-gray-900">
{selectedEvent.assignedTo || "Atanmadı"}
</p>
</div> </div>
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">Durum</label>
Durum
</label>
<span <span
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${getWorkOrderStatusColor( className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${getWorkOrderStatusColor(
selectedEvent.status selectedEvent.status,
)}`} )}`}
> >
{selectedEvent.status === WorkOrderStatusEnum.Planned {selectedEvent.status === WorkOrderStatusEnum.Planned
? "Planlandı" ? 'Planlandı'
: selectedEvent.status === WorkOrderStatusEnum.InProgress : selectedEvent.status === WorkOrderStatusEnum.InProgress
? "Devam Ediyor" ? 'Devam Ediyor'
: selectedEvent.status === WorkOrderStatusEnum.Completed : selectedEvent.status === WorkOrderStatusEnum.Completed
? "Tamamlandı" ? 'Tamamlandı'
: "Bekliyor"} : 'Bekliyor'}
</span> </span>
</div> </div>
</div> </div>
@ -522,14 +461,14 @@ const MaintenanceCalendar: React.FC = () => {
<NewCalendarEventModal <NewCalendarEventModal
isOpen={showNewEventModal} isOpen={showNewEventModal}
onClose={() => { onClose={() => {
setShowNewEventModal(false); setShowNewEventModal(false)
setSelectedDate(null); setSelectedDate(null)
}} }}
onSave={handleNewEventSave} onSave={handleNewEventSave}
selectedDate={selectedDate || undefined} selectedDate={selectedDate || undefined}
/> />
</div> </Container>
); )
}; }
export default MaintenanceCalendar; export default MaintenanceCalendar

View file

@ -1,18 +1,18 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaSave, FaPlus } from "react-icons/fa"; import { FaTimes, FaSave, FaPlus } from 'react-icons/fa'
import { import {
PmWorkCenter, PmWorkCenter,
MaintenancePlanTypeEnum, MaintenancePlanTypeEnum,
FrequencyUnitEnum, FrequencyUnitEnum,
PmMaintenancePlan, PmMaintenancePlan,
} from "../../../types/pm"; } from '../../../types/pm'
import { PriorityEnum } from "../../../types/common"; import { PriorityEnum } from '../../../types/common'
interface MaintenancePlanModalProps { interface MaintenancePlanModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (planData: PmMaintenancePlan[]) => void; onSave: (planData: PmMaintenancePlan[]) => void
selectedWorkCenters: PmWorkCenter[]; selectedWorkCenters: PmWorkCenter[]
} }
const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
@ -23,55 +23,46 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
}) => { }) => {
const [planData, setPlanData] = useState({ const [planData, setPlanData] = useState({
planType: MaintenancePlanTypeEnum.Preventive, planType: MaintenancePlanTypeEnum.Preventive,
description: "", description: '',
frequency: 1, frequency: 1,
frequencyUnit: FrequencyUnitEnum.Months, frequencyUnit: FrequencyUnitEnum.Months,
estimatedDuration: 60, estimatedDuration: 60,
priority: PriorityEnum.Normal, priority: PriorityEnum.Normal,
instructions: "", instructions: '',
requiredSkills: [] as string[], requiredSkills: [] as string[],
nextDue: new Date(), nextDue: new Date(),
}); })
const [newSkill, setNewSkill] = useState(""); const [newSkill, setNewSkill] = useState('')
if (!isOpen) return null; if (!isOpen) return null
const handleInputChange = ( const handleInputChange = (
e: React.ChangeEvent< e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>,
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
>
) => { ) => {
const { name, value, type } = e.target; const { name, value, type } = e.target
setPlanData((prev) => ({ setPlanData((prev) => ({
...prev, ...prev,
[name]: [name]: type === 'date' ? new Date(value) : type === 'number' ? Number(value) : value,
type === "date" }))
? new Date(value) }
: type === "number"
? Number(value)
: value,
}));
};
const addSkill = () => { const addSkill = () => {
if (newSkill.trim() && !planData.requiredSkills.includes(newSkill.trim())) { if (newSkill.trim() && !planData.requiredSkills.includes(newSkill.trim())) {
setPlanData((prev) => ({ setPlanData((prev) => ({
...prev, ...prev,
requiredSkills: [...prev.requiredSkills, newSkill.trim()], requiredSkills: [...prev.requiredSkills, newSkill.trim()],
})); }))
setNewSkill(""); setNewSkill('')
} }
}; }
const removeSkill = (skillToRemove: string) => { const removeSkill = (skillToRemove: string) => {
setPlanData((prev) => ({ setPlanData((prev) => ({
...prev, ...prev,
requiredSkills: prev.requiredSkills.filter( requiredSkills: prev.requiredSkills.filter((skill) => skill !== skillToRemove),
(skill) => skill !== skillToRemove }))
), }
}));
};
const handleSave = () => { const handleSave = () => {
const plansToCreate = selectedWorkCenters.map((workCenter) => ({ const plansToCreate = selectedWorkCenters.map((workCenter) => ({
@ -84,11 +75,11 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
isActive: true, isActive: true,
creationTime: new Date(), creationTime: new Date(),
lastModificationTime: new Date(), lastModificationTime: new Date(),
})); }))
onSave(plansToCreate); onSave(plansToCreate)
onClose(); onClose()
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -98,10 +89,7 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">
Bakım Planı Oluştur ({selectedWorkCenters.length} merkezi) Bakım Planı Oluştur ({selectedWorkCenters.length} merkezi)
</h2> </h2>
<button <button onClick={onClose} className="p-2 hover:bg-gray-100 rounded-lg transition-colors">
onClick={onClose}
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
>
<FaTimes className="w-5 h-5 text-gray-500" /> <FaTimes className="w-5 h-5 text-gray-500" />
</button> </button>
</div> </div>
@ -110,21 +98,14 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
<div className="p-4 space-y-4"> <div className="p-4 space-y-4">
{/* Selected Work Center List */} {/* Selected Work Center List */}
<div> <div>
<h3 className="text-sm font-medium text-gray-900 mb-2"> <h3 className="text-sm font-medium text-gray-900 mb-2">Seçili İş Merkezleri</h3>
Seçili İş Merkezleri
</h3>
<div className="max-h-28 overflow-y-auto bg-gray-50 rounded-lg p-2"> <div className="max-h-28 overflow-y-auto bg-gray-50 rounded-lg p-2">
{selectedWorkCenters.map((workCenter) => ( {selectedWorkCenters.map((workCenter) => (
<div <div key={workCenter.id} className="flex items-center justify-between py-0.5">
key={workCenter.id}
className="flex items-center justify-between py-0.5"
>
<span className="text-sm text-gray-700"> <span className="text-sm text-gray-700">
{workCenter.code} - {workCenter.name} {workCenter.code} - {workCenter.name}
</span> </span>
<span className="text-xs text-gray-500"> <span className="text-xs text-gray-500">{workCenter.location}</span>
{workCenter.location}
</span>
</div> </div>
))} ))}
</div> </div>
@ -132,38 +113,24 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
{/* Plan Details */} {/* Plan Details */}
<div> <div>
<h3 className="text-sm font-medium text-gray-900 mb-2"> <h3 className="text-sm font-medium text-gray-900 mb-2">Plan Detayları</h3>
Plan Detayları
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Plan Tipi</label>
Plan Tipi
</label>
<select <select
name="planType" name="planType"
value={planData.planType} value={planData.planType}
onChange={handleInputChange} 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" 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={MaintenancePlanTypeEnum.Preventive}> <option value={MaintenancePlanTypeEnum.Preventive}>Önleyici Bakım</option>
Önleyici Bakım <option value={MaintenancePlanTypeEnum.Predictive}>Kestirimci Bakım</option>
</option> <option value={MaintenancePlanTypeEnum.Corrective}>Düzeltici Bakım</option>
<option value={MaintenancePlanTypeEnum.Predictive}> <option value={MaintenancePlanTypeEnum.Condition}>Durum Bazlı Bakım</option>
Kestirimci Bakım
</option>
<option value={MaintenancePlanTypeEnum.Corrective}>
Düzeltici Bakım
</option>
<option value={MaintenancePlanTypeEnum.Condition}>
Durum Bazlı Bakım
</option>
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Öncelik</label>
Öncelik
</label>
<select <select
name="priority" name="priority"
value={planData.priority} value={planData.priority}
@ -191,7 +158,7 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
onChange={(e) => setNewSkill(e.target.value)} onChange={(e) => setNewSkill(e.target.value)}
placeholder="Yetenek ekle..." 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" 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"
onKeyPress={(e) => e.key === "Enter" && addSkill()} onKeyPress={(e) => e.key === 'Enter' && addSkill()}
/> />
<button <button
type="button" type="button"
@ -241,7 +208,7 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default MaintenancePlanModal; export default MaintenancePlanModal

View file

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { import {
FaPlus, FaPlus,
FaSearch, FaSearch,
@ -10,489 +10,442 @@ import {
FaTrash, FaTrash,
FaEye, FaEye,
FaTasks, FaTasks,
} from "react-icons/fa"; } from 'react-icons/fa'
import { import {
PmMaintenancePlan, PmMaintenancePlan,
MaintenancePlanTypeEnum, MaintenancePlanTypeEnum,
PmMaintenanceWorkOrder, PmMaintenanceWorkOrder,
} from "../../../types/pm"; } from '../../../types/pm'
import { mockMaintenancePlans } from "../../../mocks/mockMaintenancePlans"; import { mockMaintenancePlans } from '../../../mocks/mockMaintenancePlans'
import NewMaintenancePlanModal from "./NewMaintenancePlanModal"; import NewMaintenancePlanModal from './NewMaintenancePlanModal'
import ViewMaintenancePlanModal from "./ViewMaintenancePlanModal"; import ViewMaintenancePlanModal from './ViewMaintenancePlanModal'
import EditMaintenancePlanModal from "./EditMaintenancePlanModal"; import EditMaintenancePlanModal from './EditMaintenancePlanModal'
import CreateWorkOrderModal from "./CreateWorkOrderModal"; import CreateWorkOrderModal from './CreateWorkOrderModal'
import PlanStatusChangeModal from "./PlanStatusChangeModal"; import PlanStatusChangeModal from './PlanStatusChangeModal'
import Widget from "../../../components/common/Widget"; import Widget from '../../../components/common/Widget'
import { PriorityEnum } from "../../../types/common"; import { PriorityEnum } from '../../../types/common'
import { import {
getFrequencyUnitText, getFrequencyUnitText,
getMaintenancePlanTypeColor, getMaintenancePlanTypeColor,
getMaintenancePlanTypeText, getMaintenancePlanTypeText,
getPriorityColor, getPriorityColor,
} from "../../../utils/erp"; } from '../../../utils/erp'
import { Container } from '@/components/shared'
const MaintenancePlans: React.FC = () => { const MaintenancePlans: React.FC = () => {
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState('')
const [typeFilter, setTypeFilter] = useState<MaintenancePlanTypeEnum | "all">( const [typeFilter, setTypeFilter] = useState<MaintenancePlanTypeEnum | 'all'>('all')
"all" const [statusFilter, setStatusFilter] = useState<'active' | 'inactive' | 'all'>('all')
); const [editingPlan, setEditingPlan] = useState<PmMaintenancePlan | null>(null)
const [statusFilter, setStatusFilter] = useState< const [selectedPlans, setSelectedPlans] = useState<string[]>([])
"active" | "inactive" | "all"
>("all");
const [editingPlan, setEditingPlan] = useState<PmMaintenancePlan | null>(
null
);
const [selectedPlans, setSelectedPlans] = useState<string[]>([]);
// Modal states // Modal states
const [showNewModal, setShowNewModal] = useState(false); const [showNewModal, setShowNewModal] = useState(false)
const [showViewModal, setShowViewModal] = useState(false); const [showViewModal, setShowViewModal] = useState(false)
const [showEditModal, setShowEditModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false)
const [showWorkOrderModal, setShowWorkOrderModal] = useState(false); const [showWorkOrderModal, setShowWorkOrderModal] = useState(false)
const [showStatusModal, setShowStatusModal] = useState(false); const [showStatusModal, setShowStatusModal] = useState(false)
const [viewingPlan, setViewingPlan] = useState<PmMaintenancePlan | null>( const [viewingPlan, setViewingPlan] = useState<PmMaintenancePlan | null>(null)
null
);
// Mock data - replace with actual API calls // Mock data - replace with actual API calls
const [plans] = useState<PmMaintenancePlan[]>(mockMaintenancePlans); const [plans] = useState<PmMaintenancePlan[]>(mockMaintenancePlans)
const filteredPlans = plans.filter((plan) => { const filteredPlans = plans.filter((plan) => {
const matchesSearch = const matchesSearch =
plan.planCode.toLowerCase().includes(searchTerm.toLowerCase()) || plan.planCode.toLowerCase().includes(searchTerm.toLowerCase()) ||
plan.description.toLowerCase().includes(searchTerm.toLowerCase()); plan.description.toLowerCase().includes(searchTerm.toLowerCase())
const matchesType = typeFilter === "all" || plan.planType === typeFilter; const matchesType = typeFilter === 'all' || plan.planType === typeFilter
const matchesStatus = const matchesStatus =
statusFilter === "all" || statusFilter === 'all' ||
(statusFilter === "active" && plan.isActive) || (statusFilter === 'active' && plan.isActive) ||
(statusFilter === "inactive" && !plan.isActive); (statusFilter === 'inactive' && !plan.isActive)
return matchesSearch && matchesType && matchesStatus; return matchesSearch && matchesType && matchesStatus
}); })
const isOverdue = (plan: PmMaintenancePlan) => { const isOverdue = (plan: PmMaintenancePlan) => {
if (!plan.nextDue) return false; if (!plan.nextDue) return false
return plan.nextDue < new Date(); return plan.nextDue < new Date()
}; }
const isDueSoon = (plan: PmMaintenancePlan) => { const isDueSoon = (plan: PmMaintenancePlan) => {
if (!plan.nextDue) return false; if (!plan.nextDue) return false
const today = new Date(); const today = new Date()
const diffTime = plan.nextDue.getTime() - today.getTime(); const diffTime = plan.nextDue.getTime() - today.getTime()
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
return diffDays <= 7 && diffDays > 0; return diffDays <= 7 && diffDays > 0
}; }
const getTotalMaterialCost = (plan: PmMaintenancePlan) => { const getTotalMaterialCost = (plan: PmMaintenancePlan) => {
return plan.priority; return plan.priority
}; }
// Event handlers // Event handlers
const handleAddPlan = () => { const handleAddPlan = () => {
setShowNewModal(true); setShowNewModal(true)
}; }
const handleEdit = (plan: PmMaintenancePlan) => { const handleEdit = (plan: PmMaintenancePlan) => {
setEditingPlan(plan); setEditingPlan(plan)
setShowEditModal(true); setShowEditModal(true)
}; }
const handleView = (plan: PmMaintenancePlan) => { const handleView = (plan: PmMaintenancePlan) => {
setViewingPlan(plan); setViewingPlan(plan)
setShowViewModal(true); setShowViewModal(true)
}; }
const handleSelectPlan = (planId: string) => { const handleSelectPlan = (planId: string) => {
setSelectedPlans((prev) => setSelectedPlans((prev) =>
prev.includes(planId) prev.includes(planId) ? prev.filter((id) => id !== planId) : [...prev, planId],
? prev.filter((id) => id !== planId) )
: [...prev, planId] }
);
};
const handleCreateWorkOrder = () => { const handleCreateWorkOrder = () => {
setShowWorkOrderModal(true); setShowWorkOrderModal(true)
}; }
const handleStatusChange = () => { const handleStatusChange = () => {
setShowStatusModal(true); setShowStatusModal(true)
}; }
// Modal handlers // Modal handlers
const handleSaveNewPlan = (newPlan: Partial<PmMaintenancePlan>) => { const handleSaveNewPlan = (newPlan: Partial<PmMaintenancePlan>) => {
console.log("New plan:", newPlan); console.log('New plan:', newPlan)
// TODO: API call to save new plan // TODO: API call to save new plan
}; }
const handleSaveEditPlan = (updatedPlan: PmMaintenancePlan) => { const handleSaveEditPlan = (updatedPlan: PmMaintenancePlan) => {
console.log("Updated plan:", updatedPlan); console.log('Updated plan:', updatedPlan)
// TODO: API call to update plan // TODO: API call to update plan
}; }
const handleSaveWorkOrders = ( const handleSaveWorkOrders = (workOrders: Partial<PmMaintenanceWorkOrder>[]) => {
workOrders: Partial<PmMaintenanceWorkOrder>[] console.log('Work orders:', workOrders)
) => {
console.log("Work orders:", workOrders);
// TODO: API call to create work orders // TODO: API call to create work orders
setSelectedPlans([]); setSelectedPlans([])
}; }
const handleSaveStatusChange = ( const handleSaveStatusChange = (planIds: string[], isActive: boolean, reason: string) => {
planIds: string[], console.log('Status change:', { planIds, isActive, reason })
isActive: boolean,
reason: string
) => {
console.log("Status change:", { planIds, isActive, reason });
// TODO: API call to update plan statuses // TODO: API call to update plan statuses
setSelectedPlans([]); setSelectedPlans([])
}; }
return ( return (
<div className="space-y-4 pt-2"> <Container>
{/* Header */} <div className="space-y-2">
<div className="flex items-center justify-between"> {/* Header */}
<div> <div className="flex items-center justify-between">
<h2 className="text-2xl font-bold text-gray-900">Bakım Planları</h2> <div>
<p className="text-gray-600"> <h2 className="text-2xl font-bold text-gray-900">Bakım Planları</h2>
Periyodik ve düzeltici bakım planlarını yönetin <p className="text-gray-600">Periyodik ve düzeltici bakım planlarını yönetin</p>
</p> </div>
<button
onClick={handleAddPlan}
className="bg-blue-600 text-white px-3 py-1.5 rounded-lg hover:bg-blue-700 flex items-center space-x-2 text-sm"
>
<FaPlus className="w-4 h-4" />
<span>Yeni Plan</span>
</button>
</div> </div>
<button
onClick={handleAddPlan}
className="bg-blue-600 text-white px-3 py-1.5 rounded-lg hover:bg-blue-700 flex items-center space-x-2 text-sm"
>
<FaPlus className="w-4 h-4" />
<span>Yeni Plan</span>
</button>
</div>
{/* Summary Cards */} {/* Summary Cards */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-6"> <div className="grid grid-cols-1 md:grid-cols-4 gap-6">
<Widget <Widget title="Toplam Plan" value={plans.length} color="blue" icon="FaCalendar" />
title="Toplam Plan"
value={plans.length}
color="blue"
icon="FaCalendar"
/>
<Widget <Widget
title="Aktif Plan" title="Aktif Plan"
value={plans.filter((p) => p.isActive).length} value={plans.filter((p) => p.isActive).length}
color="green" color="green"
icon="FaCheckCircle" icon="FaCheckCircle"
/> />
<Widget <Widget
title="Geciken" title="Geciken"
value={plans.filter((p) => isOverdue(p)).length} value={plans.filter((p) => isOverdue(p)).length}
color="red" color="red"
icon="FaExclamationTriangle" icon="FaExclamationTriangle"
/> />
<Widget <Widget
title="Bu Hafta" title="Bu Hafta"
value={plans.filter((p) => isDueSoon(p)).length} value={plans.filter((p) => isDueSoon(p)).length}
color="orange" color="orange"
icon="FaClock" icon="FaClock"
/>
</div>
{/* Filters */}
<div className="flex space-x-3">
<div className="flex-1 relative">
<FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
<input
type="text"
placeholder="Plan ara..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-9 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/> />
</div> </div>
<div className="relative">
<FaFilter className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5" />
<select
value={typeFilter}
onChange={(e) =>
setTypeFilter(e.target.value as MaintenancePlanTypeEnum | "all")
}
className="pl-10 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="all">Tüm Tipler</option>
<option value={MaintenancePlanTypeEnum.Preventive}>Önleyici</option>
<option value={MaintenancePlanTypeEnum.Corrective}>
Düzeltici
</option>
<option value={MaintenancePlanTypeEnum.Predictive}>
Tahminsel
</option>
<option value={MaintenancePlanTypeEnum.Condition}>
Duruma Bağlı
</option>
</select>
</div>
<div className="relative">
<select
value={statusFilter}
onChange={(e) =>
setStatusFilter(e.target.value as "active" | "inactive" | "all")
}
className="pl-4 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="all">Tüm Durumlar</option>
<option value="active">Aktif</option>
<option value="inactive">Pasif</option>
</select>
</div>
</div>
{/* Plans Table */} {/* Filters */}
<div className="bg-white rounded-lg shadow-md overflow-hidden"> <div className="flex space-x-3">
<div className="overflow-x-auto"> <div className="flex-1 relative">
<table className="min-w-full divide-y divide-gray-200"> <FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
<thead className="bg-gray-50"> <input
<tr> type="text"
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> placeholder="Plan ara..."
<input value={searchTerm}
type="checkbox" onChange={(e) => setSearchTerm(e.target.value)}
checked={ className="w-full pl-9 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
selectedPlans.length === filteredPlans.length && />
filteredPlans.length > 0 </div>
} <div className="relative">
onChange={(e) => { <FaFilter className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5" />
if (e.target.checked) { <select
setSelectedPlans(filteredPlans.map((p) => p.id)); value={typeFilter}
} else { onChange={(e) => setTypeFilter(e.target.value as MaintenancePlanTypeEnum | 'all')}
setSelectedPlans([]); className="pl-10 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
} >
}} <option value="all">Tüm Tipler</option>
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" <option value={MaintenancePlanTypeEnum.Preventive}>Önleyici</option>
/> <option value={MaintenancePlanTypeEnum.Corrective}>Düzeltici</option>
</th> <option value={MaintenancePlanTypeEnum.Predictive}>Tahminsel</option>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> <option value={MaintenancePlanTypeEnum.Condition}>Duruma Bağlı</option>
Plan Bilgileri </select>
</th> </div>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> <div className="relative">
İş Merkezi <select
</th> value={statusFilter}
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> onChange={(e) => setStatusFilter(e.target.value as 'active' | 'inactive' | 'all')}
Tip/Öncelik className="pl-4 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
</th> >
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> <option value="all">Tüm Durumlar</option>
Sıklık <option value="active">Aktif</option>
</th> <option value="inactive">Pasif</option>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> </select>
Sonraki Bakım </div>
</th> </div>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Maliyet {/* Plans Table */}
</th> <div className="bg-white rounded-lg shadow-md overflow-hidden">
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> <div className="overflow-x-auto">
Durum <table className="min-w-full divide-y divide-gray-200">
</th> <thead className="bg-gray-50">
<th className="px-4 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider"> <tr>
İşlemler <th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{filteredPlans.map((plan) => (
<tr key={plan.id} className="hover:bg-gray-50">
<td className="px-4 py-3 whitespace-nowrap">
<input <input
type="checkbox" type="checkbox"
checked={selectedPlans.includes(plan.id)} checked={
onChange={() => handleSelectPlan(plan.id)} selectedPlans.length === filteredPlans.length && filteredPlans.length > 0
}
onChange={(e) => {
if (e.target.checked) {
setSelectedPlans(filteredPlans.map((p) => p.id))
} else {
setSelectedPlans([])
}
}}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/> />
</td> </th>
<td className="px-4 py-3 whitespace-nowrap"> <th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<div className="flex items-center"> Plan Bilgileri
<div> </th>
<div className="text-sm font-medium text-gray-900"> <th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{plan.planCode} İş Merkezi
</div> </th>
<div className="text-sm text-gray-500"> <th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{plan.description} Tip/Öncelik
</div> </th>
<div className="text-xs text-gray-400 mt-1"> <th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{plan.description} Sıklık
</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Sonraki Bakım
</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Maliyet
</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Durum
</th>
<th className="px-4 py-2 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
İşlemler
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{filteredPlans.map((plan) => (
<tr key={plan.id} className="hover:bg-gray-50">
<td className="px-4 py-3 whitespace-nowrap">
<input
type="checkbox"
checked={selectedPlans.includes(plan.id)}
onChange={() => handleSelectPlan(plan.id)}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
</td>
<td className="px-4 py-3 whitespace-nowrap">
<div className="flex items-center">
<div>
<div className="text-sm font-medium text-gray-900">{plan.planCode}</div>
<div className="text-sm text-gray-500">{plan.description}</div>
<div className="text-xs text-gray-400 mt-1">{plan.description}</div>
</div> </div>
</div> </div>
</div> </td>
</td> <td className="px-4 py-3 whitespace-nowrap">
<td className="px-4 py-3 whitespace-nowrap"> <div className="text-sm text-gray-900">{plan.workCenterId}</div>
<div className="text-sm text-gray-900"> <div className="text-sm text-gray-500">İş Merkezi Adı</div>
{plan.workCenterId} </td>
</div> <td className="px-4 py-3 whitespace-nowrap">
<div className="text-sm text-gray-500">İş Merkezi Adı</div> <div className="space-y-1">
</td> <span
<td className="px-4 py-3 whitespace-nowrap"> className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${getMaintenancePlanTypeColor(
<div className="space-y-1"> plan.planType,
)}`}
>
{getMaintenancePlanTypeText(plan.planType)}
</span>
<br />
<span
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${getPriorityColor(
plan.priority,
)}`}
>
{plan.priority === PriorityEnum.Low
? 'Düşük'
: plan.priority === PriorityEnum.Normal
? 'Normal'
: plan.priority === PriorityEnum.High
? 'Yüksek'
: 'Acil'}
</span>
</div>
</td>
<td className="px-4 py-3 whitespace-nowrap">
<div className="text-sm text-gray-900">
{getFrequencyUnitText(plan.frequency, plan.frequencyUnit)}
</div>
<div className="text-xs text-gray-500">{plan.estimatedDuration} dakika</div>
</td>
<td className="px-4 py-3 whitespace-nowrap">
{plan.nextDue ? (
<div
className={`text-sm ${
isOverdue(plan)
? 'text-red-600 font-medium'
: isDueSoon(plan)
? 'text-orange-600 font-medium'
: 'text-gray-900'
}`}
>
{plan.nextDue.toLocaleDateString('tr-TR')}
{isOverdue(plan) && <div className="text-xs">GECİKMİŞ</div>}
{isDueSoon(plan) && !isOverdue(plan) && (
<div className="text-xs">YAKINDA</div>
)}
</div>
) : (
<span className="text-sm text-gray-400">-</span>
)}
</td>
<td className="px-4 py-3 whitespace-nowrap">
<div className="text-sm text-gray-900">
{getTotalMaterialCost(plan).toLocaleString()}
</div>
<div className="text-xs text-gray-500">
{plan.requiredMaterials.length} malzeme
</div>
</td>
<td className="px-4 py-3 whitespace-nowrap">
<span <span
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${getMaintenancePlanTypeColor( className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
plan.planType plan.isActive
)}`} ? 'bg-green-100 text-green-800'
> : 'bg-gray-100 text-gray-800'
{getMaintenancePlanTypeText(plan.planType)}
</span>
<br />
<span
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${getPriorityColor(
plan.priority
)}`}
>
{plan.priority === PriorityEnum.Low
? "Düşük"
: plan.priority === PriorityEnum.Normal
? "Normal"
: plan.priority === PriorityEnum.High
? "Yüksek"
: "Acil"}
</span>
</div>
</td>
<td className="px-4 py-3 whitespace-nowrap">
<div className="text-sm text-gray-900">
{getFrequencyUnitText(plan.frequency, plan.frequencyUnit)}
</div>
<div className="text-xs text-gray-500">
{plan.estimatedDuration} dakika
</div>
</td>
<td className="px-4 py-3 whitespace-nowrap">
{plan.nextDue ? (
<div
className={`text-sm ${
isOverdue(plan)
? "text-red-600 font-medium"
: isDueSoon(plan)
? "text-orange-600 font-medium"
: "text-gray-900"
}`} }`}
> >
{plan.nextDue.toLocaleDateString("tr-TR")} {plan.isActive ? 'Aktif' : 'Pasif'}
{isOverdue(plan) && ( </span>
<div className="text-xs">GECİKMİŞ</div> </td>
)} <td className="px-4 py-3 whitespace-nowrap text-right text-sm font-medium">
{isDueSoon(plan) && !isOverdue(plan) && ( <div className="flex items-center justify-end space-x-2">
<div className="text-xs">YAKINDA</div> <button
)} onClick={() => handleView(plan)}
className="text-gray-400 hover:text-blue-600 hover:bg-blue-50 p-1 rounded"
title="Görüntüle"
>
<FaEye className="w-4 h-4" />
</button>
<button
onClick={() => handleEdit(plan)}
className="text-gray-400 hover:text-green-600 hover:bg-green-50 p-1 rounded"
title="Düzenle"
>
<FaEdit className="w-4 h-4" />
</button>
<button
className="text-gray-400 hover:text-red-600 hover:bg-red-50 p-1 rounded"
title="Sil"
>
<FaTrash className="w-4 h-4" />
</button>
<button
className="text-gray-400 hover:text-blue-600 hover:bg-blue-50 p-1 rounded"
title={plan.isActive ? 'Pasif Yap' : 'Aktif Yap'}
>
{plan.isActive ? (
<FaPause className="w-4 h-4" />
) : (
<FaPlay className="w-4 h-4" />
)}
</button>
</div> </div>
) : ( </td>
<span className="text-sm text-gray-400">-</span> </tr>
)} ))}
</td> </tbody>
<td className="px-4 py-3 whitespace-nowrap"> </table>
<div className="text-sm text-gray-900"> </div>
{getTotalMaterialCost(plan).toLocaleString()}
</div> {filteredPlans.length === 0 && (
<div className="text-xs text-gray-500"> <div className="text-center py-12">
{plan.requiredMaterials.length} malzeme <FaCalendar className="w-16 h-16 text-gray-400 mx-auto mb-4" />
</div> <h3 className="text-lg font-medium text-gray-900 mb-2">Plan bulunamadı</h3>
</td> <p className="text-gray-500 mb-4">
<td className="px-4 py-3 whitespace-nowrap"> Arama kriterlerinizi değiştirin veya yeni bir plan oluşturun.
<span </p>
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${ <button
plan.isActive onClick={handleAddPlan}
? "bg-green-100 text-green-800" className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700"
: "bg-gray-100 text-gray-800" >
}`} Yeni Plan Oluştur
> </button>
{plan.isActive ? "Aktif" : "Pasif"} </div>
</span> )}
</td>
<td className="px-4 py-3 whitespace-nowrap text-right text-sm font-medium">
<div className="flex items-center justify-end space-x-2">
<button
onClick={() => handleView(plan)}
className="text-gray-400 hover:text-blue-600 hover:bg-blue-50 p-1 rounded"
title="Görüntüle"
>
<FaEye className="w-4 h-4" />
</button>
<button
onClick={() => handleEdit(plan)}
className="text-gray-400 hover:text-green-600 hover:bg-green-50 p-1 rounded"
title="Düzenle"
>
<FaEdit className="w-4 h-4" />
</button>
<button
className="text-gray-400 hover:text-red-600 hover:bg-red-50 p-1 rounded"
title="Sil"
>
<FaTrash className="w-4 h-4" />
</button>
<button
className="text-gray-400 hover:text-blue-600 hover:bg-blue-50 p-1 rounded"
title={plan.isActive ? "Pasif Yap" : "Aktif Yap"}
>
{plan.isActive ? (
<FaPause className="w-4 h-4" />
) : (
<FaPlay className="w-4 h-4" />
)}
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div> </div>
{filteredPlans.length === 0 && ( {/* Bulk Actions */}
<div className="text-center py-12"> {selectedPlans.length > 0 && (
<FaCalendar className="w-16 h-16 text-gray-400 mx-auto mb-4" /> <div className="fixed bottom-6 left-1/2 transform -translate-x-1/2 bg-white rounded-lg shadow-lg border border-gray-200 p-4">
<h3 className="text-lg font-medium text-gray-900 mb-2"> <div className="flex items-center space-x-4">
Plan bulunamadı <span className="text-sm text-gray-600">{selectedPlans.length} plan seçildi</span>
</h3> <div className="flex space-x-2">
<p className="text-gray-500 mb-4"> <button
Arama kriterlerinizi değiştirin veya yeni bir plan oluşturun. onClick={handleCreateWorkOrder}
</p> className="flex items-center space-x-1 bg-green-600 text-white px-2.5 py-1.5 rounded text-sm hover:bg-green-700"
<button >
onClick={handleAddPlan} <FaTasks className="w-4 h-4" />
className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700" <span>İş Emri Oluştur</span>
> </button>
Yeni Plan Oluştur <button
</button> onClick={handleStatusChange}
className="flex items-center space-x-1 bg-blue-600 text-white px-2.5 py-1.5 rounded text-sm hover:bg-blue-700"
>
<FaPlay className="w-4 h-4" />
<span>Durum Değiştir</span>
</button>
<button
onClick={() => setSelectedPlans([])}
className="bg-gray-600 text-white px-2.5 py-1.5 rounded text-sm hover:bg-gray-700"
>
Temizle
</button>
</div>
</div>
</div> </div>
)} )}
</div> </div>
{/* Bulk Actions */}
{selectedPlans.length > 0 && (
<div className="fixed bottom-6 left-1/2 transform -translate-x-1/2 bg-white rounded-lg shadow-lg border border-gray-200 p-4">
<div className="flex items-center space-x-4">
<span className="text-sm text-gray-600">
{selectedPlans.length} plan seçildi
</span>
<div className="flex space-x-2">
<button
onClick={handleCreateWorkOrder}
className="flex items-center space-x-1 bg-green-600 text-white px-2.5 py-1.5 rounded text-sm hover:bg-green-700"
>
<FaTasks className="w-4 h-4" />
<span>İş Emri Oluştur</span>
</button>
<button
onClick={handleStatusChange}
className="flex items-center space-x-1 bg-blue-600 text-white px-2.5 py-1.5 rounded text-sm hover:bg-blue-700"
>
<FaPlay className="w-4 h-4" />
<span>Durum Değiştir</span>
</button>
<button
onClick={() => setSelectedPlans([])}
className="bg-gray-600 text-white px-2.5 py-1.5 rounded text-sm hover:bg-gray-700"
>
Temizle
</button>
</div>
</div>
</div>
)}
{/* Modals */} {/* Modals */}
<NewMaintenancePlanModal <NewMaintenancePlanModal
isOpen={showNewModal} isOpen={showNewModal}
@ -517,21 +470,17 @@ const MaintenancePlans: React.FC = () => {
isOpen={showWorkOrderModal} isOpen={showWorkOrderModal}
onClose={() => setShowWorkOrderModal(false)} onClose={() => setShowWorkOrderModal(false)}
onSave={handleSaveWorkOrders} onSave={handleSaveWorkOrders}
selectedPlans={selectedPlans selectedPlans={selectedPlans.map((id) => plans.find((p) => p.id === id)!).filter(Boolean)}
.map((id) => plans.find((p) => p.id === id)!)
.filter(Boolean)}
/> />
<PlanStatusChangeModal <PlanStatusChangeModal
isOpen={showStatusModal} isOpen={showStatusModal}
onClose={() => setShowStatusModal(false)} onClose={() => setShowStatusModal(false)}
onSave={handleSaveStatusChange} onSave={handleSaveStatusChange}
selectedPlans={selectedPlans selectedPlans={selectedPlans.map((id) => plans.find((p) => p.id === id)!).filter(Boolean)}
.map((id) => plans.find((p) => p.id === id)!)
.filter(Boolean)}
/> />
</div> </Container>
); )
}; }
export default MaintenancePlans; export default MaintenancePlans

View file

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { import {
FaPlus, FaPlus,
FaSearch, FaSearch,
@ -12,44 +12,38 @@ import {
FaEnvelope, FaEnvelope,
FaAward, FaAward,
FaClock, FaClock,
} from "react-icons/fa"; } from 'react-icons/fa'
import { TeamRoleEnum } from "../../../types/common"; import { TeamRoleEnum } from '../../../types/common'
import { mockMaintenanceTeams } from "../../../mocks/mockMaintenanceTeams"; import { mockMaintenanceTeams } from '../../../mocks/mockMaintenanceTeams'
import NewTeamModal from "./NewTeamModal"; import NewTeamModal from './NewTeamModal'
import ViewTeamModal from "./ViewTeamModal"; import ViewTeamModal from './ViewTeamModal'
import EditTeamModal from "./EditTeamModal"; import EditTeamModal from './EditTeamModal'
import AssignWorkOrderModal from "./AssignWorkOrderModal"; import AssignWorkOrderModal from './AssignWorkOrderModal'
import TeamStatusChangeModal from "./TeamStatusChangeModal"; import TeamStatusChangeModal from './TeamStatusChangeModal'
import Widget from "../../../components/common/Widget"; import Widget from '../../../components/common/Widget'
import { Team } from "../../../types/common"; import { Team } from '../../../types/common'
import { import { getTeamRoleColor, getTeamRoleIcon, getTeamRoleText } from '../../../utils/erp'
getTeamRoleColor, import { Container } from '@/components/shared'
getTeamRoleIcon,
getTeamRoleText,
} from "../../../utils/erp";
const MaintenanceTeams: React.FC = () => { const MaintenanceTeams: React.FC = () => {
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState('')
const [roleFilter, setRoleFilter] = useState<TeamRoleEnum | "all">("all"); const [roleFilter, setRoleFilter] = useState<TeamRoleEnum | 'all'>('all')
const [statusFilter, setStatusFilter] = useState< const [statusFilter, setStatusFilter] = useState<'active' | 'inactive' | 'all'>('all')
"active" | "inactive" | "all"
>("all");
// Modal states // Modal states
const [showNewTeamModal, setShowNewTeamModal] = useState(false); const [showNewTeamModal, setShowNewTeamModal] = useState(false)
const [showViewTeamModal, setShowViewTeamModal] = useState(false); const [showViewTeamModal, setShowViewTeamModal] = useState(false)
const [showEditTeamModal, setShowEditTeamModal] = useState(false); const [showEditTeamModal, setShowEditTeamModal] = useState(false)
const [showAssignWorkOrderModal, setShowAssignWorkOrderModal] = const [showAssignWorkOrderModal, setShowAssignWorkOrderModal] = useState(false)
useState(false); const [showStatusChangeModal, setShowStatusChangeModal] = useState(false)
const [showStatusChangeModal, setShowStatusChangeModal] = useState(false);
// Selected data // Selected data
const [viewingTeam, setViewingTeam] = useState<Team | null>(null); const [viewingTeam, setViewingTeam] = useState<Team | null>(null)
const [editingTeam, setEditingTeam] = useState<Team | null>(null); const [editingTeam, setEditingTeam] = useState<Team | null>(null)
const [selectedTeams, setSelectedTeams] = useState<string[]>([]); const [selectedTeams, setSelectedTeams] = useState<string[]>([])
// Mock data - replace with actual API calls // Mock data - replace with actual API calls
const [teams, setTeams] = useState<Team[]>(mockMaintenanceTeams); const [teams, setTeams] = useState<Team[]>(mockMaintenanceTeams)
const filteredTeams = teams.filter((team) => { const filteredTeams = teams.filter((team) => {
const matchesSearch = const matchesSearch =
@ -57,441 +51,389 @@ const MaintenanceTeams: React.FC = () => {
team.name.toLowerCase().includes(searchTerm.toLowerCase()) || team.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
team.members.some( team.members.some(
(member) => (member) =>
member.employee?.firstName member.employee?.firstName.toLowerCase().includes(searchTerm.toLowerCase()) ||
.toLowerCase() member.employee?.lastName.toLowerCase().includes(searchTerm.toLowerCase()),
.includes(searchTerm.toLowerCase()) || )
member.employee?.lastName
.toLowerCase()
.includes(searchTerm.toLowerCase())
);
const matchesRole = const matchesRole =
roleFilter === "all" || roleFilter === 'all' || team.members.some((member) => member.role === roleFilter)
team.members.some((member) => member.role === roleFilter);
const matchesStatus = const matchesStatus =
statusFilter === "all" || statusFilter === 'all' ||
(statusFilter === "active" && team.isActive) || (statusFilter === 'active' && team.isActive) ||
(statusFilter === "inactive" && !team.isActive); (statusFilter === 'inactive' && !team.isActive)
return matchesSearch && matchesRole && matchesStatus; return matchesSearch && matchesRole && matchesStatus
}); })
const getTeamLeader = (team: Team) => { const getTeamLeader = (team: Team) => {
return team.members.find((member) => member.role === TeamRoleEnum.Lead); return team.members.find((member) => member.role === TeamRoleEnum.Lead)
}; }
const getActiveMembers = (team: Team) => { const getActiveMembers = (team: Team) => {
return team.members.filter((member) => member.isActive); return team.members.filter((member) => member.isActive)
}; }
const handleAddTeam = () => { const handleAddTeam = () => {
setEditingTeam(null); setEditingTeam(null)
setShowNewTeamModal(true); setShowNewTeamModal(true)
}; }
const handleViewTeam = (team: Team) => { const handleViewTeam = (team: Team) => {
setViewingTeam(team); setViewingTeam(team)
setShowViewTeamModal(true); setShowViewTeamModal(true)
}; }
const handleEditTeam = (team: Team) => { const handleEditTeam = (team: Team) => {
setEditingTeam(team); setEditingTeam(team)
setShowEditTeamModal(true); setShowEditTeamModal(true)
}; }
const handleSelectTeam = (teamId: string) => { const handleSelectTeam = (teamId: string) => {
setSelectedTeams((prev) => setSelectedTeams((prev) =>
prev.includes(teamId) prev.includes(teamId) ? prev.filter((id) => id !== teamId) : [...prev, teamId],
? prev.filter((id) => id !== teamId) )
: [...prev, teamId] }
);
};
const handleNewTeamSave = (newTeam: Partial<Team>) => { const handleNewTeamSave = (newTeam: Partial<Team>) => {
if (newTeam.id) { if (newTeam.id) {
setTeams((prev) => [...prev, newTeam as Team]); setTeams((prev) => [...prev, newTeam as Team])
} }
}; }
const handleEditTeamSave = (updatedTeam: Team) => { const handleEditTeamSave = (updatedTeam: Team) => {
setTeams((prev) => setTeams((prev) => prev.map((team) => (team.id === updatedTeam.id ? updatedTeam : team)))
prev.map((team) => (team.id === updatedTeam.id ? updatedTeam : team)) }
);
};
const handleAssignWorkOrders = ( const handleAssignWorkOrders = (assignments: { teamId: string; planIds: string[] }[]) => {
assignments: { teamId: string; planIds: string[] }[]
) => {
// Here you would typically make API calls to assign work orders // Here you would typically make API calls to assign work orders
console.log("Assigning work orders:", assignments); console.log('Assigning work orders:', assignments)
// Show success message or handle the actual assignment logic // Show success message or handle the actual assignment logic
}; }
const handleStatusChange = ( const handleStatusChange = (teamIds: string[], newStatus: boolean, reason?: string) => {
teamIds: string[],
newStatus: boolean,
reason?: string
) => {
setTeams((prev) => setTeams((prev) =>
prev.map((team) => prev.map((team) =>
teamIds.includes(team.id) teamIds.includes(team.id)
? { ...team, isActive: newStatus, lastModificationTime: new Date() } ? { ...team, isActive: newStatus, lastModificationTime: new Date() }
: team : team,
) ),
); )
setSelectedTeams([]); setSelectedTeams([])
// Here you would typically log the status change with reason // Here you would typically log the status change with reason
console.log("Status change:", { teamIds, newStatus, reason }); console.log('Status change:', { teamIds, newStatus, reason })
}; }
const selectedTeamObjects = teams.filter((team) => const selectedTeamObjects = teams.filter((team) => selectedTeams.includes(team.id))
selectedTeams.includes(team.id)
);
return ( return (
<div className="space-y-4 pt-2"> <Container>
{/* Header */} <div className="space-y-2">
<div className="flex items-center justify-between"> {/* Header */}
<div> <div className="flex items-center justify-between">
<h2 className="text-2xl font-bold text-gray-900">Bakım Ekipleri</h2> <div>
<p className="text-gray-600"> <h2 className="text-2xl font-bold text-gray-900">Bakım Ekipleri</h2>
Bakım ekiplerini ve üyelerini yönetin <p className="text-gray-600">Bakım ekiplerini ve üyelerini yönetin</p>
</p> </div>
</div>
<button
onClick={handleAddTeam}
className="bg-blue-600 text-white px-3 py-1.5 rounded-lg hover:bg-blue-700 flex items-center space-x-2 text-sm"
>
<FaPlus className="w-4 h-4" />
<span>Yeni Ekip</span>
</button>
</div>
{/* Summary Cards */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
<Widget
title="Toplam Ekip"
value={teams.length}
color="blue"
icon="FaUsers"
/>
<Widget
title="Aktif Ekip"
value={teams.filter((t) => t.isActive).length}
color="green"
icon="FaCheckCircle"
/>
<Widget
title="Toplam Üye"
value={teams.reduce(
(total, team) => total + getActiveMembers(team).length,
0
)}
color="orange"
icon="FaUser"
/>
<Widget
title="Uzmanlık"
value={teams.reduce(
(total, team) => total + (team.specializations?.length || 0),
0
)}
color="purple"
icon="FaWrench"
/>
</div>
{/* Filters */}
<div className="flex space-x-3">
<div className="flex-1 relative">
<FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
<input
type="text"
placeholder="Ekip veya üye ara..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-9 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<div className="relative">
<FaFilter className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5" />
<select
value={roleFilter}
onChange={(e) =>
setRoleFilter(e.target.value as TeamRoleEnum | "all")
}
className="pl-10 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="all">Tüm Roller</option>
<option value={TeamRoleEnum.Lead}>Lider</option>
<option value={TeamRoleEnum.Specialist}>Uzman</option>
<option value={TeamRoleEnum.Member}>Üye</option>
</select>
</div>
<div className="relative">
<select
value={statusFilter}
onChange={(e) =>
setStatusFilter(e.target.value as "active" | "inactive" | "all")
}
className="pl-4 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="all">Tüm Durumlar</option>
<option value="active">Aktif</option>
<option value="inactive">Pasif</option>
</select>
</div>
</div>
{/* Teams Grid */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{filteredTeams.map((team) => {
const leader = getTeamLeader(team);
const activeMembers = getActiveMembers(team);
return (
<div
key={team.id}
className="bg-white rounded-lg shadow-md border border-gray-200 p-4 hover:shadow-lg transition-shadow"
>
<div className="flex items-start justify-between mb-3">
<div className="flex-1">
<div className="flex items-center space-x-2 mb-2">
<input
type="checkbox"
checked={selectedTeams.includes(team.id)}
onChange={() => handleSelectTeam(team.id)}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500 mt-0.5"
/>
<h3 className="text-lg font-semibold text-gray-900">
{team.code}
</h3>
<span
className={`px-2 py-1 rounded-full text-xs font-medium ${
team.isActive
? "bg-green-100 text-green-800"
: "bg-gray-100 text-gray-800"
}`}
>
{team.isActive ? "Aktif" : "Pasif"}
</span>
</div>
<h4 className="font-medium text-gray-700 mb-1 text-sm">
{team.name}
</h4>
<p className="text-xs text-gray-500 mb-2">
{team.description}
</p>
</div>
<div className="flex space-x-1">
<button
onClick={() => handleViewTeam(team)}
className="p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-md transition-colors"
>
<FaEye className="w-4 h-4" />
</button>
<button
onClick={() => handleEditTeam(team)}
className="p-1.5 text-gray-400 hover:text-green-600 hover:bg-green-50 rounded-md transition-colors"
>
<FaEdit className="w-4 h-4" />
</button>
<button className="p-1.5 text-gray-400 hover:text-red-600 hover:bg-red-50 rounded-md transition-colors">
<FaTrash className="w-4 h-4" />
</button>
</div>
</div>
{/* Team Leader */}
{leader && (
<div className="bg-purple-50 rounded-lg p-2 mb-3">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 bg-purple-600 rounded-full flex items-center justify-center">
<FaAward className="w-5 h-5 text-white" />
</div>
<div className="flex-1">
<div className="flex items-center space-x-2">
<h5 className="font-medium text-gray-900">
{leader.employee?.firstName}{" "}
{leader.employee?.lastName}
</h5>
<span
className={`px-2 py-1 rounded-full text-xs font-medium flex items-center space-x-1 ${getTeamRoleColor(
leader.role
)}`}
>
{getTeamRoleIcon(leader.role)}
<span>{getTeamRoleText(leader.role)}</span>
</span>
</div>
<p className="text-sm text-gray-600">
{leader.employee?.jobPosition?.code}
</p>
<div className="flex items-center space-x-4 mt-1 text-xs text-gray-500">
{leader.employee?.email && (
<div className="flex items-center space-x-1">
<FaEnvelope className="w-3 h-3" />
<span>{leader.employee.email}</span>
</div>
)}
{leader.employee?.phone && (
<div className="flex items-center space-x-1">
<FaPhone className="w-3 h-3" />
<span>{leader.employee.phone}</span>
</div>
)}
</div>
</div>
</div>
</div>
)}
{/* Team Members */}
<div className="space-y-2 mb-3">
<h5 className="text-xs font-medium text-gray-700">
Ekip Üyeleri ({activeMembers.length})
</h5>
<div className="space-y-2">
{activeMembers
.filter((member) => member.role !== TeamRoleEnum.Lead)
.slice(0, 3)
.map((member) => (
<div
key={member.id}
className="flex items-center space-x-2 p-1.5 bg-gray-50 rounded-lg"
>
<div className="w-8 h-8 bg-gray-400 rounded-full flex items-center justify-center">
<FaUser className="w-4 h-4 text-white" />
</div>
<div className="flex-1">
<div className="flex items-center space-x-2">
<span className="text-sm font-medium text-gray-900">
{member.employee?.firstName}{" "}
{member.employee?.lastName}
</span>
<span
className={`px-2 py-1 rounded-full text-xs font-medium flex items-center space-x-1 ${getTeamRoleColor(
member.role
)}`}
>
{getTeamRoleIcon(member.role)}
<span>{getTeamRoleText(member.role)}</span>
</span>
</div>
<p className="text-xs text-gray-600">
{member.employee?.jobPosition?.code}
</p>
</div>
</div>
))}
{activeMembers.filter(
(member) => member.role !== TeamRoleEnum.Lead
).length > 3 && (
<div className="text-center text-xs text-gray-500 p-1.5">
+
{activeMembers.filter(
(member) => member.role !== TeamRoleEnum.Lead
).length - 3}{" "}
kişi daha...
</div>
)}
</div>
</div>
{/* Specializations */}
<div className="border-t border-gray-100 pt-2">
<h5 className="text-xs font-medium text-gray-700 mb-2">
Uzmanlık Alanları
</h5>
<div className="flex flex-wrap gap-1">
{team.specializations ??
[].slice(0, 6).map((specialization, index) => (
<span
key={index}
className="px-2 py-1 bg-blue-100 text-blue-800 text-xs rounded-full"
>
{specialization}
</span>
))}
{(team.specializations?.length ?? 0) > 6 && (
<span className="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded-full">
+{(team.specializations?.length ?? 0) - 6}
</span>
)}
</div>
</div>
<div className="border-t border-gray-100 pt-2 mt-2">
<div className="flex items-center justify-between text-xs text-gray-500">
<div className="flex items-center space-x-2">
<FaClock className="w-3 h-3" />
<span>
Oluşturuldu:{" "}
{team.creationTime.toLocaleDateString("tr-TR")}
</span>
</div>
<div className="flex items-center space-x-2">
<span>
Son Güncelleme:{" "}
{team.lastModificationTime.toLocaleDateString("tr-TR")}
</span>
</div>
</div>
</div>
</div>
);
})}
</div>
{filteredTeams.length === 0 && (
<div className="text-center py-12">
<FaUsers className="w-16 h-16 text-gray-400 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2">
Ekip bulunamadı
</h3>
<p className="text-gray-500 mb-4">
Arama kriterlerinizi değiştirin veya yeni bir ekip oluşturun.
</p>
<button <button
onClick={handleAddTeam} onClick={handleAddTeam}
className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700" className="bg-blue-600 text-white px-3 py-1.5 rounded-lg hover:bg-blue-700 flex items-center space-x-2 text-sm"
> >
Yeni Ekip Oluştur <FaPlus className="w-4 h-4" />
<span>Yeni Ekip</span>
</button> </button>
</div> </div>
)}
{/* Bulk Actions */} {/* Summary Cards */}
{selectedTeams.length > 0 && ( <div className="grid grid-cols-1 md:grid-cols-4 gap-6">
<div className="fixed bottom-6 left-1/2 transform -translate-x-1/2 bg-white rounded-lg shadow-lg border border-gray-200 p-4"> <Widget title="Toplam Ekip" value={teams.length} color="blue" icon="FaUsers" />
<div className="flex items-center space-x-4">
<span className="text-sm text-gray-600"> <Widget
{selectedTeams.length} ekip seçildi title="Aktif Ekip"
</span> value={teams.filter((t) => t.isActive).length}
<div className="flex space-x-2"> color="green"
<button icon="FaCheckCircle"
onClick={() => setShowAssignWorkOrderModal(true)} />
className="bg-green-600 text-white px-2.5 py-1.5 rounded text-sm hover:bg-green-700"
> <Widget
İş Emri Ata title="Toplam Üye"
</button> value={teams.reduce((total, team) => total + getActiveMembers(team).length, 0)}
<button color="orange"
onClick={() => setShowStatusChangeModal(true)} icon="FaUser"
className="bg-blue-600 text-white px-2.5 py-1.5 rounded text-sm hover:bg-blue-700" />
>
Durum Değiştir <Widget
</button> title="Uzmanlık"
<button value={teams.reduce((total, team) => total + (team.specializations?.length || 0), 0)}
onClick={() => setSelectedTeams([])} color="purple"
className="bg-gray-600 text-white px-2.5 py-1.5 rounded text-sm hover:bg-gray-700" icon="FaWrench"
> />
Temizle </div>
</button>
</div> {/* Filters */}
<div className="flex space-x-3">
<div className="flex-1 relative">
<FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
<input
type="text"
placeholder="Ekip veya üye ara..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-9 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<div className="relative">
<FaFilter className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5" />
<select
value={roleFilter}
onChange={(e) => setRoleFilter(e.target.value as TeamRoleEnum | 'all')}
className="pl-10 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="all">Tüm Roller</option>
<option value={TeamRoleEnum.Lead}>Lider</option>
<option value={TeamRoleEnum.Specialist}>Uzman</option>
<option value={TeamRoleEnum.Member}>Üye</option>
</select>
</div>
<div className="relative">
<select
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value as 'active' | 'inactive' | 'all')}
className="pl-4 pr-4 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="all">Tüm Durumlar</option>
<option value="active">Aktif</option>
<option value="inactive">Pasif</option>
</select>
</div> </div>
</div> </div>
)}
{/* Teams Grid */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{filteredTeams.map((team) => {
const leader = getTeamLeader(team)
const activeMembers = getActiveMembers(team)
return (
<div
key={team.id}
className="bg-white rounded-lg shadow-md border border-gray-200 p-4 hover:shadow-lg transition-shadow"
>
<div className="flex items-start justify-between mb-3">
<div className="flex-1">
<div className="flex items-center space-x-2 mb-2">
<input
type="checkbox"
checked={selectedTeams.includes(team.id)}
onChange={() => handleSelectTeam(team.id)}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500 mt-0.5"
/>
<h3 className="text-lg font-semibold text-gray-900">{team.code}</h3>
<span
className={`px-2 py-1 rounded-full text-xs font-medium ${
team.isActive
? 'bg-green-100 text-green-800'
: 'bg-gray-100 text-gray-800'
}`}
>
{team.isActive ? 'Aktif' : 'Pasif'}
</span>
</div>
<h4 className="font-medium text-gray-700 mb-1 text-sm">{team.name}</h4>
<p className="text-xs text-gray-500 mb-2">{team.description}</p>
</div>
<div className="flex space-x-1">
<button
onClick={() => handleViewTeam(team)}
className="p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-md transition-colors"
>
<FaEye className="w-4 h-4" />
</button>
<button
onClick={() => handleEditTeam(team)}
className="p-1.5 text-gray-400 hover:text-green-600 hover:bg-green-50 rounded-md transition-colors"
>
<FaEdit className="w-4 h-4" />
</button>
<button className="p-1.5 text-gray-400 hover:text-red-600 hover:bg-red-50 rounded-md transition-colors">
<FaTrash className="w-4 h-4" />
</button>
</div>
</div>
{/* Team Leader */}
{leader && (
<div className="bg-purple-50 rounded-lg p-2 mb-3">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 bg-purple-600 rounded-full flex items-center justify-center">
<FaAward className="w-5 h-5 text-white" />
</div>
<div className="flex-1">
<div className="flex items-center space-x-2">
<h5 className="font-medium text-gray-900">
{leader.employee?.firstName} {leader.employee?.lastName}
</h5>
<span
className={`px-2 py-1 rounded-full text-xs font-medium flex items-center space-x-1 ${getTeamRoleColor(
leader.role,
)}`}
>
{getTeamRoleIcon(leader.role)}
<span>{getTeamRoleText(leader.role)}</span>
</span>
</div>
<p className="text-sm text-gray-600">
{leader.employee?.jobPosition?.code}
</p>
<div className="flex items-center space-x-4 mt-1 text-xs text-gray-500">
{leader.employee?.email && (
<div className="flex items-center space-x-1">
<FaEnvelope className="w-3 h-3" />
<span>{leader.employee.email}</span>
</div>
)}
{leader.employee?.phone && (
<div className="flex items-center space-x-1">
<FaPhone className="w-3 h-3" />
<span>{leader.employee.phone}</span>
</div>
)}
</div>
</div>
</div>
</div>
)}
{/* Team Members */}
<div className="space-y-2 mb-3">
<h5 className="text-xs font-medium text-gray-700">
Ekip Üyeleri ({activeMembers.length})
</h5>
<div className="space-y-2">
{activeMembers
.filter((member) => member.role !== TeamRoleEnum.Lead)
.slice(0, 3)
.map((member) => (
<div
key={member.id}
className="flex items-center space-x-2 p-1.5 bg-gray-50 rounded-lg"
>
<div className="w-8 h-8 bg-gray-400 rounded-full flex items-center justify-center">
<FaUser className="w-4 h-4 text-white" />
</div>
<div className="flex-1">
<div className="flex items-center space-x-2">
<span className="text-sm font-medium text-gray-900">
{member.employee?.firstName} {member.employee?.lastName}
</span>
<span
className={`px-2 py-1 rounded-full text-xs font-medium flex items-center space-x-1 ${getTeamRoleColor(
member.role,
)}`}
>
{getTeamRoleIcon(member.role)}
<span>{getTeamRoleText(member.role)}</span>
</span>
</div>
<p className="text-xs text-gray-600">
{member.employee?.jobPosition?.code}
</p>
</div>
</div>
))}
{activeMembers.filter((member) => member.role !== TeamRoleEnum.Lead).length >
3 && (
<div className="text-center text-xs text-gray-500 p-1.5">
+
{activeMembers.filter((member) => member.role !== TeamRoleEnum.Lead)
.length - 3}{' '}
kişi daha...
</div>
)}
</div>
</div>
{/* Specializations */}
<div className="border-t border-gray-100 pt-2">
<h5 className="text-xs font-medium text-gray-700 mb-2">Uzmanlık Alanları</h5>
<div className="flex flex-wrap gap-1">
{team.specializations ??
[].slice(0, 6).map((specialization, index) => (
<span
key={index}
className="px-2 py-1 bg-blue-100 text-blue-800 text-xs rounded-full"
>
{specialization}
</span>
))}
{(team.specializations?.length ?? 0) > 6 && (
<span className="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded-full">
+{(team.specializations?.length ?? 0) - 6}
</span>
)}
</div>
</div>
<div className="border-t border-gray-100 pt-2 mt-2">
<div className="flex items-center justify-between text-xs text-gray-500">
<div className="flex items-center space-x-2">
<FaClock className="w-3 h-3" />
<span>Oluşturuldu: {team.creationTime.toLocaleDateString('tr-TR')}</span>
</div>
<div className="flex items-center space-x-2">
<span>
Son Güncelleme: {team.lastModificationTime.toLocaleDateString('tr-TR')}
</span>
</div>
</div>
</div>
</div>
)
})}
</div>
{filteredTeams.length === 0 && (
<div className="text-center py-12">
<FaUsers className="w-16 h-16 text-gray-400 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2">Ekip bulunamadı</h3>
<p className="text-gray-500 mb-4">
Arama kriterlerinizi değiştirin veya yeni bir ekip oluşturun.
</p>
<button
onClick={handleAddTeam}
className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700"
>
Yeni Ekip Oluştur
</button>
</div>
)}
{/* Bulk Actions */}
{selectedTeams.length > 0 && (
<div className="fixed bottom-6 left-1/2 transform -translate-x-1/2 bg-white rounded-lg shadow-lg border border-gray-200 p-4">
<div className="flex items-center space-x-4">
<span className="text-sm text-gray-600">{selectedTeams.length} ekip seçildi</span>
<div className="flex space-x-2">
<button
onClick={() => setShowAssignWorkOrderModal(true)}
className="bg-green-600 text-white px-2.5 py-1.5 rounded text-sm hover:bg-green-700"
>
İş Emri Ata
</button>
<button
onClick={() => setShowStatusChangeModal(true)}
className="bg-blue-600 text-white px-2.5 py-1.5 rounded text-sm hover:bg-blue-700"
>
Durum Değiştir
</button>
<button
onClick={() => setSelectedTeams([])}
className="bg-gray-600 text-white px-2.5 py-1.5 rounded text-sm hover:bg-gray-700"
>
Temizle
</button>
</div>
</div>
</div>
)}
</div>
{/* Modals */} {/* Modals */}
<NewTeamModal <NewTeamModal
@ -527,8 +469,8 @@ const MaintenanceTeams: React.FC = () => {
onSave={handleStatusChange} onSave={handleStatusChange}
selectedTeams={selectedTeamObjects} selectedTeams={selectedTeamObjects}
/> />
</div> </Container>
); )
}; }
export default MaintenanceTeams; export default MaintenanceTeams

File diff suppressed because it is too large Load diff

View file

@ -1,15 +1,15 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from 'react'
import { FaTimes, FaSave, FaCalendar, FaClock } from "react-icons/fa"; import { FaTimes, FaSave, FaCalendar, FaClock } from 'react-icons/fa'
import { PmCalendarEvent, WorkOrderStatusEnum } from "../../../types/pm"; import { PmCalendarEvent, WorkOrderStatusEnum } from '../../../types/pm'
import { mockWorkCenters } from "../../../mocks/mockWorkCenters"; import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from '../../../mocks/mockEmployees'
import { PriorityEnum } from "../../../types/common"; import { PriorityEnum } from '../../../types/common'
interface NewCalendarEventModalProps { interface NewCalendarEventModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (event: Partial<PmCalendarEvent>) => void; onSave: (event: Partial<PmCalendarEvent>) => void
selectedDate?: Date; selectedDate?: Date
} }
const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
@ -20,185 +20,165 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
}) => { }) => {
const getInitialStartTime = () => { const getInitialStartTime = () => {
if (selectedDate) { if (selectedDate) {
const hour = selectedDate.getHours(); const hour = selectedDate.getHours()
const minute = selectedDate.getMinutes(); const minute = selectedDate.getMinutes()
return `${hour.toString().padStart(2, "0")}:${minute return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`
.toString()
.padStart(2, "0")}`;
} }
return "09:00"; return '09:00'
}; }
const getInitialEndTime = () => { const getInitialEndTime = () => {
if (selectedDate) { if (selectedDate) {
const endTime = new Date(selectedDate); const endTime = new Date(selectedDate)
endTime.setHours(endTime.getHours() + 1); endTime.setHours(endTime.getHours() + 1)
const hour = endTime.getHours(); const hour = endTime.getHours()
const minute = endTime.getMinutes(); const minute = endTime.getMinutes()
return `${hour.toString().padStart(2, "0")}:${minute return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`
.toString()
.padStart(2, "0")}`;
} }
return "10:00"; return '10:00'
}; }
const [eventData, setEventData] = useState<Partial<PmCalendarEvent>>({ const [eventData, setEventData] = useState<Partial<PmCalendarEvent>>({
title: "", title: '',
type: "plan", type: 'plan',
date: selectedDate || new Date(), date: selectedDate || new Date(),
startTime: getInitialStartTime(), startTime: getInitialStartTime(),
endTime: getInitialEndTime(), endTime: getInitialEndTime(),
status: WorkOrderStatusEnum.Planned, status: WorkOrderStatusEnum.Planned,
priority: PriorityEnum.Normal, priority: PriorityEnum.Normal,
assignedTo: "", assignedTo: '',
workCenterCode: "", workCenterCode: '',
duration: 60, duration: 60,
}); })
const [errors, setErrors] = useState<Record<string, string>>({}); const [errors, setErrors] = useState<Record<string, string>>({})
// Update form data when selectedDate changes // Update form data when selectedDate changes
useEffect(() => { useEffect(() => {
if (selectedDate) { if (selectedDate) {
const getInitialStartTime = () => { const getInitialStartTime = () => {
const hour = selectedDate.getHours(); const hour = selectedDate.getHours()
const minute = selectedDate.getMinutes(); const minute = selectedDate.getMinutes()
return `${hour.toString().padStart(2, "0")}:${minute return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`
.toString() }
.padStart(2, "0")}`;
};
const getInitialEndTime = () => { const getInitialEndTime = () => {
const endTime = new Date(selectedDate); const endTime = new Date(selectedDate)
endTime.setHours(endTime.getHours() + 1); endTime.setHours(endTime.getHours() + 1)
const hour = endTime.getHours(); const hour = endTime.getHours()
const minute = endTime.getMinutes(); const minute = endTime.getMinutes()
return `${hour.toString().padStart(2, "0")}:${minute return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`
.toString() }
.padStart(2, "0")}`;
};
setEventData((prev) => ({ setEventData((prev) => ({
...prev, ...prev,
date: selectedDate, date: selectedDate,
startTime: getInitialStartTime(), startTime: getInitialStartTime(),
endTime: getInitialEndTime(), endTime: getInitialEndTime(),
})); }))
} }
}, [selectedDate]); }, [selectedDate])
if (!isOpen) return null; if (!isOpen) return null
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (!eventData.title?.trim()) { if (!eventData.title?.trim()) {
newErrors.title = "Başlık gerekli"; newErrors.title = 'Başlık gerekli'
} }
if (!eventData.workCenterCode?.trim()) { if (!eventData.workCenterCode?.trim()) {
newErrors.workCenterCode = "İş Merkezi seçimi gerekli"; newErrors.workCenterCode = 'İş Merkezi seçimi gerekli'
} }
if (!eventData.startTime) { if (!eventData.startTime) {
newErrors.startTime = "Başlangıç saati gerekli"; newErrors.startTime = 'Başlangıç saati gerekli'
} }
if (!eventData.endTime) { if (!eventData.endTime) {
newErrors.endTime = "Bitiş saati gerekli"; newErrors.endTime = 'Bitiş saati gerekli'
} }
if (eventData.startTime && eventData.endTime) { if (eventData.startTime && eventData.endTime) {
const start = new Date(`2000-01-01 ${eventData.startTime}`); const start = new Date(`2000-01-01 ${eventData.startTime}`)
const end = new Date(`2000-01-01 ${eventData.endTime}`); const end = new Date(`2000-01-01 ${eventData.endTime}`)
if (start >= end) { if (start >= end) {
newErrors.endTime = "Bitiş saati başlangıç saatinden sonra olmalı"; newErrors.endTime = 'Bitiş saati başlangıç saatinden sonra olmalı'
} }
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleSave = () => { const handleSave = () => {
if (validateForm()) { if (validateForm()) {
// Calculate duration // Calculate duration
if (eventData.startTime && eventData.endTime) { if (eventData.startTime && eventData.endTime) {
const start = new Date(`2000-01-01 ${eventData.startTime}`); const start = new Date(`2000-01-01 ${eventData.startTime}`)
const end = new Date(`2000-01-01 ${eventData.endTime}`); const end = new Date(`2000-01-01 ${eventData.endTime}`)
const durationMinutes = (end.getTime() - start.getTime()) / (1000 * 60); const durationMinutes = (end.getTime() - start.getTime()) / (1000 * 60)
eventData.duration = durationMinutes; eventData.duration = durationMinutes
} }
onSave({ onSave({
...eventData, ...eventData,
id: `E${Date.now()}`, // Generate a simple ID id: `E${Date.now()}`, // Generate a simple ID
}); })
onClose(); onClose()
// Reset form // Reset form
setEventData({ setEventData({
title: "", title: '',
type: "plan", type: 'plan',
date: selectedDate || new Date(), date: selectedDate || new Date(),
startTime: getInitialStartTime(), startTime: getInitialStartTime(),
endTime: getInitialEndTime(), endTime: getInitialEndTime(),
status: WorkOrderStatusEnum.Planned, status: WorkOrderStatusEnum.Planned,
priority: PriorityEnum.Normal, priority: PriorityEnum.Normal,
assignedTo: "", assignedTo: '',
workCenterCode: "", workCenterCode: '',
duration: 60, duration: 60,
}); })
setErrors({}); setErrors({})
} }
}; }
const handleInputChange = ( const handleInputChange = (
field: keyof PmCalendarEvent, field: keyof PmCalendarEvent,
value: value: string | Date | PriorityEnum | WorkOrderStatusEnum | 'plan' | 'workorder' | 'scheduled',
| string
| Date
| PriorityEnum
| WorkOrderStatusEnum
| "plan"
| "workorder"
| "scheduled"
) => { ) => {
setEventData((prev) => ({ setEventData((prev) => ({
...prev, ...prev,
[field]: value, [field]: value,
})); }))
// Clear error when user starts typing // Clear error when user starts typing
if (errors[field]) { if (errors[field]) {
setErrors((prev) => ({ setErrors((prev) => ({
...prev, ...prev,
[field]: "", [field]: '',
})); }))
} }
}; }
const generateTimeOptions = () => { const generateTimeOptions = () => {
const options = []; const options = []
for (let hour = 0; hour < 24; hour++) { for (let hour = 0; hour < 24; hour++) {
for (let minute = 0; minute < 60; minute += 30) { for (let minute = 0; minute < 60; minute += 30) {
const timeString = `${hour.toString().padStart(2, "0")}:${minute const timeString = `${hour.toString().padStart(2, '0')}:${minute
.toString() .toString()
.padStart(2, "0")}`; .padStart(2, '0')}`
options.push(timeString); options.push(timeString)
} }
} }
return options; return options
}; }
const timeOptions = generateTimeOptions(); const timeOptions = generateTimeOptions()
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <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-lg mx-4 max-h-[90vh] overflow-y-auto"> <div className="bg-white rounded-lg w-full max-w-lg mx-4 max-h-[90vh] overflow-y-auto">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<h2 className="text-xl font-bold text-gray-900"> <h2 className="text-xl font-bold text-gray-900">Yeni Bakım Planlaması</h2>
Yeni Bakım Planlaması <button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors">
</h2>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors"
>
<FaTimes className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>
@ -208,35 +188,24 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
{/* Basic Info */} {/* Basic Info */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="md:col-span-2"> <div className="md:col-span-2">
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Başlık *</label>
Başlık *
</label>
<input <input
type="text" type="text"
value={eventData.title || ""} value={eventData.title || ''}
onChange={(e) => handleInputChange("title", e.target.value)} onChange={(e) => handleInputChange('title', 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 ${ 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 ${
errors.title ? "border-red-500" : "border-gray-300" errors.title ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Bakım planı başlığı" placeholder="Bakım planı başlığı"
/> />
{errors.title && ( {errors.title && <p className="text-red-500 text-xs mt-1">{errors.title}</p>}
<p className="text-red-500 text-xs mt-1">{errors.title}</p>
)}
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Tip</label>
Tip
</label>
<select <select
value={eventData.type || "plan"} value={eventData.type || 'plan'}
onChange={(e) => onChange={(e) => handleInputChange('type', e.target.value as 'plan' | 'workorder')}
handleInputChange(
"type",
e.target.value as "plan" | "workorder"
)
}
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" 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"
> >
<option value="plan">Bakım Planı</option> <option value="plan">Bakım Planı</option>
@ -245,14 +214,10 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Öncelik</label>
Öncelik
</label>
<select <select
value={eventData.priority || PriorityEnum.Normal} value={eventData.priority || PriorityEnum.Normal}
onChange={(e) => onChange={(e) => handleInputChange('priority', e.target.value as PriorityEnum)}
handleInputChange("priority", e.target.value as PriorityEnum)
}
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" 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"
> >
<option value={PriorityEnum.Low}>Düşük</option> <option value={PriorityEnum.Low}>Düşük</option>
@ -263,16 +228,12 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">İş Merkezi *</label>
İş Merkezi *
</label>
<select <select
value={eventData.workCenterCode || ""} value={eventData.workCenterCode || ''}
onChange={(e) => onChange={(e) => handleInputChange('workCenterCode', e.target.value)}
handleInputChange("workCenterCode", 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 ${ 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 ${
errors.workCenterCode ? "border-red-500" : "border-gray-300" errors.workCenterCode ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
<option value="">İş merkezi seçin</option> <option value="">İş merkezi seçin</option>
@ -283,21 +244,15 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
))} ))}
</select> </select>
{errors.workCenterCode && ( {errors.workCenterCode && (
<p className="text-red-500 text-xs mt-1"> <p className="text-red-500 text-xs mt-1">{errors.workCenterCode}</p>
{errors.workCenterCode}
</p>
)} )}
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Atanan Kişi</label>
Atanan Kişi
</label>
<select <select
value={eventData.assignedTo || ""} value={eventData.assignedTo || ''}
onChange={(e) => onChange={(e) => handleInputChange('assignedTo', e.target.value)}
handleInputChange("assignedTo", e.target.value)
}
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" 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"
> >
<option value="">Kişi seçin</option> <option value="">Kişi seçin</option>
@ -319,10 +274,8 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
</label> </label>
<input <input
type="date" type="date"
value={eventData.date?.toISOString().split("T")[0] || ""} value={eventData.date?.toISOString().split('T')[0] || ''}
onChange={(e) => onChange={(e) => handleInputChange('date', new Date(e.target.value))}
handleInputChange("date", new Date(e.target.value))
}
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" 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"
/> />
</div> </div>
@ -333,10 +286,10 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
Başlangıç Saati * Başlangıç Saati *
</label> </label>
<select <select
value={eventData.startTime || "09:00"} value={eventData.startTime || '09:00'}
onChange={(e) => handleInputChange("startTime", e.target.value)} onChange={(e) => handleInputChange('startTime', 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 ${ 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 ${
errors.startTime ? "border-red-500" : "border-gray-300" errors.startTime ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
{timeOptions.map((time) => ( {timeOptions.map((time) => (
@ -345,20 +298,16 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
</option> </option>
))} ))}
</select> </select>
{errors.startTime && ( {errors.startTime && <p className="text-red-500 text-xs mt-1">{errors.startTime}</p>}
<p className="text-red-500 text-xs mt-1">{errors.startTime}</p>
)}
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Bitiş Saati *</label>
Bitiş Saati *
</label>
<select <select
value={eventData.endTime || "10:00"} value={eventData.endTime || '10:00'}
onChange={(e) => handleInputChange("endTime", e.target.value)} onChange={(e) => handleInputChange('endTime', 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 ${ 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 ${
errors.endTime ? "border-red-500" : "border-gray-300" errors.endTime ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
{timeOptions.map((time) => ( {timeOptions.map((time) => (
@ -367,44 +316,29 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
</option> </option>
))} ))}
</select> </select>
{errors.endTime && ( {errors.endTime && <p className="text-red-500 text-xs mt-1">{errors.endTime}</p>}
<p className="text-red-500 text-xs mt-1">{errors.endTime}</p>
)}
</div> </div>
</div> </div>
{/* Status */} {/* Status */}
{eventData.type === "workorder" && ( {eventData.type === 'workorder' && (
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Durum</label>
Durum
</label>
<select <select
value={eventData.status || "scheduled"} value={eventData.status || 'scheduled'}
onChange={(e) => onChange={(e) =>
handleInputChange( handleInputChange('status', e.target.value as WorkOrderStatusEnum | 'scheduled')
"status",
e.target.value as WorkOrderStatusEnum | "scheduled"
)
} }
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" 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"
> >
<option value="scheduled">Planlanmış</option> <option value="scheduled">Planlanmış</option>
<option value={WorkOrderStatusEnum.Created}>Oluşturuldu</option> <option value={WorkOrderStatusEnum.Created}>Oluşturuldu</option>
<option value={WorkOrderStatusEnum.Planned}>Planlandı</option> <option value={WorkOrderStatusEnum.Planned}>Planlandı</option>
<option value={WorkOrderStatusEnum.Released}> <option value={WorkOrderStatusEnum.Released}>Serbest Bırakıldı</option>
Serbest Bırakıldı <option value={WorkOrderStatusEnum.InProgress}>Devam Ediyor</option>
</option>
<option value={WorkOrderStatusEnum.InProgress}>
Devam Ediyor
</option>
<option value={WorkOrderStatusEnum.OnHold}>Beklemede</option> <option value={WorkOrderStatusEnum.OnHold}>Beklemede</option>
<option value={WorkOrderStatusEnum.Completed}> <option value={WorkOrderStatusEnum.Completed}>Tamamlandı</option>
Tamamlandı <option value={WorkOrderStatusEnum.Cancelled}>İptal Edildi</option>
</option>
<option value={WorkOrderStatusEnum.Cancelled}>
İptal Edildi
</option>
</select> </select>
</div> </div>
)} )}
@ -428,7 +362,7 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default NewCalendarEventModal; export default NewCalendarEventModal

View file

@ -1,19 +1,19 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaSave, FaUpload, FaMinus } from "react-icons/fa"; import { FaTimes, FaSave, FaUpload, FaMinus } from 'react-icons/fa'
import { import {
PmFaultNotification, PmFaultNotification,
FaultTypeEnum, FaultTypeEnum,
CriticalityLevelEnum, CriticalityLevelEnum,
NotificationStatusEnum, NotificationStatusEnum,
} from "../../../types/pm"; } from '../../../types/pm'
import { mockWorkCenters } from "../../../mocks/mockWorkCenters"; import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from '../../../mocks/mockEmployees'
import { PriorityEnum } from "../../../types/common"; import { PriorityEnum } from '../../../types/common'
interface NewFaultNotificationModalProps { interface NewFaultNotificationModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (notification: Partial<PmFaultNotification>) => void; onSave: (notification: Partial<PmFaultNotification>) => void
} }
const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
@ -21,12 +21,8 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
onClose, onClose,
onSave, onSave,
}) => { }) => {
const [notificationData, setNotificationData] = useState< const [notificationData, setNotificationData] = useState<Partial<PmFaultNotification>>({
Partial<PmFaultNotification> notificationCode: `ARZ-${new Date().getFullYear()}-${String(Date.now()).slice(-3)}`,
>({
notificationCode: `ARZ-${new Date().getFullYear()}-${String(
Date.now()
).slice(-3)}`,
faultType: FaultTypeEnum.Mechanical, faultType: FaultTypeEnum.Mechanical,
priority: PriorityEnum.Normal, priority: PriorityEnum.Normal,
severity: CriticalityLevelEnum.Medium, severity: CriticalityLevelEnum.Medium,
@ -34,57 +30,55 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
followUpRequired: false, followUpRequired: false,
isActive: true, isActive: true,
images: [], images: [],
}); })
const [errors, setErrors] = useState<Record<string, string>>({}); const [errors, setErrors] = useState<Record<string, string>>({})
const [uploadedImages, setUploadedImages] = useState<string[]>([]); const [uploadedImages, setUploadedImages] = useState<string[]>([])
if (!isOpen) return null; if (!isOpen) return null
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (!notificationData.workCenterId) { if (!notificationData.workCenterId) {
newErrors.workCenterId = "İş merkezi seçimi gerekli"; newErrors.workCenterId = 'İş merkezi seçimi gerekli'
} }
if (!notificationData.title?.trim()) { if (!notificationData.title?.trim()) {
newErrors.title = "Başlık gerekli"; newErrors.title = 'Başlık gerekli'
} }
if (!notificationData.description?.trim()) { if (!notificationData.description?.trim()) {
newErrors.description = "Açıklama gerekli"; newErrors.description = 'Açıklama gerekli'
} }
if (!notificationData.location?.trim()) { if (!notificationData.location?.trim()) {
newErrors.location = "Konum gerekli"; newErrors.location = 'Konum gerekli'
} }
if (!notificationData.reportedBy?.trim()) { if (!notificationData.reportedBy?.trim()) {
newErrors.reportedBy = "Bildiren kişi gerekli"; newErrors.reportedBy = 'Bildiren kişi gerekli'
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleInputChange = ( const handleInputChange = (
field: keyof PmFaultNotification, field: keyof PmFaultNotification,
value: string | number | boolean | undefined value: string | number | boolean | undefined,
) => { ) => {
setNotificationData((prev) => ({ setNotificationData((prev) => ({
...prev, ...prev,
[field]: value, [field]: value,
})); }))
// Clear error when user starts typing // Clear error when user starts typing
if (errors[field]) { if (errors[field]) {
setErrors((prev) => ({ setErrors((prev) => ({
...prev, ...prev,
[field]: "", [field]: '',
})); }))
} }
}; }
const handleWorkCenterChange = (workCenterId: string) => { const handleWorkCenterChange = (workCenterId: string) => {
const selectedWorkCenter = mockWorkCenters.find( const selectedWorkCenter = mockWorkCenters.find((eq) => eq.id === workCenterId)
(eq) => eq.id === workCenterId
);
if (selectedWorkCenter) { if (selectedWorkCenter) {
setNotificationData((prev) => ({ setNotificationData((prev) => ({
...prev, ...prev,
@ -92,29 +86,29 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
workCenterCode: selectedWorkCenter.code, workCenterCode: selectedWorkCenter.code,
workCenterName: selectedWorkCenter.name, workCenterName: selectedWorkCenter.name,
location: selectedWorkCenter.location, location: selectedWorkCenter.location,
})); }))
} }
}; }
const handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => { const handleImageUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const files = event.target.files; const files = event.target.files
if (files) { if (files) {
const imageNames = Array.from(files).map((file) => file.name); const imageNames = Array.from(files).map((file) => file.name)
setUploadedImages((prev) => [...prev, ...imageNames]); setUploadedImages((prev) => [...prev, ...imageNames])
setNotificationData((prev) => ({ setNotificationData((prev) => ({
...prev, ...prev,
images: [...(prev.images || []), ...imageNames], images: [...(prev.images || []), ...imageNames],
})); }))
} }
}; }
const removeImage = (index: number) => { const removeImage = (index: number) => {
setUploadedImages((prev) => prev.filter((_, i) => i !== index)); setUploadedImages((prev) => prev.filter((_, i) => i !== index))
setNotificationData((prev) => ({ setNotificationData((prev) => ({
...prev, ...prev,
images: prev.images?.filter((_, i) => i !== index) || [], images: prev.images?.filter((_, i) => i !== index) || [],
})); }))
}; }
const handleSave = () => { const handleSave = () => {
if (validateForm()) { if (validateForm()) {
@ -124,16 +118,14 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
reportedAt: new Date(), reportedAt: new Date(),
creationTime: new Date(), creationTime: new Date(),
lastModificationTime: new Date(), lastModificationTime: new Date(),
}; }
onSave(notificationToSave); onSave(notificationToSave)
onClose(); onClose()
// Reset form // Reset form
setNotificationData({ setNotificationData({
notificationCode: `ARZ-${new Date().getFullYear()}-${String( notificationCode: `ARZ-${new Date().getFullYear()}-${String(Date.now()).slice(-3)}`,
Date.now()
).slice(-3)}`,
faultType: FaultTypeEnum.Mechanical, faultType: FaultTypeEnum.Mechanical,
priority: PriorityEnum.Normal, priority: PriorityEnum.Normal,
severity: CriticalityLevelEnum.Medium, severity: CriticalityLevelEnum.Medium,
@ -141,24 +133,19 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
followUpRequired: false, followUpRequired: false,
isActive: true, isActive: true,
images: [], images: [],
}); })
setUploadedImages([]); setUploadedImages([])
setErrors({}); setErrors({})
} }
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <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"> <div className="bg-white rounded-lg w-full max-w-3xl max-h-[90vh] overflow-y-auto">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<h2 className="text-xl font-bold text-gray-900"> <h2 className="text-xl font-bold text-gray-900">Yeni Arıza Bildirimi</h2>
Yeni Arıza Bildirimi <button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors">
</h2>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors"
>
<FaTimes className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>
@ -173,24 +160,20 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
</label> </label>
<input <input
type="text" type="text"
value={notificationData.notificationCode || ""} value={notificationData.notificationCode || ''}
onChange={(e) => onChange={(e) => handleInputChange('notificationCode', e.target.value)}
handleInputChange("notificationCode", e.target.value)
}
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" 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" placeholder="ARZ-2024-001"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">İş Merkezi *</label>
İş Merkezi *
</label>
<select <select
value={notificationData.workCenterId || ""} value={notificationData.workCenterId || ''}
onChange={(e) => handleWorkCenterChange(e.target.value)} 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 ${ 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 ${
errors.workCenterId ? "border-red-500" : "border-gray-300" errors.workCenterId ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
<option value="">İş merkezi seçin</option> <option value="">İş merkezi seçin</option>
@ -201,9 +184,7 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
))} ))}
</select> </select>
{errors.workCenterId && ( {errors.workCenterId && (
<p className="text-red-500 text-xs mt-1"> <p className="text-red-500 text-xs mt-1">{errors.workCenterId}</p>
{errors.workCenterId}
</p>
)} )}
</div> </div>
</div> </div>
@ -216,16 +197,14 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
</label> </label>
<input <input
type="text" type="text"
value={notificationData.title || ""} value={notificationData.title || ''}
onChange={(e) => handleInputChange("title", e.target.value)} onChange={(e) => handleInputChange('title', 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 ${ 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 ${
errors.title ? "border-red-500" : "border-gray-300" errors.title ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Arıza başlığı" placeholder="Arıza başlığı"
/> />
{errors.title && ( {errors.title && <p className="text-red-500 text-xs mt-1">{errors.title}</p>}
<p className="text-red-500 text-xs mt-1">{errors.title}</p>
)}
</div> </div>
<div> <div>
@ -233,20 +212,16 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
Detaylı ıklama * Detaylı ıklama *
</label> </label>
<textarea <textarea
value={notificationData.description || ""} value={notificationData.description || ''}
onChange={(e) => onChange={(e) => handleInputChange('description', e.target.value)}
handleInputChange("description", e.target.value)
}
rows={2} 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 ${ 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 ${
errors.description ? "border-red-500" : "border-gray-300" errors.description ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Arızanın detaylııklaması, belirtiler ve gözlemler" placeholder="Arızanın detaylııklaması, belirtiler ve gözlemler"
/> />
{errors.description && ( {errors.description && (
<p className="text-red-500 text-xs mt-1"> <p className="text-red-500 text-xs mt-1">{errors.description}</p>
{errors.description}
</p>
)} )}
</div> </div>
</div> </div>
@ -254,21 +229,17 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
{/* Location and Reporter */} {/* Location and Reporter */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Konum *</label>
Konum *
</label>
<input <input
type="text" type="text"
value={notificationData.location || ""} value={notificationData.location || ''}
onChange={(e) => handleInputChange("location", e.target.value)} onChange={(e) => handleInputChange('location', 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 ${ 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 ${
errors.location ? "border-red-500" : "border-gray-300" errors.location ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Atölye A - Hat 1" placeholder="Atölye A - Hat 1"
/> />
{errors.location && ( {errors.location && <p className="text-red-500 text-xs mt-1">{errors.location}</p>}
<p className="text-red-500 text-xs mt-1">{errors.location}</p>
)}
</div> </div>
<div> <div>
@ -276,12 +247,10 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
Bildiren Kişi * Bildiren Kişi *
</label> </label>
<select <select
value={notificationData.reportedBy || ""} value={notificationData.reportedBy || ''}
onChange={(e) => onChange={(e) => handleInputChange('reportedBy', e.target.value)}
handleInputChange("reportedBy", 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 ${ 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 ${
errors.reportedBy ? "border-red-500" : "border-gray-300" errors.reportedBy ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
<option value="">Bildiren kişi seçin</option> <option value="">Bildiren kişi seçin</option>
@ -299,17 +268,10 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
<div className="grid grid-cols-1 md:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Arıza Türü</label>
Arıza Türü
</label>
<select <select
value={notificationData.faultType || FaultTypeEnum.Mechanical} value={notificationData.faultType || FaultTypeEnum.Mechanical}
onChange={(e) => onChange={(e) => handleInputChange('faultType', e.target.value as FaultTypeEnum)}
handleInputChange(
"faultType",
e.target.value as FaultTypeEnum
)
}
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" 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"
> >
<option value={FaultTypeEnum.Mechanical}>Mekanik</option> <option value={FaultTypeEnum.Mechanical}>Mekanik</option>
@ -324,14 +286,10 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Öncelik</label>
Öncelik
</label>
<select <select
value={notificationData.priority || PriorityEnum.Normal} value={notificationData.priority || PriorityEnum.Normal}
onChange={(e) => onChange={(e) => handleInputChange('priority', e.target.value as PriorityEnum)}
handleInputChange("priority", e.target.value as PriorityEnum)
}
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" 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"
> >
<option value={PriorityEnum.Low}>Düşük</option> <option value={PriorityEnum.Low}>Düşük</option>
@ -342,16 +300,11 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Kritiklik</label>
Kritiklik
</label>
<select <select
value={notificationData.severity || CriticalityLevelEnum.Medium} value={notificationData.severity || CriticalityLevelEnum.Medium}
onChange={(e) => onChange={(e) =>
handleInputChange( handleInputChange('severity', e.target.value as CriticalityLevelEnum)
"severity",
e.target.value as CriticalityLevelEnum
)
} }
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" 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"
> >
@ -371,12 +324,9 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
</label> </label>
<input <input
type="number" type="number"
value={notificationData.estimatedRepairTime || ""} value={notificationData.estimatedRepairTime || ''}
onChange={(e) => onChange={(e) =>
handleInputChange( handleInputChange('estimatedRepairTime', parseInt(e.target.value) || undefined)
"estimatedRepairTime",
parseInt(e.target.value) || undefined
)
} }
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" 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" placeholder="120"
@ -389,23 +339,17 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
<input <input
type="checkbox" type="checkbox"
checked={notificationData.followUpRequired || false} checked={notificationData.followUpRequired || false}
onChange={(e) => onChange={(e) => handleInputChange('followUpRequired', e.target.checked)}
handleInputChange("followUpRequired", e.target.checked)
}
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50" className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
/> />
<span className="ml-2 text-sm text-gray-700"> <span className="ml-2 text-sm text-gray-700">Takip gerekli</span>
Takip gerekli
</span>
</label> </label>
</div> </div>
</div> </div>
{/* Image Upload */} {/* Image Upload */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Fotoğraflar</label>
Fotoğraflar
</label>
<div className="border-2 border-dashed border-gray-300 rounded-lg p-4"> <div className="border-2 border-dashed border-gray-300 rounded-lg p-4">
<div className="text-center"> <div className="text-center">
<FaUpload className="mx-auto h-10 w-10 text-gray-400" /> <FaUpload className="mx-auto h-10 w-10 text-gray-400" />
@ -433,9 +377,7 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
{uploadedImages.length > 0 && ( {uploadedImages.length > 0 && (
<div className="mt-4"> <div className="mt-4">
<h4 className="text-sm font-medium text-gray-700 mb-1"> <h4 className="text-sm font-medium text-gray-700 mb-1">Yüklenen Fotoğraflar:</h4>
Yüklenen Fotoğraflar:
</h4>
<div className="space-y-2"> <div className="space-y-2">
{uploadedImages.map((image, index) => ( {uploadedImages.map((image, index) => (
<div <div
@ -476,7 +418,7 @@ const NewFaultNotificationModal: React.FC<NewFaultNotificationModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default NewFaultNotificationModal; export default NewFaultNotificationModal

View file

@ -1,109 +1,93 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaSave, FaPlus, FaMinus } from "react-icons/fa"; import { FaTimes, FaSave, FaPlus, FaMinus } from 'react-icons/fa'
import { import {
PmMaintenancePlan, PmMaintenancePlan,
MaintenancePlanTypeEnum, MaintenancePlanTypeEnum,
FrequencyUnitEnum, FrequencyUnitEnum,
PmPlanMaterial, PmPlanMaterial,
} from "../../../types/pm"; } from '../../../types/pm'
import { mockWorkCenters } from "../../../mocks/mockWorkCenters"; import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
import { mockMaterials } from "../../../mocks/mockMaterials"; import { mockMaterials } from '../../../mocks/mockMaterials'
import { mockUnits } from "../../../mocks/mockUnits"; import { mockUnits } from '../../../mocks/mockUnits'
import { PriorityEnum } from "../../../types/common"; import { PriorityEnum } from '../../../types/common'
interface NewMaintenancePlanModalProps { interface NewMaintenancePlanModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (plan: Partial<PmMaintenancePlan>) => void; onSave: (plan: Partial<PmMaintenancePlan>) => void
} }
const initialPlan: Partial<PmMaintenancePlan> = { const initialPlan: Partial<PmMaintenancePlan> = {
planCode: "", planCode: '',
workCenterId: "", workCenterId: '',
planType: MaintenancePlanTypeEnum.Preventive, planType: MaintenancePlanTypeEnum.Preventive,
description: "", description: '',
frequency: 1, frequency: 1,
frequencyUnit: FrequencyUnitEnum.Months, frequencyUnit: FrequencyUnitEnum.Months,
estimatedDuration: 60, estimatedDuration: 60,
priority: PriorityEnum.Normal, priority: PriorityEnum.Normal,
instructions: "", instructions: '',
requiredMaterials: [], requiredMaterials: [],
requiredSkills: [], requiredSkills: [],
nextDue: new Date(), nextDue: new Date(),
isActive: true, isActive: true,
}; }
const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
isOpen, isOpen,
onClose, onClose,
onSave, onSave,
}) => { }) => {
const [planData, setPlanData] = const [planData, setPlanData] = useState<Partial<PmMaintenancePlan>>(initialPlan)
useState<Partial<PmMaintenancePlan>>(initialPlan); const [requiredSkills, setRequiredSkills] = useState<string[]>([])
const [requiredSkills, setRequiredSkills] = useState<string[]>([]); const [requiredMaterials, setRequiredMaterials] = useState<PmPlanMaterial[]>([])
const [requiredMaterials, setRequiredMaterials] = useState<PmPlanMaterial[]>( const [newSkill, setNewSkill] = useState('')
[]
);
const [newSkill, setNewSkill] = useState("");
if (!isOpen) return null; if (!isOpen) return null
const handleInputChange = ( const handleInputChange = (
e: React.ChangeEvent< e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>,
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
>
) => { ) => {
const { name, value, type } = e.target; const { name, value, type } = e.target
setPlanData((prev) => ({ setPlanData((prev) => ({
...prev, ...prev,
[name]: [name]: type === 'date' ? new Date(value) : type === 'number' ? Number(value) : value,
type === "date" }))
? new Date(value) }
: type === "number"
? Number(value)
: value,
}));
};
const addSkill = () => { const addSkill = () => {
if (newSkill.trim() && !requiredSkills.includes(newSkill.trim())) { if (newSkill.trim() && !requiredSkills.includes(newSkill.trim())) {
setRequiredSkills([...requiredSkills, newSkill.trim()]); setRequiredSkills([...requiredSkills, newSkill.trim()])
setNewSkill(""); setNewSkill('')
} }
}; }
const removeSkill = (skillToRemove: string) => { const removeSkill = (skillToRemove: string) => {
setRequiredSkills( setRequiredSkills(requiredSkills.filter((skill) => skill !== skillToRemove))
requiredSkills.filter((skill) => skill !== skillToRemove) }
);
};
const addMaterial = () => { const addMaterial = () => {
const newMaterial: PmPlanMaterial = { const newMaterial: PmPlanMaterial = {
id: `MAT${Date.now()}`, id: `MAT${Date.now()}`,
planId: "", planId: '',
materialId: "", materialId: '',
quantity: 1, quantity: 1,
unitId: "", unitId: '',
isRequired: true, isRequired: true,
}; }
setRequiredMaterials([...requiredMaterials, newMaterial]); setRequiredMaterials([...requiredMaterials, newMaterial])
}; }
const removeMaterial = (index: number) => { const removeMaterial = (index: number) => {
setRequiredMaterials(requiredMaterials.filter((_, i) => i !== index)); setRequiredMaterials(requiredMaterials.filter((_, i) => i !== index))
}; }
const updateMaterial = ( const updateMaterial = (index: number, field: string, value: string | number | boolean) => {
index: number,
field: string,
value: string | number | boolean
) => {
const updated = requiredMaterials.map((material, i) => const updated = requiredMaterials.map((material, i) =>
i === index ? { ...material, [field]: value } : material i === index ? { ...material, [field]: value } : material,
); )
setRequiredMaterials(updated); setRequiredMaterials(updated)
}; }
const handleSave = () => { const handleSave = () => {
const planToSave = { const planToSave = {
@ -112,26 +96,21 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
requiredMaterials, requiredMaterials,
creationTime: new Date(), creationTime: new Date(),
lastModificationTime: new Date(), lastModificationTime: new Date(),
}; }
onSave(planToSave); onSave(planToSave)
setPlanData(initialPlan); setPlanData(initialPlan)
setRequiredSkills([]); setRequiredSkills([])
setRequiredMaterials([]); setRequiredMaterials([])
onClose(); onClose()
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <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-4xl mx-4 max-h-[90vh] overflow-y-auto"> <div className="bg-white rounded-lg w-full max-w-4xl mx-4 max-h-[90vh] overflow-y-auto">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">Yeni Bakım Planı</h2>
Yeni Bakım Planı <button onClick={onClose} className="p-1 hover:bg-gray-100 rounded-lg transition-colors">
</h2>
<button
onClick={onClose}
className="p-1 hover:bg-gray-100 rounded-lg transition-colors"
>
<FaTimes className="w-4 h-4 text-gray-500" /> <FaTimes className="w-4 h-4 text-gray-500" />
</button> </button>
</div> </div>
@ -140,18 +119,14 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
<div className="p-4 space-y-4"> <div className="p-4 space-y-4">
{/* Basic Information */} {/* Basic Information */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-3"> <h3 className="text-base font-medium text-gray-900 mb-3">Temel Bilgiler</h3>
Temel Bilgiler
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Plan Kodu *</label>
Plan Kodu *
</label>
<input <input
type="text" type="text"
name="planCode" name="planCode"
value={planData.planCode || ""} value={planData.planCode || ''}
onChange={handleInputChange} onChange={handleInputChange}
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" 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="örn: PM-CNC-001" placeholder="örn: PM-CNC-001"
@ -159,12 +134,10 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">İş Merkezi *</label>
İş Merkezi *
</label>
<select <select
name="workCenterId" name="workCenterId"
value={planData.workCenterId || ""} value={planData.workCenterId || ''}
onChange={handleInputChange} onChange={handleInputChange}
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" 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"
required required
@ -178,35 +151,21 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Plan Tipi *</label>
Plan Tipi *
</label>
<select <select
name="planType" name="planType"
value={ value={planData.planType || MaintenancePlanTypeEnum.Preventive}
planData.planType || MaintenancePlanTypeEnum.Preventive
}
onChange={handleInputChange} onChange={handleInputChange}
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" 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"
> >
<option value={MaintenancePlanTypeEnum.Preventive}> <option value={MaintenancePlanTypeEnum.Preventive}>Önleyici Bakım</option>
Önleyici Bakım <option value={MaintenancePlanTypeEnum.Predictive}>Kestirimci Bakım</option>
</option> <option value={MaintenancePlanTypeEnum.Corrective}>Düzeltici Bakım</option>
<option value={MaintenancePlanTypeEnum.Predictive}> <option value={MaintenancePlanTypeEnum.Condition}>Durum Bazlı Bakım</option>
Kestirimci Bakım
</option>
<option value={MaintenancePlanTypeEnum.Corrective}>
Düzeltici Bakım
</option>
<option value={MaintenancePlanTypeEnum.Condition}>
Durum Bazlı Bakım
</option>
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Öncelik</label>
Öncelik
</label>
<select <select
name="priority" name="priority"
value={planData.priority || PriorityEnum.Normal} value={planData.priority || PriorityEnum.Normal}
@ -220,12 +179,10 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
</select> </select>
</div> </div>
<div className="md:col-span-2"> <div className="md:col-span-2">
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">ıklama *</label>
ıklama *
</label>
<textarea <textarea
name="description" name="description"
value={planData.description || ""} value={planData.description || ''}
onChange={handleInputChange} onChange={handleInputChange}
rows={2} rows={2}
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" 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"
@ -238,14 +195,10 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
{/* Frequency Settings */} {/* Frequency Settings */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-3"> <h3 className="text-base font-medium text-gray-900 mb-3">Sıklık Ayarları</h3>
Sıklık Ayarları
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Sıklık *</label>
Sıklık *
</label>
<input <input
type="number" type="number"
name="frequency" name="frequency"
@ -295,11 +248,7 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
<input <input
type="date" type="date"
name="nextDue" name="nextDue"
value={ value={planData.nextDue ? planData.nextDue.toISOString().split('T')[0] : ''}
planData.nextDue
? planData.nextDue.toISOString().split("T")[0]
: ""
}
onChange={handleInputChange} onChange={handleInputChange}
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" 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"
/> />
@ -309,12 +258,10 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
{/* Instructions */} {/* Instructions */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-3"> <h3 className="text-base font-medium text-gray-900 mb-3">Bakım Talimatları</h3>
Bakım Talimatları
</h3>
<textarea <textarea
name="instructions" name="instructions"
value={planData.instructions || ""} value={planData.instructions || ''}
onChange={handleInputChange} onChange={handleInputChange}
rows={3} rows={3}
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" 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"
@ -325,9 +272,7 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
{/* Required Skills */} {/* Required Skills */}
<div> <div>
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
<h3 className="text-base font-medium text-gray-900"> <h3 className="text-base font-medium text-gray-900">Gerekli Yetenekler</h3>
Gerekli Yetenekler
</h3>
<div className="flex space-x-1.5"> <div className="flex space-x-1.5">
<input <input
type="text" type="text"
@ -335,7 +280,7 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
onChange={(e) => setNewSkill(e.target.value)} onChange={(e) => setNewSkill(e.target.value)}
placeholder="Yetenek ekle..." placeholder="Yetenek ekle..."
className="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" className="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"
onKeyPress={(e) => e.key === "Enter" && addSkill()} onKeyPress={(e) => e.key === 'Enter' && addSkill()}
/> />
<button <button
type="button" type="button"
@ -368,9 +313,7 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
{/* Required Materials */} {/* Required Materials */}
<div> <div>
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
<h3 className="text-base font-medium text-gray-900"> <h3 className="text-base font-medium text-gray-900">Gerekli Malzemeler</h3>
Gerekli Malzemeler
</h3>
<button <button
type="button" type="button"
onClick={addMaterial} onClick={addMaterial}
@ -382,23 +325,14 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
</div> </div>
<div className="space-y-3"> <div className="space-y-3">
{requiredMaterials.map((material, index) => ( {requiredMaterials.map((material, index) => (
<div <div key={index} className="flex items-center space-x-2 p-2 bg-gray-50 rounded-lg">
key={index}
className="flex items-center space-x-2 p-2 bg-gray-50 rounded-lg"
>
<select <select
value={material.materialId} value={material.materialId}
onChange={(e) => { onChange={(e) => {
const selectedMaterial = mockMaterials.find( const selectedMaterial = mockMaterials.find((m) => m.id === e.target.value)
(m) => m.id === e.target.value updateMaterial(index, 'materialId', e.target.value)
);
updateMaterial(index, "materialId", e.target.value);
if (selectedMaterial) { if (selectedMaterial) {
updateMaterial( updateMaterial(index, 'unitId', selectedMaterial.baseUnitId)
index,
"unitId",
selectedMaterial.baseUnitId
);
} }
}} }}
className="flex-1 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" className="flex-1 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"
@ -413,18 +347,14 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
<input <input
type="number" type="number"
value={material.quantity} value={material.quantity}
onChange={(e) => onChange={(e) => updateMaterial(index, 'quantity', Number(e.target.value))}
updateMaterial(index, "quantity", Number(e.target.value))
}
placeholder="Miktar" placeholder="Miktar"
min="1" min="1"
className="w-20 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" className="w-20 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"
/> />
<select <select
value={material.unitId} value={material.unitId}
onChange={(e) => onChange={(e) => updateMaterial(index, 'unitId', e.target.value)}
updateMaterial(index, "unitId", e.target.value)
}
className="w-24 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" className="w-24 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"
> >
<option value="">Birim</option> <option value="">Birim</option>
@ -437,32 +367,25 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
{material.materialId && {material.materialId &&
(() => { (() => {
const selectedMaterial = mockMaterials.find( const selectedMaterial = mockMaterials.find(
(m) => m.id === material.materialId (m) => m.id === material.materialId,
); )
const baseUnitCode = selectedMaterial?.baseUnit; const baseUnitCode = selectedMaterial?.baseUnit
const existsInList = mockUnits.some( const existsInList = mockUnits.some((unit) => unit.id === baseUnitCode?.id)
(unit) => unit.id === baseUnitCode?.id
);
if (baseUnitCode && !existsInList) { if (baseUnitCode && !existsInList) {
return ( return (
<option <option key={baseUnitCode.id} value={baseUnitCode.id}>
key={baseUnitCode.id}
value={baseUnitCode.id}
>
{baseUnitCode.code} {baseUnitCode.code}
</option> </option>
); )
} }
return null; return null
})()} })()}
</select> </select>
<label className="flex items-center space-x-2"> <label className="flex items-center space-x-2">
<input <input
type="checkbox" type="checkbox"
checked={material.isRequired} checked={material.isRequired}
onChange={(e) => onChange={(e) => updateMaterial(index, 'isRequired', e.target.checked)}
updateMaterial(index, "isRequired", e.target.checked)
}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/> />
<span className="text-sm text-gray-700">Zorunlu</span> <span className="text-sm text-gray-700">Zorunlu</span>
@ -478,8 +401,8 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
))} ))}
{requiredMaterials.length === 0 && ( {requiredMaterials.length === 0 && (
<p className="text-gray-500 text-center py-4"> <p className="text-gray-500 text-center py-4">
Henüz malzeme eklenmedi. "Malzeme Ekle" butonunu kullanarak Henüz malzeme eklenmedi. "Malzeme Ekle" butonunu kullanarak malzeme
malzeme ekleyebilirsiniz. ekleyebilirsiniz.
</p> </p>
)} )}
</div> </div>
@ -506,7 +429,7 @@ const NewMaintenancePlanModal: React.FC<NewMaintenancePlanModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default NewMaintenancePlanModal; export default NewMaintenancePlanModal

View file

@ -1,170 +1,151 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaSave, FaPlus, FaMinus } from "react-icons/fa"; import { FaTimes, FaSave, FaPlus, FaMinus } from 'react-icons/fa'
import { TeamRoleEnum } from "../../../types/common"; import { TeamRoleEnum } from '../../../types/common'
import MultiSelectEmployee from "../../../components/common/MultiSelectEmployee"; import MultiSelectEmployee from '../../../components/common/MultiSelectEmployee'
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from '../../../mocks/mockEmployees'
import { Team, TeamMember } from "../../../types/common"; import { Team, TeamMember } from '../../../types/common'
interface NewTeamModalProps { interface NewTeamModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (team: Partial<Team>) => void; onSave: (team: Partial<Team>) => void
} }
const NewTeamModal: React.FC<NewTeamModalProps> = ({ const NewTeamModal: React.FC<NewTeamModalProps> = ({ isOpen, onClose, onSave }) => {
isOpen,
onClose,
onSave,
}) => {
const [teamData, setTeamData] = useState<Partial<Team>>({ const [teamData, setTeamData] = useState<Partial<Team>>({
code: "", code: '',
name: "", name: '',
description: "", description: '',
isActive: true, isActive: true,
specializations: [], specializations: [],
members: [], members: [],
}); })
const [selectedEmployees, setSelectedEmployees] = useState<string[]>([]); const [selectedEmployees, setSelectedEmployees] = useState<string[]>([])
const [newSpecialization, setNewSpecialization] = useState(""); const [newSpecialization, setNewSpecialization] = useState('')
const [errors, setErrors] = useState<Record<string, string>>({}); const [errors, setErrors] = useState<Record<string, string>>({})
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (!teamData.code?.trim()) { if (!teamData.code?.trim()) {
newErrors.teamCode = "Ekip kodu gerekli"; newErrors.teamCode = 'Ekip kodu gerekli'
} }
if (!teamData.name?.trim()) { if (!teamData.name?.trim()) {
newErrors.teamName = "Ekip adı gerekli"; newErrors.teamName = 'Ekip adı gerekli'
} }
if (!teamData.description?.trim()) { if (!teamData.description?.trim()) {
newErrors.description = "Açıklama gerekli"; newErrors.description = 'Açıklama gerekli'
} }
if (!teamData.managerId) { if (!teamData.managerId) {
newErrors.managerId = "Ekip yöneticisi seçilmeli"; newErrors.managerId = 'Ekip yöneticisi seçilmeli'
} }
if (selectedEmployees.length === 0) { if (selectedEmployees.length === 0) {
newErrors.members = "En az bir ekip üyesi seçilmeli"; newErrors.members = 'En az bir ekip üyesi seçilmeli'
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleInputChange = ( const handleInputChange = (field: keyof Team, value: string | boolean | string[]) => {
field: keyof Team,
value: string | boolean | string[]
) => {
setTeamData((prev) => ({ setTeamData((prev) => ({
...prev, ...prev,
[field]: value, [field]: value,
})); }))
// Clear error when user starts typing // Clear error when user starts typing
if (errors[field]) { if (errors[field]) {
setErrors((prev) => ({ setErrors((prev) => ({
...prev, ...prev,
[field]: "", [field]: '',
})); }))
} }
}; }
const addSpecialization = () => { const addSpecialization = () => {
if ( if (newSpecialization.trim() && !teamData.specializations?.includes(newSpecialization.trim())) {
newSpecialization.trim() &&
!teamData.specializations?.includes(newSpecialization.trim())
) {
setTeamData((prev) => ({ setTeamData((prev) => ({
...prev, ...prev,
specializations: [ specializations: [...(prev.specializations || []), newSpecialization.trim()],
...(prev.specializations || []), }))
newSpecialization.trim(), setNewSpecialization('')
],
}));
setNewSpecialization("");
} }
}; }
const removeSpecialization = (index: number) => { const removeSpecialization = (index: number) => {
setTeamData((prev) => ({ setTeamData((prev) => ({
...prev, ...prev,
specializations: specializations: prev.specializations?.filter((_, i) => i !== index) || [],
prev.specializations?.filter((_, i) => i !== index) || [], }))
})); }
};
const handleEmployeeSelection = (employees: string[]) => { const handleEmployeeSelection = (employees: string[]) => {
setSelectedEmployees(employees); setSelectedEmployees(employees)
if (errors.members) { if (errors.members) {
setErrors((prev) => ({ setErrors((prev) => ({
...prev, ...prev,
members: "", members: '',
})); }))
} }
}; }
const handleMemberRoleChange = (employeeName: string, role: TeamRoleEnum) => { const handleMemberRoleChange = (employeeName: string, role: TeamRoleEnum) => {
const employee = mockEmployees.find((emp) => emp.fullName === employeeName); const employee = mockEmployees.find((emp) => emp.fullName === employeeName)
if (role === TeamRoleEnum.Lead && employee) { if (role === TeamRoleEnum.Lead && employee) {
handleInputChange("managerId", employee.id); handleInputChange('managerId', employee.id)
} }
}; }
const handleSave = () => { const handleSave = () => {
if (validateForm()) { if (validateForm()) {
const members: TeamMember[] = selectedEmployees.map( const members: TeamMember[] = selectedEmployees.map((employeeName, index) => {
(employeeName, index) => { const employee = mockEmployees.find((emp) => emp.fullName === employeeName)
const employee = mockEmployees.find( const isLeader = index === 0 // First selected employee becomes leader
(emp) => emp.fullName === employeeName
);
const isLeader = index === 0; // First selected employee becomes leader
return { return {
id: `TM${Date.now()}-${index}`, id: `TM${Date.now()}-${index}`,
teamId: "", teamId: '',
employeeId: employee?.id || "", employeeId: employee?.id || '',
employee: employee, employee: employee,
role: isLeader ? TeamRoleEnum.Lead : TeamRoleEnum.Member, role: isLeader ? TeamRoleEnum.Lead : TeamRoleEnum.Member,
joinDate: new Date(), joinDate: new Date(),
isActive: true, isActive: true,
};
} }
); })
const teamId = `MT${Date.now()}`; const teamId = `MT${Date.now()}`
// Update members with the teamId // Update members with the teamId
members.forEach((member) => { members.forEach((member) => {
member.teamId = teamId; member.teamId = teamId
}); })
const teamToSave: Partial<Team> = { const teamToSave: Partial<Team> = {
...teamData, ...teamData,
id: teamId, id: teamId,
managerId: members.find((m) => m.role === TeamRoleEnum.Lead) managerId: members.find((m) => m.role === TeamRoleEnum.Lead)?.employeeId,
?.employeeId,
members, members,
creationTime: new Date(), creationTime: new Date(),
lastModificationTime: new Date(), lastModificationTime: new Date(),
}; }
onSave(teamToSave); onSave(teamToSave)
onClose(); onClose()
// Reset form // Reset form
setTeamData({ setTeamData({
code: "", code: '',
name: "", name: '',
description: "", description: '',
isActive: true, isActive: true,
specializations: [], specializations: [],
members: [], members: [],
}); })
setSelectedEmployees([]); setSelectedEmployees([])
setNewSpecialization(""); setNewSpecialization('')
setErrors({}); setErrors({})
} }
}; }
return ( return (
isOpen && ( isOpen && (
@ -172,9 +153,7 @@ const NewTeamModal: React.FC<NewTeamModalProps> = ({
<div className="bg-white rounded-lg w-full max-w-3xl max-h-[90vh] overflow-y-auto"> <div className="bg-white rounded-lg w-full max-w-3xl max-h-[90vh] overflow-y-auto">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">Yeni Ekip Oluştur</h2>
Yeni Ekip Oluştur
</h2>
<button <button
onClick={onClose} onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors" className="text-gray-400 hover:text-gray-600 transition-colors"
@ -188,91 +167,69 @@ const NewTeamModal: React.FC<NewTeamModalProps> = ({
{/* Basic Info */} {/* Basic Info */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Ekip Kodu *</label>
Ekip Kodu *
</label>
<input <input
type="text" type="text"
value={teamData.code || ""} value={teamData.code || ''}
onChange={(e) => handleInputChange("code", e.target.value)} onChange={(e) => handleInputChange('code', 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 ${ 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 ${
errors.code ? "border-red-500" : "border-gray-300" errors.code ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="MEC-001" placeholder="MEC-001"
/> />
{errors.code && ( {errors.code && <p className="text-red-500 text-xs mt-1">{errors.code}</p>}
<p className="text-red-500 text-xs mt-1">{errors.code}</p>
)}
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Ekip Adı *</label>
Ekip Adı *
</label>
<input <input
type="text" type="text"
value={teamData.name || ""} value={teamData.name || ''}
onChange={(e) => handleInputChange("name", e.target.value)} onChange={(e) => handleInputChange('name', 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 ${ 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 ${
errors.name ? "border-red-500" : "border-gray-300" errors.name ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Mekanik Bakım Ekibi" placeholder="Mekanik Bakım Ekibi"
/> />
{errors.name && ( {errors.name && <p className="text-red-500 text-xs mt-1">{errors.name}</p>}
<p className="text-red-500 text-xs mt-1">{errors.name}</p>
)}
</div> </div>
</div> </div>
{/* Description */} {/* Description */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">ıklama *</label>
ıklama *
</label>
<textarea <textarea
value={teamData.description || ""} value={teamData.description || ''}
onChange={(e) => onChange={(e) => handleInputChange('description', e.target.value)}
handleInputChange("description", e.target.value)
}
rows={2} 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 ${ 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 ${
errors.description ? "border-red-500" : "border-gray-300" errors.description ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Ekip açıklaması ve sorumlulukları" placeholder="Ekip açıklaması ve sorumlulukları"
/> />
{errors.description && ( {errors.description && (
<p className="text-red-500 text-xs mt-1"> <p className="text-red-500 text-xs mt-1">{errors.description}</p>
{errors.description}
</p>
)} )}
</div> </div>
{/* Team Members */} {/* Team Members */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Ekip Üyeleri *</label>
Ekip Üyeleri *
</label>
<MultiSelectEmployee <MultiSelectEmployee
selectedEmployees={selectedEmployees} selectedEmployees={selectedEmployees}
onChange={handleEmployeeSelection} onChange={handleEmployeeSelection}
placeholder="Ekip üyelerini seçin" placeholder="Ekip üyelerini seçin"
className={errors.members ? "border-red-500" : ""} className={errors.members ? 'border-red-500' : ''}
/> />
{errors.members && ( {errors.members && <p className="text-red-500 text-xs mt-1">{errors.members}</p>}
<p className="text-red-500 text-xs mt-1">{errors.members}</p>
)}
{/* Selected Members Display */} {/* Selected Members Display */}
{selectedEmployees.length > 0 && ( {selectedEmployees.length > 0 && (
<div className="mt-3 p-3 bg-gray-50 rounded-lg"> <div className="mt-3 p-3 bg-gray-50 rounded-lg">
<h4 className="text-sm font-medium text-gray-700 mb-2"> <h4 className="text-sm font-medium text-gray-700 mb-2">Seçili Ekip Üyeleri:</h4>
Seçili Ekip Üyeleri:
</h4>
<div className="space-y-1.5"> <div className="space-y-1.5">
{selectedEmployees.map((employeeName, index) => { {selectedEmployees.map((employeeName, index) => {
const employee = mockEmployees.find( const employee = mockEmployees.find((emp) => emp.fullName === employeeName)
(emp) => emp.fullName === employeeName
);
return ( return (
<div <div
key={index} key={index}
@ -286,12 +243,8 @@ const NewTeamModal: React.FC<NewTeamModalProps> = ({
</span> </span>
</div> </div>
<div> <div>
<p className="text-sm font-medium text-gray-900"> <p className="text-sm font-medium text-gray-900">{employeeName}</p>
{employeeName} <p className="text-sm text-gray-600">{employee?.jobPosition?.name}</p>
</p>
<p className="text-sm text-gray-600">
{employee?.jobPosition?.name}
</p>
</div> </div>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
@ -302,25 +255,18 @@ const NewTeamModal: React.FC<NewTeamModalProps> = ({
: TeamRoleEnum.Member : TeamRoleEnum.Member
} }
onChange={(e) => onChange={(e) =>
handleMemberRoleChange( handleMemberRoleChange(employeeName, e.target.value as TeamRoleEnum)
employeeName,
e.target.value as TeamRoleEnum
)
} }
className="text-xs px-1.5 py-1 border border-gray-300 rounded" className="text-xs px-1.5 py-1 border border-gray-300 rounded"
> >
<option value={TeamRoleEnum.Member}>Üye</option> <option value={TeamRoleEnum.Member}>Üye</option>
<option value={TeamRoleEnum.Lead}>Lider</option> <option value={TeamRoleEnum.Lead}>Lider</option>
<option value={TeamRoleEnum.Specialist}> <option value={TeamRoleEnum.Specialist}>Uzman</option>
Uzman <option value={TeamRoleEnum.Manager}>Yönetici</option>
</option>
<option value={TeamRoleEnum.Manager}>
Yönetici
</option>
</select> </select>
</div> </div>
</div> </div>
); )
})} })}
</div> </div>
</div> </div>
@ -341,9 +287,9 @@ const NewTeamModal: React.FC<NewTeamModalProps> = ({
className="flex-1 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" className="flex-1 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="Uzmanlık alanı ekle" placeholder="Uzmanlık alanı ekle"
onKeyPress={(e) => { onKeyPress={(e) => {
if (e.key === "Enter") { if (e.key === 'Enter') {
e.preventDefault(); e.preventDefault()
addSpecialization(); addSpecialization()
} }
}} }}
/> />
@ -355,26 +301,25 @@ const NewTeamModal: React.FC<NewTeamModalProps> = ({
<FaPlus className="w-4 h-4" /> <FaPlus className="w-4 h-4" />
</button> </button>
</div> </div>
{teamData.specializations && {teamData.specializations && teamData.specializations.length > 0 && (
teamData.specializations.length > 0 && ( <div className="flex flex-wrap gap-2">
<div className="flex flex-wrap gap-2"> {teamData.specializations.map((spec, index) => (
{teamData.specializations.map((spec, index) => ( <span
<span key={index}
key={index} className="inline-flex items-center px-2.5 py-1 rounded-full text-xs bg-blue-100 text-blue-800"
className="inline-flex items-center px-2.5 py-1 rounded-full text-xs bg-blue-100 text-blue-800" >
{spec}
<button
type="button"
onClick={() => removeSpecialization(index)}
className="ml-2 text-blue-600 hover:text-blue-800"
> >
{spec} <FaMinus className="w-3 h-3" />
<button </button>
type="button" </span>
onClick={() => removeSpecialization(index)} ))}
className="ml-2 text-blue-600 hover:text-blue-800" </div>
> )}
<FaMinus className="w-3 h-3" />
</button>
</span>
))}
</div>
)}
</div> </div>
</div> </div>
@ -384,9 +329,7 @@ const NewTeamModal: React.FC<NewTeamModalProps> = ({
<input <input
type="checkbox" type="checkbox"
checked={teamData.isActive || false} checked={teamData.isActive || false}
onChange={(e) => onChange={(e) => handleInputChange('isActive', e.target.checked)}
handleInputChange("isActive", e.target.checked)
}
className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50" className="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50"
/> />
<span className="ml-2 text-sm text-gray-700">Ekip aktif</span> <span className="ml-2 text-sm text-gray-700">Ekip aktif</span>
@ -413,7 +356,7 @@ const NewTeamModal: React.FC<NewTeamModalProps> = ({
</div> </div>
</div> </div>
) )
); )
}; }
export default NewTeamModal; export default NewTeamModal

View file

@ -1,95 +1,82 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaSave, FaPlus, FaMinus } from "react-icons/fa"; import { FaTimes, FaSave, FaPlus, FaMinus } from 'react-icons/fa'
import { import {
PmWorkCenter, PmWorkCenter,
WorkCenterStatusEnum, WorkCenterStatusEnum,
CriticalityLevelEnum, CriticalityLevelEnum,
PmWorkCenterSpecification, PmWorkCenterSpecification,
} from "../../../types/pm"; } from '../../../types/pm'
interface NewWorkCenterModalProps { interface NewWorkCenterModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (workCenter: Partial<PmWorkCenter>) => void; onSave: (workCenter: Partial<PmWorkCenter>) => void
} }
const initialWorkCenter: Partial<PmWorkCenter> = { const initialWorkCenter: Partial<PmWorkCenter> = {
code: "", code: '',
name: "", name: '',
description: "", description: '',
manufacturer: "", manufacturer: '',
model: "", model: '',
serialNumber: "", serialNumber: '',
installationDate: new Date(), installationDate: new Date(),
location: "", location: '',
departmentId: "", departmentId: '',
status: WorkCenterStatusEnum.Operational, status: WorkCenterStatusEnum.Operational,
criticality: CriticalityLevelEnum.Medium, criticality: CriticalityLevelEnum.Medium,
specifications: [], specifications: [],
isActive: true, isActive: true,
}; }
const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({ isOpen, onClose, onSave }) => {
isOpen, const [workCenter, setWorkCenter] = useState<Partial<PmWorkCenter>>(initialWorkCenter)
onClose, const [specifications, setSpecifications] = useState<PmWorkCenterSpecification[]>([])
onSave,
}) => {
const [workCenter, setWorkCenter] =
useState<Partial<PmWorkCenter>>(initialWorkCenter);
const [specifications, setSpecifications] = useState<
PmWorkCenterSpecification[]
>([]);
if (!isOpen) return null; if (!isOpen) return null
const handleInputChange = ( const handleInputChange = (
e: React.ChangeEvent< e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>,
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
>
) => { ) => {
const { name, value, type } = e.target; const { name, value, type } = e.target
setWorkCenter((prev) => ({ setWorkCenter((prev) => ({
...prev, ...prev,
[name]: type === "date" ? new Date(value) : value, [name]: type === 'date' ? new Date(value) : value,
})); }))
}; }
const addSpecification = () => { const addSpecification = () => {
const newSpec: PmWorkCenterSpecification = { const newSpec: PmWorkCenterSpecification = {
id: `SPEC${Date.now()}`, id: `SPEC${Date.now()}`,
workCenterId: "", workCenterId: '',
specificationName: "", specificationName: '',
specificationValue: "", specificationValue: '',
unit: "", unit: '',
isRequired: false, isRequired: false,
}; }
setSpecifications([...specifications, newSpec]); setSpecifications([...specifications, newSpec])
}; }
const removeSpecification = (index: number) => { const removeSpecification = (index: number) => {
setSpecifications(specifications.filter((_, i) => i !== index)); setSpecifications(specifications.filter((_, i) => i !== index))
}; }
const updateSpecification = ( const updateSpecification = (index: number, field: string, value: string | boolean) => {
index: number,
field: string,
value: string | boolean
) => {
const updated = specifications.map((spec, i) => const updated = specifications.map((spec, i) =>
i === index ? { ...spec, [field]: value } : spec i === index ? { ...spec, [field]: value } : spec,
); )
setSpecifications(updated); setSpecifications(updated)
}; }
const handleSave = () => { const handleSave = () => {
const workCenterData = { const workCenterData = {
...workCenter, ...workCenter,
specifications, specifications,
workCenterType: { workCenterType: {
id: "ET001", id: 'ET001',
code: "GENERAL", code: 'GENERAL',
name: "Genel İş Merkezi", name: 'Genel İş Merkezi',
category: "Genel", category: 'Genel',
isActive: true, isActive: true,
}, },
maintenancePlans: [], maintenancePlans: [],
@ -97,25 +84,20 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
downTimeHistory: [], downTimeHistory: [],
creationTime: new Date(), creationTime: new Date(),
lastModificationTime: new Date(), lastModificationTime: new Date(),
}; }
onSave(workCenterData); onSave(workCenterData)
setWorkCenter(initialWorkCenter); setWorkCenter(initialWorkCenter)
setSpecifications([]); setSpecifications([])
onClose(); onClose()
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <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-4xl mx-4 max-h-[90vh] overflow-y-auto"> <div className="bg-white rounded-lg w-full max-w-4xl mx-4 max-h-[90vh] overflow-y-auto">
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">Yeni İş Merkezi Ekle</h2>
Yeni İş Merkezi Ekle <button onClick={onClose} className="p-1 hover:bg-gray-100 rounded-lg transition-colors">
</h2>
<button
onClick={onClose}
className="p-1 hover:bg-gray-100 rounded-lg transition-colors"
>
<FaTimes className="w-4 h-4 text-gray-500" /> <FaTimes className="w-4 h-4 text-gray-500" />
</button> </button>
</div> </div>
@ -124,9 +106,7 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
<div className="p-4 space-y-4"> <div className="p-4 space-y-4">
{/* Basic Information */} {/* Basic Information */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-3"> <h3 className="text-base font-medium text-gray-900 mb-3">Temel Bilgiler</h3>
Temel Bilgiler
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">
@ -135,7 +115,7 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
<input <input
type="text" type="text"
name="workCenterCode" name="workCenterCode"
value={workCenter.code || ""} value={workCenter.code || ''}
onChange={handleInputChange} onChange={handleInputChange}
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" 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="örn: CNC-001" placeholder="örn: CNC-001"
@ -149,7 +129,7 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
<input <input
type="text" type="text"
name="name" name="name"
value={workCenter.name || ""} value={workCenter.name || ''}
onChange={handleInputChange} onChange={handleInputChange}
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" 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="örn: CNC Torna Tezgahı" placeholder="örn: CNC Torna Tezgahı"
@ -157,12 +137,10 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
/> />
</div> </div>
<div className="md:col-span-2"> <div className="md:col-span-2">
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">ıklama</label>
ıklama
</label>
<textarea <textarea
name="description" name="description"
value={workCenter.description || ""} value={workCenter.description || ''}
onChange={handleInputChange} onChange={handleInputChange}
rows={2} rows={2}
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" 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"
@ -174,31 +152,25 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
{/* Technical Details */} {/* Technical Details */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-3"> <h3 className="text-base font-medium text-gray-900 mb-3">Teknik Detaylar</h3>
Teknik Detaylar
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Üretici</label>
Üretici
</label>
<input <input
type="text" type="text"
name="manufacturer" name="manufacturer"
value={workCenter.manufacturer || ""} value={workCenter.manufacturer || ''}
onChange={handleInputChange} onChange={handleInputChange}
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" 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="örn: HAAS Automation" placeholder="örn: HAAS Automation"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Model</label>
Model
</label>
<input <input
type="text" type="text"
name="model" name="model"
value={workCenter.model || ""} value={workCenter.model || ''}
onChange={handleInputChange} onChange={handleInputChange}
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" 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="örn: ST-30" placeholder="örn: ST-30"
@ -211,7 +183,7 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
<input <input
type="text" type="text"
name="serialNumber" name="serialNumber"
value={workCenter.serialNumber || ""} value={workCenter.serialNumber || ''}
onChange={handleInputChange} onChange={handleInputChange}
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" 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="örn: SN123456789" placeholder="örn: SN123456789"
@ -226,8 +198,8 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
name="installationDate" name="installationDate"
value={ value={
workCenter.installationDate workCenter.installationDate
? workCenter.installationDate.toISOString().split("T")[0] ? workCenter.installationDate.toISOString().split('T')[0]
: "" : ''
} }
onChange={handleInputChange} onChange={handleInputChange}
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" 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"
@ -243,21 +215,19 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
name="warrantyExpiry" name="warrantyExpiry"
value={ value={
workCenter.warrantyExpiry workCenter.warrantyExpiry
? workCenter.warrantyExpiry.toISOString().split("T")[0] ? workCenter.warrantyExpiry.toISOString().split('T')[0]
: "" : ''
} }
onChange={handleInputChange} onChange={handleInputChange}
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" 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"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Lokasyon *</label>
Lokasyon *
</label>
<input <input
type="text" type="text"
name="location" name="location"
value={workCenter.location || ""} value={workCenter.location || ''}
onChange={handleInputChange} onChange={handleInputChange}
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" 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="örn: Atölye A - Hat 1" placeholder="örn: Atölye A - Hat 1"
@ -269,29 +239,19 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
{/* Status and Priority */} {/* Status and Priority */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-3"> <h3 className="text-base font-medium text-gray-900 mb-3">Durum ve Öncelik</h3>
Durum ve Öncelik
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Durum</label>
Durum
</label>
<select <select
name="status" name="status"
value={workCenter.status || WorkCenterStatusEnum.Operational} value={workCenter.status || WorkCenterStatusEnum.Operational}
onChange={handleInputChange} onChange={handleInputChange}
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" 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"
> >
<option value={WorkCenterStatusEnum.Operational}> <option value={WorkCenterStatusEnum.Operational}>Operasyonel</option>
Operasyonel <option value={WorkCenterStatusEnum.UnderMaintenance}>Bakımda</option>
</option> <option value={WorkCenterStatusEnum.OutOfOrder}>Arızalı</option>
<option value={WorkCenterStatusEnum.UnderMaintenance}>
Bakımda
</option>
<option value={WorkCenterStatusEnum.OutOfOrder}>
Arızalı
</option>
<option value={WorkCenterStatusEnum.Retired}>Emekli</option> <option value={WorkCenterStatusEnum.Retired}>Emekli</option>
</select> </select>
</div> </div>
@ -317,9 +277,7 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
{/* Specifications */} {/* Specifications */}
<div> <div>
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
<h3 className="text-base font-medium text-gray-900"> <h3 className="text-base font-medium text-gray-900">Teknik Özellikler</h3>
Teknik Özellikler
</h3>
<button <button
type="button" type="button"
onClick={addSpecification} onClick={addSpecification}
@ -331,19 +289,12 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
</div> </div>
<div className="space-y-3"> <div className="space-y-3">
{specifications.map((spec, index) => ( {specifications.map((spec, index) => (
<div <div key={index} className="flex items-center space-x-2 p-2 bg-gray-50 rounded-lg">
key={index}
className="flex items-center space-x-2 p-2 bg-gray-50 rounded-lg"
>
<input <input
type="text" type="text"
value={spec.specificationName} value={spec.specificationName}
onChange={(e) => onChange={(e) =>
updateSpecification( updateSpecification(index, 'specificationName', e.target.value)
index,
"specificationName",
e.target.value
)
} }
placeholder="Özellik adı" placeholder="Özellik adı"
className="flex-1 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" className="flex-1 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"
@ -352,21 +303,15 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
type="text" type="text"
value={spec.specificationValue} value={spec.specificationValue}
onChange={(e) => onChange={(e) =>
updateSpecification( updateSpecification(index, 'specificationValue', e.target.value)
index,
"specificationValue",
e.target.value
)
} }
placeholder="Değer" placeholder="Değer"
className="flex-1 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" className="flex-1 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"
/> />
<input <input
type="text" type="text"
value={spec.unit || ""} value={spec.unit || ''}
onChange={(e) => onChange={(e) => updateSpecification(index, 'unit', e.target.value)}
updateSpecification(index, "unit", e.target.value)
}
placeholder="Birim" placeholder="Birim"
className="w-20 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" className="w-20 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"
/> />
@ -374,13 +319,7 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
<input <input
type="checkbox" type="checkbox"
checked={spec.isRequired} checked={spec.isRequired}
onChange={(e) => onChange={(e) => updateSpecification(index, 'isRequired', e.target.checked)}
updateSpecification(
index,
"isRequired",
e.target.checked
)
}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500 h-4 w-4" className="rounded border-gray-300 text-blue-600 focus:ring-blue-500 h-4 w-4"
/> />
<span className="text-sm text-gray-700">Zorunlu</span> <span className="text-sm text-gray-700">Zorunlu</span>
@ -396,8 +335,8 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
))} ))}
{specifications.length === 0 && ( {specifications.length === 0 && (
<p className="text-gray-500 text-center py-4"> <p className="text-gray-500 text-center py-4">
Henüz teknik özellik eklenmedi. "Özellik Ekle" butonunu Henüz teknik özellik eklenmedi. "Özellik Ekle" butonunu kullanarak özellik
kullanarak özellik ekleyebilirsiniz. ekleyebilirsiniz.
</p> </p>
)} )}
</div> </div>
@ -424,7 +363,7 @@ const NewWorkCenterModal: React.FC<NewWorkCenterModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default NewWorkCenterModal; export default NewWorkCenterModal

View file

@ -1,85 +1,76 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaPlus, FaTrash, FaCalendar, FaClock } from "react-icons/fa"; import { FaTimes, FaPlus, FaTrash, FaCalendar, FaClock } from 'react-icons/fa'
import { import {
PmMaintenanceWorkOrder, PmMaintenanceWorkOrder,
WorkOrderTypeEnum, WorkOrderTypeEnum,
WorkOrderStatusEnum, WorkOrderStatusEnum,
PmWorkOrderMaterial, PmWorkOrderMaterial,
PmWorkOrderActivity, PmWorkOrderActivity,
} from "../../../types/pm"; } from '../../../types/pm'
import { mockWorkCenters } from "../../../mocks/mockWorkCenters"; import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
import { mockMaintenanceTeams } from "../../../mocks/mockMaintenanceTeams"; import { mockMaintenanceTeams } from '../../../mocks/mockMaintenanceTeams'
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from '../../../mocks/mockEmployees'
import { mockMaterials } from "../../../mocks/mockMaterials"; import { mockMaterials } from '../../../mocks/mockMaterials'
import { PriorityEnum } from "../../../types/common"; import { PriorityEnum } from '../../../types/common'
interface NewWorkOrderModalProps { interface NewWorkOrderModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: ( onSave: (
workOrder: Omit< workOrder: Omit<PmMaintenanceWorkOrder, 'id' | 'creationTime' | 'lastModificationTime'>,
PmMaintenanceWorkOrder, ) => void
"id" | "creationTime" | "lastModificationTime"
>
) => void;
} }
const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({ isOpen, onClose, onSave }) => {
isOpen,
onClose,
onSave,
}) => {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
workOrderNumber: `WO-${Date.now()}`, workOrderNumber: `WO-${Date.now()}`,
workCenterId: "", workCenterId: '',
orderType: WorkOrderTypeEnum.Corrective, orderType: WorkOrderTypeEnum.Corrective,
priority: PriorityEnum.Normal, priority: PriorityEnum.Normal,
status: WorkOrderStatusEnum.Created, status: WorkOrderStatusEnum.Created,
description: "", description: '',
reportedBy: "", reportedBy: '',
assignedTo: "", assignedTo: '',
maintenanceTeamId: "", maintenanceTeamId: '',
scheduledStart: "", scheduledStart: '',
scheduledEnd: "", scheduledEnd: '',
estimatedCost: 0, estimatedCost: 0,
notes: "", notes: '',
}); })
const [materials, setMaterials] = useState< const [materials, setMaterials] = useState<Omit<PmWorkOrderMaterial, 'id' | 'workOrderId'>[]>([])
Omit<PmWorkOrderMaterial, "id" | "workOrderId">[] const [activities, setActivities] = useState<Omit<PmWorkOrderActivity, 'id' | 'workOrderId'>[]>(
>([]); [],
const [activities, setActivities] = useState< )
Omit<PmWorkOrderActivity, "id" | "workOrderId">[] const [errors, setErrors] = useState<Record<string, string>>({})
>([]);
const [errors, setErrors] = useState<Record<string, string>>({});
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (!formData.description.trim()) { if (!formData.description.trim()) {
newErrors.description = "Açıklama alanı zorunludur"; newErrors.description = 'Açıklama alanı zorunludur'
} }
if (!formData.workCenterId) { if (!formData.workCenterId) {
newErrors.workCenterId = "İş Merkezi seçimi zorunludur"; newErrors.workCenterId = 'İş Merkezi seçimi zorunludur'
} }
if (!formData.reportedBy.trim()) { if (!formData.reportedBy.trim()) {
newErrors.reportedBy = "Bildiren kişi zorunludur"; newErrors.reportedBy = 'Bildiren kişi zorunludur'
} }
if (formData.estimatedCost < 0) { if (formData.estimatedCost < 0) {
newErrors.estimatedCost = "Tahmini maliyet negatif olamaz"; newErrors.estimatedCost = 'Tahmini maliyet negatif olamaz'
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault()
if (!validateForm()) return; if (!validateForm()) return
const newWorkOrder: Omit< const newWorkOrder: Omit<
PmMaintenanceWorkOrder, PmMaintenanceWorkOrder,
"id" | "creationTime" | "lastModificationTime" 'id' | 'creationTime' | 'lastModificationTime'
> = { > = {
workOrderNumber: formData.workOrderNumber, workOrderNumber: formData.workOrderNumber,
workCenterId: formData.workCenterId, workCenterId: formData.workCenterId,
@ -90,12 +81,8 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
reportedBy: formData.reportedBy, reportedBy: formData.reportedBy,
assignedTo: formData.assignedTo || undefined, assignedTo: formData.assignedTo || undefined,
maintenanceTeamId: formData.maintenanceTeamId || undefined, maintenanceTeamId: formData.maintenanceTeamId || undefined,
scheduledStart: formData.scheduledStart scheduledStart: formData.scheduledStart ? new Date(formData.scheduledStart) : undefined,
? new Date(formData.scheduledStart) scheduledEnd: formData.scheduledEnd ? new Date(formData.scheduledEnd) : undefined,
: undefined,
scheduledEnd: formData.scheduledEnd
? new Date(formData.scheduledEnd)
: undefined,
actualStart: undefined, actualStart: undefined,
actualEnd: undefined, actualEnd: undefined,
estimatedCost: formData.estimatedCost, estimatedCost: formData.estimatedCost,
@ -103,51 +90,47 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
materials: materials.map((material, index) => ({ materials: materials.map((material, index) => ({
...material, ...material,
id: `mat-${index}`, id: `mat-${index}`,
workOrderId: "", workOrderId: '',
totalCost: material.plannedQuantity * material.unitCost, totalCost: material.plannedQuantity * material.unitCost,
})), })),
activities: activities.map((activity, index) => ({ activities: activities.map((activity, index) => ({
...activity, ...activity,
id: `act-${index}`, id: `act-${index}`,
workOrderId: "", workOrderId: '',
actualDuration: 0, actualDuration: 0,
completedAt: undefined, completedAt: undefined,
})), })),
notes: formData.notes || undefined, notes: formData.notes || undefined,
completionNotes: undefined, completionNotes: undefined,
}; }
onSave(newWorkOrder); onSave(newWorkOrder)
onClose(); onClose()
}; }
const addMaterial = () => { const addMaterial = () => {
setMaterials([ setMaterials([
...materials, ...materials,
{ {
materialId: "", materialId: '',
materialCode: "", materialCode: '',
materialName: "", materialName: '',
plannedQuantity: 1, plannedQuantity: 1,
actualQuantity: 0, actualQuantity: 0,
unitCost: 0, unitCost: 0,
totalCost: 0, totalCost: 0,
}, },
]); ])
}; }
const removeMaterial = (index: number) => { const removeMaterial = (index: number) => {
setMaterials(materials.filter((_, i) => i !== index)); setMaterials(materials.filter((_, i) => i !== index))
}; }
const updateMaterial = ( const updateMaterial = (index: number, field: string, value: string | number) => {
index: number, const updated = [...materials]
field: string, if (field === 'materialId') {
value: string | number const selectedMaterial = mockMaterials.find((m) => m.id === value)
) => {
const updated = [...materials];
if (field === "materialId") {
const selectedMaterial = mockMaterials.find((m) => m.id === value);
if (selectedMaterial) { if (selectedMaterial) {
updated[index] = { updated[index] = {
...updated[index], ...updated[index],
@ -155,66 +138,59 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
materialCode: selectedMaterial.code, materialCode: selectedMaterial.code,
materialName: selectedMaterial.name, materialName: selectedMaterial.name,
unitCost: selectedMaterial.costPrice, unitCost: selectedMaterial.costPrice,
}; }
} }
} else { } else {
const material = updated[index]; const material = updated[index]
if (field === "plannedQuantity") { if (field === 'plannedQuantity') {
material.plannedQuantity = value as number; material.plannedQuantity = value as number
} else if (field === "unitCost") { } else if (field === 'unitCost') {
material.unitCost = value as number; material.unitCost = value as number
} }
} }
setMaterials(updated); setMaterials(updated)
}; }
const addActivity = () => { const addActivity = () => {
setActivities([ setActivities([
...activities, ...activities,
{ {
activityDescription: "", activityDescription: '',
plannedDuration: 60, plannedDuration: 60,
actualDuration: 0, actualDuration: 0,
performedBy: "", performedBy: '',
notes: "", notes: '',
}, },
]); ])
}; }
const removeActivity = (index: number) => { const removeActivity = (index: number) => {
setActivities(activities.filter((_, i) => i !== index)); setActivities(activities.filter((_, i) => i !== index))
}; }
const updateActivity = ( const updateActivity = (index: number, field: string, value: string | number) => {
index: number, const updated = [...activities]
field: string, const activity = updated[index]
value: string | number if (field === 'activityDescription') {
) => { activity.activityDescription = value as string
const updated = [...activities]; } else if (field === 'plannedDuration') {
const activity = updated[index]; activity.plannedDuration = value as number
if (field === "activityDescription") { } else if (field === 'performedBy') {
activity.activityDescription = value as string; activity.performedBy = value as string
} else if (field === "plannedDuration") { } else if (field === 'notes') {
activity.plannedDuration = value as number; activity.notes = value as string
} else if (field === "performedBy") {
activity.performedBy = value as string;
} else if (field === "notes") {
activity.notes = value as string;
} }
setActivities(updated); setActivities(updated)
}; }
if (!isOpen) return null; if (!isOpen) return null
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <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="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"> <div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold text-gray-900">Yeni İş Emri</h3> <h3 className="text-lg font-semibold text-gray-900">Yeni İş Emri</h3>
<button <button onClick={onClose} className="text-gray-400 hover:text-gray-600">
onClick={onClose}
className="text-gray-400 hover:text-gray-600"
>
<FaTimes className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>
@ -223,31 +199,23 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
{/* Basic Information */} {/* Basic Information */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">İş Emri No</label>
İş Emri No
</label>
<input <input
type="text" type="text"
value={formData.workOrderNumber} value={formData.workOrderNumber}
onChange={(e) => onChange={(e) => setFormData({ ...formData, workOrderNumber: e.target.value })}
setFormData({ ...formData, workOrderNumber: e.target.value })
}
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" 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"
readOnly readOnly
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">İş Merkezi *</label>
İş Merkezi *
</label>
<select <select
value={formData.workCenterId} value={formData.workCenterId}
onChange={(e) => onChange={(e) => setFormData({ ...formData, workCenterId: e.target.value })}
setFormData({ ...formData, workCenterId: 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 ${ 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 ${
errors.workCenterId ? "border-red-500" : "border-gray-300" errors.workCenterId ? 'border-red-500' : 'border-gray-300'
}`} }`}
> >
<option value="">İş Merkezi Seçin</option> <option value="">İş Merkezi Seçin</option>
@ -258,16 +226,12 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
))} ))}
</select> </select>
{errors.workCenterId && ( {errors.workCenterId && (
<p className="mt-1 text-xs text-red-600"> <p className="mt-1 text-xs text-red-600">{errors.workCenterId}</p>
{errors.workCenterId}
</p>
)} )}
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">İş Emri Tipi</label>
İş Emri Tipi
</label>
<select <select
value={formData.orderType} value={formData.orderType}
onChange={(e) => onChange={(e) =>
@ -282,16 +246,12 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
<option value={WorkOrderTypeEnum.Corrective}>Düzeltici</option> <option value={WorkOrderTypeEnum.Corrective}>Düzeltici</option>
<option value={WorkOrderTypeEnum.Emergency}>Acil</option> <option value={WorkOrderTypeEnum.Emergency}>Acil</option>
<option value={WorkOrderTypeEnum.Inspection}>İnceleme</option> <option value={WorkOrderTypeEnum.Inspection}>İnceleme</option>
<option value={WorkOrderTypeEnum.Calibration}> <option value={WorkOrderTypeEnum.Calibration}>Kalibrasyon</option>
Kalibrasyon
</option>
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Öncelik</label>
Öncelik
</label>
<select <select
value={formData.priority} value={formData.priority}
onChange={(e) => onChange={(e) =>
@ -311,17 +271,13 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">ıklama *</label>
ıklama *
</label>
<textarea <textarea
value={formData.description} value={formData.description}
onChange={(e) => onChange={(e) => setFormData({ ...formData, description: e.target.value })}
setFormData({ ...formData, description: e.target.value })
}
rows={2} 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 ${ 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 ${
errors.description ? "border-red-500" : "border-gray-300" errors.description ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="İş emri açıklaması..." placeholder="İş emri açıklaması..."
/> />
@ -333,17 +289,13 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
{/* Assignment */} {/* Assignment */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Bildiren *</label>
Bildiren *
</label>
<input <input
type="text" type="text"
value={formData.reportedBy} value={formData.reportedBy}
onChange={(e) => onChange={(e) => setFormData({ ...formData, reportedBy: e.target.value })}
setFormData({ ...formData, reportedBy: 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 ${ 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 ${
errors.reportedBy ? "border-red-500" : "border-gray-300" errors.reportedBy ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Bildiren kişi adı" placeholder="Bildiren kişi adı"
/> />
@ -353,14 +305,10 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Atanan Kişi</label>
Atanan Kişi
</label>
<select <select
value={formData.assignedTo} value={formData.assignedTo}
onChange={(e) => onChange={(e) => setFormData({ ...formData, assignedTo: e.target.value })}
setFormData({ ...formData, assignedTo: e.target.value })
}
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" 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"
> >
<option value="">Kişi Seçin</option> <option value="">Kişi Seçin</option>
@ -373,9 +321,7 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Bakım Ekibi</label>
Bakım Ekibi
</label>
<select <select
value={formData.maintenanceTeamId} value={formData.maintenanceTeamId}
onChange={(e) => onChange={(e) =>
@ -406,9 +352,7 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
<input <input
type="datetime-local" type="datetime-local"
value={formData.scheduledStart} value={formData.scheduledStart}
onChange={(e) => onChange={(e) => setFormData({ ...formData, scheduledStart: e.target.value })}
setFormData({ ...formData, scheduledStart: e.target.value })
}
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" 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"
/> />
</div> </div>
@ -421,9 +365,7 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
<input <input
type="datetime-local" type="datetime-local"
value={formData.scheduledEnd} value={formData.scheduledEnd}
onChange={(e) => onChange={(e) => setFormData({ ...formData, scheduledEnd: e.target.value })}
setFormData({ ...formData, scheduledEnd: e.target.value })
}
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" 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"
/> />
</div> </div>
@ -444,14 +386,12 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
}) })
} }
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 ${ 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 ${
errors.estimatedCost ? "border-red-500" : "border-gray-300" errors.estimatedCost ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="0.00" placeholder="0.00"
/> />
{errors.estimatedCost && ( {errors.estimatedCost && (
<p className="mt-1 text-xs text-red-600"> <p className="mt-1 text-xs text-red-600">{errors.estimatedCost}</p>
{errors.estimatedCost}
</p>
)} )}
</div> </div>
</div> </div>
@ -459,9 +399,7 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
{/* Materials */} {/* Materials */}
<div> <div>
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<h4 className="text-base font-medium text-gray-900"> <h4 className="text-base font-medium text-gray-900">Malzemeler</h4>
Malzemeler
</h4>
<button <button
type="button" type="button"
onClick={addMaterial} onClick={addMaterial}
@ -476,14 +414,10 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
<div key={index} className="bg-gray-50 p-3 rounded-lg mb-2"> <div key={index} className="bg-gray-50 p-3 rounded-lg mb-2">
<div className="grid grid-cols-1 md:grid-cols-5 gap-3"> <div className="grid grid-cols-1 md:grid-cols-5 gap-3">
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Malzeme</label>
Malzeme
</label>
<select <select
value={material.materialId} value={material.materialId}
onChange={(e) => onChange={(e) => updateMaterial(index, 'materialId', e.target.value)}
updateMaterial(index, "materialId", e.target.value)
}
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" 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"
> >
<option value="">Malzeme Seçin</option> <option value="">Malzeme Seçin</option>
@ -503,11 +437,7 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
min="0" min="0"
value={material.plannedQuantity} value={material.plannedQuantity}
onChange={(e) => onChange={(e) =>
updateMaterial( updateMaterial(index, 'plannedQuantity', parseInt(e.target.value) || 0)
index,
"plannedQuantity",
parseInt(e.target.value) || 0
)
} }
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" 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"
/> />
@ -522,24 +452,16 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
step="0.01" step="0.01"
value={material.unitCost} value={material.unitCost}
onChange={(e) => onChange={(e) =>
updateMaterial( updateMaterial(index, 'unitCost', parseFloat(e.target.value) || 0)
index,
"unitCost",
parseFloat(e.target.value) || 0
)
} }
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" 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"
/> />
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">Toplam</label>
Toplam
</label>
<input <input
type="text" type="text"
value={`${( value={`${(material.plannedQuantity * material.unitCost).toFixed(2)}`}
material.plannedQuantity * material.unitCost
).toFixed(2)}`}
readOnly readOnly
className="w-full px-2.5 py-1.5 text-sm border border-gray-300 rounded-lg bg-gray-100" className="w-full px-2.5 py-1.5 text-sm border border-gray-300 rounded-lg bg-gray-100"
/> />
@ -561,9 +483,7 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
{/* Activities */} {/* Activities */}
<div> <div>
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
<h4 className="text-base font-medium text-gray-900"> <h4 className="text-base font-medium text-gray-900">Aktiviteler</h4>
Aktiviteler
</h4>
<button <button
type="button" type="button"
onClick={addActivity} onClick={addActivity}
@ -584,13 +504,7 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
<input <input
type="text" type="text"
value={activity.activityDescription} value={activity.activityDescription}
onChange={(e) => onChange={(e) => updateActivity(index, 'activityDescription', e.target.value)}
updateActivity(
index,
"activityDescription",
e.target.value
)
}
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" 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="Aktivite açıklaması" placeholder="Aktivite açıklaması"
/> />
@ -605,11 +519,7 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
min="0" min="0"
value={activity.plannedDuration} value={activity.plannedDuration}
onChange={(e) => onChange={(e) =>
updateActivity( updateActivity(index, 'plannedDuration', parseInt(e.target.value) || 0)
index,
"plannedDuration",
parseInt(e.target.value) || 0
)
} }
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" 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"
/> />
@ -630,14 +540,10 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
{/* Notes */} {/* Notes */}
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Notlar</label>
Notlar
</label>
<textarea <textarea
value={formData.notes} value={formData.notes}
onChange={(e) => onChange={(e) => setFormData({ ...formData, notes: e.target.value })}
setFormData({ ...formData, notes: e.target.value })
}
rows={2} rows={2}
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" 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="Ek notlar..." placeholder="Ek notlar..."
@ -663,7 +569,7 @@ const NewWorkOrderModal: React.FC<NewWorkOrderModalProps> = ({
</form> </form>
</div> </div>
</div> </div>
); )
}; }
export default NewWorkOrderModal; export default NewWorkOrderModal

View file

@ -1,17 +1,12 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from 'react'
import { import { FaTimes, FaSave, FaExclamationTriangle, FaInfoCircle } from 'react-icons/fa'
FaTimes, import { PmMaintenancePlan } from '../../../types/pm'
FaSave,
FaExclamationTriangle,
FaInfoCircle,
} from "react-icons/fa";
import { PmMaintenancePlan } from "../../../types/pm";
interface PlanStatusChangeModalProps { interface PlanStatusChangeModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (planIds: string[], isActive: boolean, reason: string) => void; onSave: (planIds: string[], isActive: boolean, reason: string) => void
selectedPlans: PmMaintenancePlan[]; selectedPlans: PmMaintenancePlan[]
} }
const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
@ -20,47 +15,43 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
onSave, onSave,
selectedPlans, selectedPlans,
}) => { }) => {
const [targetStatus, setTargetStatus] = useState<boolean>(true); const [targetStatus, setTargetStatus] = useState<boolean>(true)
const [reason, setReason] = useState(""); const [reason, setReason] = useState('')
const activePlans = selectedPlans.filter((plan) => plan.isActive); const activePlans = selectedPlans.filter((plan) => plan.isActive)
const inactivePlans = selectedPlans.filter((plan) => !plan.isActive); const inactivePlans = selectedPlans.filter((plan) => !plan.isActive)
useEffect(() => { useEffect(() => {
if (isOpen) { if (isOpen) {
setTargetStatus(true); setTargetStatus(true)
setReason(""); setReason('')
} }
}, [isOpen]); }, [isOpen])
const handleSave = () => { const handleSave = () => {
if (!reason.trim()) { if (!reason.trim()) {
alert("Lütfen durum değişikliği için bir açıklama girin."); alert('Lütfen durum değişikliği için bir açıklama girin.')
return; return
} }
const planIds = selectedPlans.map((plan) => plan.id); const planIds = selectedPlans.map((plan) => plan.id)
onSave(planIds, targetStatus, reason.trim()); onSave(planIds, targetStatus, reason.trim())
onClose(); onClose()
}; }
const getStatusText = (isActive: boolean) => { const getStatusText = (isActive: boolean) => {
return isActive ? "Aktif" : "Pasif"; return isActive ? 'Aktif' : 'Pasif'
}; }
const getStatusColor = (isActive: boolean) => { const getStatusColor = (isActive: boolean) => {
return isActive ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800"; return isActive ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
}; }
const getTargetStatusColor = (isActive: boolean) => { const getTargetStatusColor = (isActive: boolean) => {
return isActive ? "text-green-600" : "text-red-600"; return isActive ? 'text-green-600' : 'text-red-600'
}; }
const willChange = selectedPlans.filter( const willChange = selectedPlans.filter((plan) => plan.isActive !== targetStatus)
(plan) => plan.isActive !== targetStatus const willNotChange = selectedPlans.filter((plan) => plan.isActive === targetStatus)
);
const willNotChange = selectedPlans.filter(
(plan) => plan.isActive === targetStatus
);
return ( return (
isOpen && ( isOpen && (
@ -69,12 +60,8 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<div> <div>
<h2 className="text-2xl font-bold text-gray-900"> <h2 className="text-2xl font-bold text-gray-900">Plan Durumu Değiştir</h2>
Plan Durumu Değiştir <p className="text-gray-600">{selectedPlans.length} plan için durum değişikliği</p>
</h2>
<p className="text-gray-600">
{selectedPlans.length} plan için durum değişikliği
</p>
</div> </div>
<button <button
onClick={onClose} onClick={onClose}
@ -88,40 +75,28 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
<div className="p-3 space-y-3"> <div className="p-3 space-y-3">
{/* Current Status Summary */} {/* Current Status Summary */}
<div> <div>
<h3 className="text-sm font-medium text-gray-900 mb-2"> <h3 className="text-sm font-medium text-gray-900 mb-2">Mevcut Durum</h3>
Mevcut Durum
</h3>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<div className="bg-green-50 border border-green-200 rounded-lg p-3"> <div className="bg-green-50 border border-green-200 rounded-lg p-3">
<div className="flex items-center space-x-1.5"> <div className="flex items-center space-x-1.5">
<div className="w-3 h-3 bg-green-500 rounded-full"></div> <div className="w-3 h-3 bg-green-500 rounded-full"></div>
<span className="text-sm font-medium text-green-800"> <span className="text-sm font-medium text-green-800">Aktif Planlar</span>
Aktif Planlar
</span>
</div> </div>
<p className="text-base font-bold text-green-600 mt-1"> <p className="text-base font-bold text-green-600 mt-1">{activePlans.length}</p>
{activePlans.length}
</p>
</div> </div>
<div className="bg-red-50 border border-red-200 rounded-lg p-3"> <div className="bg-red-50 border border-red-200 rounded-lg p-3">
<div className="flex items-center space-x-1.5"> <div className="flex items-center space-x-1.5">
<div className="w-3 h-3 bg-red-500 rounded-full"></div> <div className="w-3 h-3 bg-red-500 rounded-full"></div>
<span className="text-sm font-medium text-red-800"> <span className="text-sm font-medium text-red-800">Pasif Planlar</span>
Pasif Planlar
</span>
</div> </div>
<p className="text-base font-bold text-red-600 mt-1"> <p className="text-base font-bold text-red-600 mt-1">{inactivePlans.length}</p>
{inactivePlans.length}
</p>
</div> </div>
</div> </div>
</div> </div>
{/* Target Status Selection */} {/* Target Status Selection */}
<div> <div>
<h3 className="text-sm font-medium text-gray-900 mb-2"> <h3 className="text-sm font-medium text-gray-900 mb-2">Hedef Durum</h3>
Hedef Durum
</h3>
<div className="space-y-2"> <div className="space-y-2">
<label className="flex items-center space-x-3 p-2 border border-gray-200 rounded-lg hover:bg-gray-50"> <label className="flex items-center space-x-3 p-2 border border-gray-200 rounded-lg hover:bg-gray-50">
<input <input
@ -133,9 +108,7 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
/> />
<div className="flex items-center space-x-1.5"> <div className="flex items-center space-x-1.5">
<div className="w-3 h-3 bg-green-500 rounded-full"></div> <div className="w-3 h-3 bg-green-500 rounded-full"></div>
<span className="text-sm font-medium text-gray-900"> <span className="text-sm font-medium text-gray-900">Aktif</span>
Aktif
</span>
<span className="text-xs text-gray-500"> <span className="text-xs text-gray-500">
(Planlar bakım takvimine dahil edilir) (Planlar bakım takvimine dahil edilir)
</span> </span>
@ -151,9 +124,7 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
/> />
<div className="flex items-center space-x-1.5"> <div className="flex items-center space-x-1.5">
<div className="w-3 h-3 bg-red-500 rounded-full"></div> <div className="w-3 h-3 bg-red-500 rounded-full"></div>
<span className="text-sm font-medium text-gray-900"> <span className="text-sm font-medium text-gray-900">Pasif</span>
Pasif
</span>
<span className="text-xs text-gray-500"> <span className="text-xs text-gray-500">
(Planlar bakım takvimine dahil edilmez) (Planlar bakım takvimine dahil edilmez)
</span> </span>
@ -164,9 +135,7 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
{/* Change Impact */} {/* Change Impact */}
<div> <div>
<h3 className="text-sm font-medium text-gray-900 mb-2"> <h3 className="text-sm font-medium text-gray-900 mb-2">Değişiklik Etkisi</h3>
Değişiklik Etkisi
</h3>
{willChange.length > 0 && ( {willChange.length > 0 && (
<div className="mb-2"> <div className="mb-2">
@ -179,23 +148,16 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-2 max-h-28 overflow-y-auto"> <div className="bg-yellow-50 border border-yellow-200 rounded-lg p-2 max-h-28 overflow-y-auto">
<div className="space-y-2"> <div className="space-y-2">
{willChange.map((plan) => ( {willChange.map((plan) => (
<div <div key={plan.id} className="flex items-center justify-between text-sm">
key={plan.id}
className="flex items-center justify-between text-sm"
>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<span className="font-mono text-gray-600"> <span className="font-mono text-gray-600">{plan.planCode}</span>
{plan.planCode}
</span>
<span className="text-gray-500">-</span> <span className="text-gray-500">-</span>
<span className="text-gray-700"> <span className="text-gray-700">{plan.description}</span>
{plan.description}
</span>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<span <span
className={`px-2 py-1 rounded-full text-xs ${getStatusColor( className={`px-2 py-1 rounded-full text-xs ${getStatusColor(
plan.isActive plan.isActive,
)}`} )}`}
> >
{getStatusText(plan.isActive)} {getStatusText(plan.isActive)}
@ -203,7 +165,7 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
<span className="text-gray-400"></span> <span className="text-gray-400"></span>
<span <span
className={`px-2 py-1 rounded-full text-xs ${getStatusColor( className={`px-2 py-1 rounded-full text-xs ${getStatusColor(
targetStatus targetStatus,
)}`} )}`}
> >
{getStatusText(targetStatus)} {getStatusText(targetStatus)}
@ -227,22 +189,15 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
<div className="bg-blue-50 border border-blue-200 rounded-lg p-2 max-h-28 overflow-y-auto"> <div className="bg-blue-50 border border-blue-200 rounded-lg p-2 max-h-28 overflow-y-auto">
<div className="space-y-2"> <div className="space-y-2">
{willNotChange.map((plan) => ( {willNotChange.map((plan) => (
<div <div key={plan.id} className="flex items-center justify-between text-sm">
key={plan.id}
className="flex items-center justify-between text-sm"
>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<span className="font-mono text-gray-600"> <span className="font-mono text-gray-600">{plan.planCode}</span>
{plan.planCode}
</span>
<span className="text-gray-500">-</span> <span className="text-gray-500">-</span>
<span className="text-gray-700"> <span className="text-gray-700">{plan.description}</span>
{plan.description}
</span>
</div> </div>
<span <span
className={`px-2 py-1 rounded-full text-xs ${getStatusColor( className={`px-2 py-1 rounded-full text-xs ${getStatusColor(
plan.isActive plan.isActive,
)}`} )}`}
> >
{getStatusText(plan.isActive)} {getStatusText(plan.isActive)}
@ -281,10 +236,9 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
<div> <div>
<h4 className="text-sm font-medium text-red-800">Uyarı</h4> <h4 className="text-sm font-medium text-red-800">Uyarı</h4>
<p className="text-sm text-red-700 mt-1"> <p className="text-sm text-red-700 mt-1">
Planları pasif hale getirmek, gelecek bakım işlemlerinin Planları pasif hale getirmek, gelecek bakım işlemlerinin otomatik olarak
otomatik olarak planlanmasını durdurur. Bu planlar manuel planlanmasını durdurur. Bu planlar manuel olarak aktif hale getirilene kadar
olarak aktif hale getirilene kadar bakım takviminde bakım takviminde görünmeyecektir.
görünmeyecektir.
</p> </p>
</div> </div>
</div> </div>
@ -296,13 +250,10 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
<div className="flex items-start space-x-2"> <div className="flex items-start space-x-2">
<FaInfoCircle className="w-5 h-5 text-green-600 mt-0.5" /> <FaInfoCircle className="w-5 h-5 text-green-600 mt-0.5" />
<div> <div>
<h4 className="text-sm font-medium text-green-800"> <h4 className="text-sm font-medium text-green-800">Bilgi</h4>
Bilgi
</h4>
<p className="text-sm text-green-700 mt-1"> <p className="text-sm text-green-700 mt-1">
Planları aktif hale getirmek, bakım takviminde Planları aktif hale getirmek, bakım takviminde görünmelerini ve otomatik
görünmelerini ve otomatik emri oluşturulmalarını emri oluşturulmalarını sağlar. Sonraki bakım tarihleri plan ayarlarına göre
sağlar. Sonraki bakım tarihleri plan ayarlarına göre
hesaplanacaktır. hesaplanacaktır.
</p> </p>
</div> </div>
@ -326,11 +277,11 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
disabled={!reason.trim()} disabled={!reason.trim()}
className={`flex items-center space-x-2 px-3 py-1.5 text-sm rounded-lg transition-colors ${ className={`flex items-center space-x-2 px-3 py-1.5 text-sm rounded-lg transition-colors ${
!reason.trim() !reason.trim()
? "bg-gray-300 text-gray-500 cursor-not-allowed" ? 'bg-gray-300 text-gray-500 cursor-not-allowed'
: `${getTargetStatusColor(targetStatus)} ${ : `${getTargetStatusColor(targetStatus)} ${
targetStatus targetStatus
? "bg-green-600 hover:bg-green-700 text-white" ? 'bg-green-600 hover:bg-green-700 text-white'
: "bg-red-600 hover:bg-red-700 text-white" : 'bg-red-600 hover:bg-red-700 text-white'
}` }`
}`} }`}
> >
@ -343,7 +294,7 @@ const PlanStatusChangeModal: React.FC<PlanStatusChangeModalProps> = ({
</div> </div>
</div> </div>
) )
); )
}; }
export default PlanStatusChangeModal; export default PlanStatusChangeModal

View file

@ -1,24 +1,21 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaPlay, FaCalendar, FaUser } from "react-icons/fa"; import { FaTimes, FaPlay, FaCalendar, FaUser } from 'react-icons/fa'
import { PmMaintenanceWorkOrder, WorkOrderStatusEnum } from "../../../types/pm"; import { PmMaintenanceWorkOrder, WorkOrderStatusEnum } from '../../../types/pm'
import { mockEmployees } from "../../../mocks/mockEmployees"; import { mockEmployees } from '../../../mocks/mockEmployees'
import { mockMaintenanceTeams } from "../../../mocks/mockMaintenanceTeams"; import { mockMaintenanceTeams } from '../../../mocks/mockMaintenanceTeams'
interface StartWorkOrderModalProps { interface StartWorkOrderModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onStart: ( onStart: (workOrders: PmMaintenanceWorkOrder[], startData: StartWorkOrderData) => void
workOrders: PmMaintenanceWorkOrder[], workOrders: PmMaintenanceWorkOrder[]
startData: StartWorkOrderData
) => void;
workOrders: PmMaintenanceWorkOrder[];
} }
interface StartWorkOrderData { interface StartWorkOrderData {
actualStart: Date; actualStart: Date
assignedTo?: string; assignedTo?: string
maintenanceTeamId?: string; maintenanceTeamId?: string
notes?: string; notes?: string
} }
const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
@ -29,57 +26,57 @@ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
}) => { }) => {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
actualStart: new Date().toISOString().slice(0, 16), actualStart: new Date().toISOString().slice(0, 16),
assignedTo: "", assignedTo: '',
maintenanceTeamId: "", maintenanceTeamId: '',
notes: "", notes: '',
}); })
const [errors, setErrors] = useState<Record<string, string>>({}); const [errors, setErrors] = useState<Record<string, string>>({})
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (!formData.actualStart) { if (!formData.actualStart) {
newErrors.actualStart = "Başlangıç tarihi zorunludur"; newErrors.actualStart = 'Başlangıç tarihi zorunludur'
} }
const startDate = new Date(formData.actualStart); const startDate = new Date(formData.actualStart)
const now = new Date(); const now = new Date()
if (startDate > now) { if (startDate > now) {
newErrors.actualStart = "Başlangıç tarihi gelecekte olamaz"; newErrors.actualStart = 'Başlangıç tarihi gelecekte olamaz'
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault()
if (!validateForm()) return; if (!validateForm()) return
const startData: StartWorkOrderData = { const startData: StartWorkOrderData = {
actualStart: new Date(formData.actualStart), actualStart: new Date(formData.actualStart),
assignedTo: formData.assignedTo || undefined, assignedTo: formData.assignedTo || undefined,
maintenanceTeamId: formData.maintenanceTeamId || undefined, maintenanceTeamId: formData.maintenanceTeamId || undefined,
notes: formData.notes || undefined, notes: formData.notes || undefined,
}; }
onStart(workOrders, startData); onStart(workOrders, startData)
onClose(); onClose()
}; }
const canStartWorkOrders = workOrders.every( const canStartWorkOrders = workOrders.every(
(wo) => (wo) =>
wo.status === WorkOrderStatusEnum.Created || wo.status === WorkOrderStatusEnum.Created ||
wo.status === WorkOrderStatusEnum.Planned || wo.status === WorkOrderStatusEnum.Planned ||
wo.status === WorkOrderStatusEnum.Released wo.status === WorkOrderStatusEnum.Released,
); )
const inProgressWorkOrders = workOrders.filter( const inProgressWorkOrders = workOrders.filter(
(wo) => wo.status === WorkOrderStatusEnum.InProgress (wo) => wo.status === WorkOrderStatusEnum.InProgress,
); )
if (!isOpen) return null; if (!isOpen) return null
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -89,10 +86,7 @@ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
<FaPlay className="w-5 h-5 mr-2 text-green-600" /> <FaPlay className="w-5 h-5 mr-2 text-green-600" />
İş Emirlerini Başlat İş Emirlerini Başlat
</h3> </h3>
<button <button onClick={onClose} className="text-gray-400 hover:text-gray-600">
onClick={onClose}
className="text-gray-400 hover:text-gray-600"
>
<FaTimes className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>
@ -104,47 +98,33 @@ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
</h4> </h4>
<div className="max-h-32 overflow-y-auto border border-gray-200 rounded-lg"> <div className="max-h-32 overflow-y-auto border border-gray-200 rounded-lg">
{workOrders.map((workOrder) => ( {workOrders.map((workOrder) => (
<div <div key={workOrder.id} className="p-3 border-b border-gray-100 last:border-b-0">
key={workOrder.id}
className="p-3 border-b border-gray-100 last:border-b-0"
>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<p className="font-medium text-sm text-gray-900"> <p className="font-medium text-sm text-gray-900">{workOrder.workOrderNumber}</p>
{workOrder.workOrderNumber} <p className="text-xs text-gray-600 truncate">{workOrder.description}</p>
</p>
<p className="text-xs text-gray-600 truncate">
{workOrder.description}
</p>
</div> </div>
<div className="text-right"> <div className="text-right">
<span <span
className={`px-2 py-1 rounded-full text-xs font-medium ${ className={`px-2 py-1 rounded-full text-xs font-medium ${
workOrder.status === WorkOrderStatusEnum.Created workOrder.status === WorkOrderStatusEnum.Created
? "bg-gray-100 text-gray-800" ? 'bg-gray-100 text-gray-800'
: workOrder.status === WorkOrderStatusEnum.Planned : workOrder.status === WorkOrderStatusEnum.Planned
? "bg-blue-100 text-blue-800" ? 'bg-blue-100 text-blue-800'
: workOrder.status === WorkOrderStatusEnum.Released : workOrder.status === WorkOrderStatusEnum.Released
? "bg-purple-100 text-purple-800" ? 'bg-purple-100 text-purple-800'
: workOrder.status === WorkOrderStatusEnum.InProgress : workOrder.status === WorkOrderStatusEnum.InProgress
? "bg-orange-100 text-orange-800" ? 'bg-orange-100 text-orange-800'
: "bg-gray-100 text-gray-800" : 'bg-gray-100 text-gray-800'
}`} }`}
> >
{workOrder.status === WorkOrderStatusEnum.Created && {workOrder.status === WorkOrderStatusEnum.Created && 'Oluşturuldu'}
"Oluşturuldu"} {workOrder.status === WorkOrderStatusEnum.Planned && 'Planlandı'}
{workOrder.status === WorkOrderStatusEnum.Planned && {workOrder.status === WorkOrderStatusEnum.Released && 'Serbest Bırakıldı'}
"Planlandı"} {workOrder.status === WorkOrderStatusEnum.InProgress && 'Devam Ediyor'}
{workOrder.status === WorkOrderStatusEnum.Released && {workOrder.status === WorkOrderStatusEnum.OnHold && 'Beklemede'}
"Serbest Bırakıldı"} {workOrder.status === WorkOrderStatusEnum.Completed && 'Tamamlandı'}
{workOrder.status === WorkOrderStatusEnum.InProgress && {workOrder.status === WorkOrderStatusEnum.Cancelled && 'İptal Edildi'}
"Devam Ediyor"}
{workOrder.status === WorkOrderStatusEnum.OnHold &&
"Beklemede"}
{workOrder.status === WorkOrderStatusEnum.Completed &&
"Tamamlandı"}
{workOrder.status === WorkOrderStatusEnum.Cancelled &&
"İptal Edildi"}
</span> </span>
</div> </div>
</div> </div>
@ -161,9 +141,8 @@ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
<div> <div>
<h5 className="font-medium text-yellow-800 mb-1">Uyarı</h5> <h5 className="font-medium text-yellow-800 mb-1">Uyarı</h5>
<p className="text-yellow-700 text-sm"> <p className="text-yellow-700 text-sm">
Bazı emirleri başlatılamaz durumda. Sadece "Oluşturuldu", Bazı emirleri başlatılamaz durumda. Sadece "Oluşturuldu", "Planlandı" veya
"Planlandı" veya "Serbest Bırakıldı" durumundaki emirleri "Serbest Bırakıldı" durumundaki emirleri başlatılabilir.
başlatılabilir.
</p> </p>
</div> </div>
</div> </div>
@ -177,9 +156,8 @@ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
<div> <div>
<h5 className="font-medium text-blue-800 mb-1">Bilgi</h5> <h5 className="font-medium text-blue-800 mb-1">Bilgi</h5>
<p className="text-blue-700 text-sm"> <p className="text-blue-700 text-sm">
{inProgressWorkOrders.length} emri zaten devam ediyor {inProgressWorkOrders.length} emri zaten devam ediyor durumunda. Bu emirleri
durumunda. Bu emirleri için sadece atama ve not için sadece atama ve not güncellemesi yapılacak.
güncellemesi yapılacak.
</p> </p>
</div> </div>
</div> </div>
@ -196,11 +174,9 @@ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
<input <input
type="datetime-local" type="datetime-local"
value={formData.actualStart} value={formData.actualStart}
onChange={(e) => onChange={(e) => setFormData({ ...formData, actualStart: e.target.value })}
setFormData({ ...formData, actualStart: e.target.value })
}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.actualStart ? "border-red-500" : "border-gray-300" errors.actualStart ? 'border-red-500' : 'border-gray-300'
}`} }`}
/> />
{errors.actualStart && ( {errors.actualStart && (
@ -217,9 +193,7 @@ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
</label> </label>
<select <select
value={formData.assignedTo} value={formData.assignedTo}
onChange={(e) => onChange={(e) => setFormData({ ...formData, assignedTo: e.target.value })}
setFormData({ ...formData, assignedTo: 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" 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> <option value="">Kişi Seçin</option>
@ -232,9 +206,7 @@ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Bakım Ekibi</label>
Bakım Ekibi
</label>
<select <select
value={formData.maintenanceTeamId} value={formData.maintenanceTeamId}
onChange={(e) => onChange={(e) =>
@ -262,9 +234,7 @@ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
</label> </label>
<textarea <textarea
value={formData.notes} value={formData.notes}
onChange={(e) => onChange={(e) => setFormData({ ...formData, notes: e.target.value })}
setFormData({ ...formData, notes: e.target.value })
}
rows={2} 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" 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="İş emirlerinin başlatılması ile ilgili notlar..." placeholder="İş emirlerinin başlatılması ile ilgili notlar..."
@ -287,7 +257,7 @@ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
(wo) => (wo) =>
wo.status === WorkOrderStatusEnum.Created || wo.status === WorkOrderStatusEnum.Created ||
wo.status === WorkOrderStatusEnum.Planned || wo.status === WorkOrderStatusEnum.Planned ||
wo.status === WorkOrderStatusEnum.Released wo.status === WorkOrderStatusEnum.Released,
).length ).length
} }
</span> </span>
@ -301,10 +271,10 @@ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
<div> <div>
<span className="text-gray-600">Başlangıç Tarihi:</span> <span className="text-gray-600">Başlangıç Tarihi:</span>
<span className="ml-2 font-medium"> <span className="ml-2 font-medium">
{new Date(formData.actualStart).toLocaleDateString("tr-TR")}{" "} {new Date(formData.actualStart).toLocaleDateString('tr-TR')}{' '}
{new Date(formData.actualStart).toLocaleTimeString("tr-TR", { {new Date(formData.actualStart).toLocaleTimeString('tr-TR', {
hour: "2-digit", hour: '2-digit',
minute: "2-digit", minute: '2-digit',
})} })}
</span> </span>
</div> </div>
@ -331,7 +301,7 @@ const StartWorkOrderModal: React.FC<StartWorkOrderModalProps> = ({
</form> </form>
</div> </div>
</div> </div>
); )
}; }
export default StartWorkOrderModal; export default StartWorkOrderModal

View file

@ -1,20 +1,13 @@
import React, { useState } from "react"; import React, { useState } from 'react'
import { FaTimes, FaSave, FaExclamationTriangle } from "react-icons/fa"; import { FaTimes, FaSave, FaExclamationTriangle } from 'react-icons/fa'
import { import { PmWorkCenter, WorkCenterStatusEnum, CriticalityLevelEnum } from '../../../types/pm'
PmWorkCenter, import { getCriticalityLevelText, getWorkCenterStatusText } from '../../../utils/erp'
WorkCenterStatusEnum,
CriticalityLevelEnum,
} from "../../../types/pm";
import {
getCriticalityLevelText,
getWorkCenterStatusText,
} from "../../../utils/erp";
interface StatusUpdateModalProps { interface StatusUpdateModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (updatedWorkCenters: PmWorkCenter[]) => void; onSave: (updatedWorkCenters: PmWorkCenter[]) => void
selectedWorkCenters: PmWorkCenter[]; selectedWorkCenters: PmWorkCenter[]
} }
const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
@ -23,17 +16,15 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
onSave, onSave,
selectedWorkCenters, selectedWorkCenters,
}) => { }) => {
const [newStatus, setNewStatus] = useState<WorkCenterStatusEnum>( const [newStatus, setNewStatus] = useState<WorkCenterStatusEnum>(WorkCenterStatusEnum.Operational)
WorkCenterStatusEnum.Operational
);
const [newCriticality, setNewCriticality] = useState<CriticalityLevelEnum>( const [newCriticality, setNewCriticality] = useState<CriticalityLevelEnum>(
CriticalityLevelEnum.Medium CriticalityLevelEnum.Medium,
); )
const [updateStatus, setUpdateStatus] = useState(true); const [updateStatus, setUpdateStatus] = useState(true)
const [updateCriticality, setUpdateCriticality] = useState(false); const [updateCriticality, setUpdateCriticality] = useState(false)
const [reason, setReason] = useState(""); const [reason, setReason] = useState('')
if (!isOpen) return null; if (!isOpen) return null
const handleSave = () => { const handleSave = () => {
const updatedWorkCenters = selectedWorkCenters.map((workCenter) => ({ const updatedWorkCenters = selectedWorkCenters.map((workCenter) => ({
@ -41,15 +32,15 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
status: updateStatus ? newStatus : workCenter.status, status: updateStatus ? newStatus : workCenter.status,
criticality: updateCriticality ? newCriticality : workCenter.criticality, criticality: updateCriticality ? newCriticality : workCenter.criticality,
lastModificationTime: new Date(), lastModificationTime: new Date(),
})); }))
onSave(updatedWorkCenters); onSave(updatedWorkCenters)
onClose(); onClose()
}; }
const isStatusCritical = const isStatusCritical =
newStatus === WorkCenterStatusEnum.OutOfOrder || newStatus === WorkCenterStatusEnum.OutOfOrder ||
newStatus === WorkCenterStatusEnum.UnderMaintenance; newStatus === WorkCenterStatusEnum.UnderMaintenance
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -59,10 +50,7 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">
Durum Güncelle ({selectedWorkCenters.length} merkezi) Durum Güncelle ({selectedWorkCenters.length} merkezi)
</h2> </h2>
<button <button onClick={onClose} className="p-1 hover:bg-gray-100 rounded-lg transition-colors">
onClick={onClose}
className="p-1 hover:bg-gray-100 rounded-lg transition-colors"
>
<FaTimes className="w-4 h-4 text-gray-500" /> <FaTimes className="w-4 h-4 text-gray-500" />
</button> </button>
</div> </div>
@ -71,15 +59,10 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
<div className="p-4 space-y-4"> <div className="p-4 space-y-4">
{/* Selected WorkCenter List */} {/* Selected WorkCenter List */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Seçili İş Merkezleri</h3>
Seçili İş Merkezleri
</h3>
<div className="max-h-28 overflow-y-auto bg-gray-50 rounded-lg p-2"> <div className="max-h-28 overflow-y-auto bg-gray-50 rounded-lg p-2">
{selectedWorkCenters.map((workCenter) => ( {selectedWorkCenters.map((workCenter) => (
<div <div key={workCenter.id} className="flex items-center justify-between py-0.5">
key={workCenter.id}
className="flex items-center justify-between py-0.5"
>
<span className="text-sm text-gray-700"> <span className="text-sm text-gray-700">
{workCenter.code} - {workCenter.name} {workCenter.code} - {workCenter.name}
</span> </span>
@ -106,35 +89,22 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
onChange={(e) => setUpdateStatus(e.target.checked)} onChange={(e) => setUpdateStatus(e.target.checked)}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/> />
<label <label htmlFor="updateStatus" className="text-sm font-medium text-gray-700">
htmlFor="updateStatus"
className="text-sm font-medium text-gray-700"
>
Operasyonel durumu güncelle Operasyonel durumu güncelle
</label> </label>
</div> </div>
{updateStatus && ( {updateStatus && (
<div> <div>
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">Yeni Durum</label>
Yeni Durum
</label>
<select <select
value={newStatus} value={newStatus}
onChange={(e) => onChange={(e) => setNewStatus(e.target.value as WorkCenterStatusEnum)}
setNewStatus(e.target.value as WorkCenterStatusEnum)
}
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" 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={WorkCenterStatusEnum.Operational}> <option value={WorkCenterStatusEnum.Operational}>Operasyonel</option>
Operasyonel <option value={WorkCenterStatusEnum.UnderMaintenance}>Bakımda</option>
</option> <option value={WorkCenterStatusEnum.OutOfOrder}>Arızalı</option>
<option value={WorkCenterStatusEnum.UnderMaintenance}>
Bakımda
</option>
<option value={WorkCenterStatusEnum.OutOfOrder}>
Arızalı
</option>
<option value={WorkCenterStatusEnum.Retired}>Emekli</option> <option value={WorkCenterStatusEnum.Retired}>Emekli</option>
</select> </select>
@ -142,13 +112,10 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
<div className="mt-2 p-2 bg-yellow-50 border border-yellow-200 rounded-lg"> <div className="mt-2 p-2 bg-yellow-50 border border-yellow-200 rounded-lg">
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<FaExclamationTriangle className="w-4 h-4 text-yellow-600" /> <FaExclamationTriangle className="w-4 h-4 text-yellow-600" />
<span className="text-sm text-yellow-800 font-medium"> <span className="text-sm text-yellow-800 font-medium">Dikkat!</span>
Dikkat!
</span>
</div> </div>
<p className="text-sm text-yellow-700 mt-1"> <p className="text-sm text-yellow-700 mt-1">
Bu durum değişikliği merkezinin üretim kapasitesini Bu durum değişikliği merkezinin üretim kapasitesini etkileyebilir.
etkileyebilir.
</p> </p>
</div> </div>
)} )}
@ -163,10 +130,7 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
onChange={(e) => setUpdateCriticality(e.target.checked)} onChange={(e) => setUpdateCriticality(e.target.checked)}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500" className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/> />
<label <label htmlFor="updateCriticality" className="text-sm font-medium text-gray-700">
htmlFor="updateCriticality"
className="text-sm font-medium text-gray-700"
>
Kritiklik seviyesini güncelle Kritiklik seviyesini güncelle
</label> </label>
</div> </div>
@ -178,9 +142,7 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
</label> </label>
<select <select
value={newCriticality} value={newCriticality}
onChange={(e) => onChange={(e) => setNewCriticality(e.target.value as CriticalityLevelEnum)}
setNewCriticality(e.target.value as CriticalityLevelEnum)
}
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" 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={CriticalityLevelEnum.Low}>Düşük</option> <option value={CriticalityLevelEnum.Low}>Düşük</option>
@ -212,15 +174,11 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
<div className="text-sm text-blue-800 space-y-1"> <div className="text-sm text-blue-800 space-y-1">
<p> {selectedWorkCenters.length} merkezi güncellenecek</p> <p> {selectedWorkCenters.length} merkezi güncellenecek</p>
{updateStatus && ( {updateStatus && (
<p> <p> Durum "{getWorkCenterStatusText(newStatus)}" olarak değiştirilecek</p>
Durum "{getWorkCenterStatusText(newStatus)}" olarak
değiştirilecek
</p>
)} )}
{updateCriticality && ( {updateCriticality && (
<p> <p>
Kritiklik seviyesi " Kritiklik seviyesi "{getCriticalityLevelText(newCriticality)}" olarak
{getCriticalityLevelText(newCriticality)}" olarak
değiştirilecek değiştirilecek
</p> </p>
)} )}
@ -249,7 +207,7 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default StatusUpdateModal; export default StatusUpdateModal

View file

@ -1,18 +1,18 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from 'react'
import { import {
FaTimes, FaTimes,
FaSave, FaSave,
FaExclamationTriangle, FaExclamationTriangle,
FaCheckCircle, FaCheckCircle,
FaTimesCircle, FaTimesCircle,
} from "react-icons/fa"; } from 'react-icons/fa'
import { Team } from "../../../types/common"; import { Team } from '../../../types/common'
interface TeamStatusChangeModalProps { interface TeamStatusChangeModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onSave: (teamIds: string[], newStatus: boolean, reason?: string) => void; onSave: (teamIds: string[], newStatus: boolean, reason?: string) => void
selectedTeams: Team[]; selectedTeams: Team[]
} }
const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
@ -21,60 +21,60 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
onSave, onSave,
selectedTeams, selectedTeams,
}) => { }) => {
const [newStatus, setNewStatus] = useState<boolean>(true); const [newStatus, setNewStatus] = useState<boolean>(true)
const [reason, setReason] = useState(""); const [reason, setReason] = useState('')
const [errors, setErrors] = useState<Record<string, string>>({}); const [errors, setErrors] = useState<Record<string, string>>({})
const activeTeams = selectedTeams.filter((team) => team.isActive); const activeTeams = selectedTeams.filter((team) => team.isActive)
const inactiveTeams = selectedTeams.filter((team) => !team.isActive); const inactiveTeams = selectedTeams.filter((team) => !team.isActive)
useEffect(() => { useEffect(() => {
if (isOpen) { if (isOpen) {
// Reset form when modal opens // Reset form when modal opens
setNewStatus(true); setNewStatus(true)
setReason(""); setReason('')
setErrors({}); setErrors({})
} }
}, [isOpen]); }, [isOpen])
const validateForm = () => { const validateForm = () => {
const newErrors: Record<string, string> = {}; const newErrors: Record<string, string> = {}
if (!newStatus && !reason.trim()) { if (!newStatus && !reason.trim()) {
newErrors.reason = "Ekipleri pasif yaparken sebep belirtmeniz gerekli"; newErrors.reason = 'Ekipleri pasif yaparken sebep belirtmeniz gerekli'
} }
setErrors(newErrors); setErrors(newErrors)
return Object.keys(newErrors).length === 0; return Object.keys(newErrors).length === 0
}; }
const handleSave = () => { const handleSave = () => {
if (validateForm()) { if (validateForm()) {
const teamIds = selectedTeams.map((team) => team.id); const teamIds = selectedTeams.map((team) => team.id)
onSave(teamIds, newStatus, reason.trim() || undefined); onSave(teamIds, newStatus, reason.trim() || undefined)
onClose(); onClose()
} }
}; }
const getImpactAnalysis = () => { const getImpactAnalysis = () => {
const teamsToActivate = newStatus ? inactiveTeams : []; const teamsToActivate = newStatus ? inactiveTeams : []
const teamsToDeactivate = newStatus ? [] : activeTeams; const teamsToDeactivate = newStatus ? [] : activeTeams
return { return {
teamsToActivate, teamsToActivate,
teamsToDeactivate, teamsToDeactivate,
totalMembers: selectedTeams.reduce( totalMembers: selectedTeams.reduce(
(total, team) => total + team.members.filter((m) => m.isActive).length, (total, team) => total + team.members.filter((m) => m.isActive).length,
0 0,
), ),
activeMembers: activeTeams.reduce( activeMembers: activeTeams.reduce(
(total, team) => total + team.members.filter((m) => m.isActive).length, (total, team) => total + team.members.filter((m) => m.isActive).length,
0 0,
), ),
}; }
}; }
const impact = getImpactAnalysis(); const impact = getImpactAnalysis()
return ( return (
isOpen && ( isOpen && (
@ -83,12 +83,8 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<div> <div>
<h2 className="text-2xl font-bold text-gray-900"> <h2 className="text-2xl font-bold text-gray-900">Ekip Durumu Değiştir</h2>
Ekip Durumu Değiştir <p className="text-gray-600">{selectedTeams.length} ekibin durumunu değiştirin</p>
</h2>
<p className="text-gray-600">
{selectedTeams.length} ekibin durumunu değiştirin
</p>
</div> </div>
<button <button
onClick={onClose} onClick={onClose}
@ -102,9 +98,7 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
<div className="p-3 space-y-3"> <div className="p-3 space-y-3">
{/* Status Selection */} {/* Status Selection */}
<div> <div>
<h3 className="text-sm font-medium text-gray-900 mb-2"> <h3 className="text-sm font-medium text-gray-900 mb-2">Yeni Durum</h3>
Yeni Durum
</h3>
<div className="space-y-3"> <div className="space-y-3">
<label className="flex items-center p-2 border border-gray-200 rounded-lg hover:bg-gray-50 cursor-pointer"> <label className="flex items-center p-2 border border-gray-200 rounded-lg hover:bg-gray-50 cursor-pointer">
<input <input
@ -148,41 +142,31 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
<textarea <textarea
value={reason} value={reason}
onChange={(e) => { onChange={(e) => {
setReason(e.target.value); setReason(e.target.value)
if (errors.reason) { if (errors.reason) {
setErrors((prev) => ({ ...prev, reason: "" })); setErrors((prev) => ({ ...prev, reason: '' }))
} }
}} }}
rows={2} 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 ${ className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
errors.reason ? "border-red-500" : "border-gray-300" errors.reason ? 'border-red-500' : 'border-gray-300'
}`} }`}
placeholder="Ekiplerin neden pasif yapıldığınııklayın..." placeholder="Ekiplerin neden pasif yapıldığınııklayın..."
/> />
{errors.reason && ( {errors.reason && <p className="text-red-500 text-xs mt-1">{errors.reason}</p>}
<p className="text-red-500 text-xs mt-1">{errors.reason}</p>
)}
</div> </div>
)} )}
{/* Impact Analysis */} {/* Impact Analysis */}
<div className="bg-gray-50 rounded-lg p-3"> <div className="bg-gray-50 rounded-lg p-3">
<h3 className="text-sm font-medium text-gray-900 mb-3"> <h3 className="text-sm font-medium text-gray-900 mb-3">Etki Analizi</h3>
Etki Analizi
</h3>
<div className="grid grid-cols-2 gap-3 mb-3"> <div className="grid grid-cols-2 gap-3 mb-3">
<div className="text-center"> <div className="text-center">
<div className="text-base font-bold text-blue-600"> <div className="text-base font-bold text-blue-600">{selectedTeams.length}</div>
{selectedTeams.length} <div className="text-sm text-gray-600">Toplam Seçili Ekip</div>
</div>
<div className="text-sm text-gray-600">
Toplam Seçili Ekip
</div>
</div> </div>
<div className="text-center"> <div className="text-center">
<div className="text-base font-bold text-green-600"> <div className="text-base font-bold text-green-600">{impact.totalMembers}</div>
{impact.totalMembers}
</div>
<div className="text-sm text-gray-600">Toplam Üye Sayısı</div> <div className="text-sm text-gray-600">Toplam Üye Sayısı</div>
</div> </div>
</div> </div>
@ -192,12 +176,10 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
<div className="flex items-start space-x-3"> <div className="flex items-start space-x-3">
<FaExclamationTriangle className="w-5 h-5 text-yellow-600 mt-0.5" /> <FaExclamationTriangle className="w-5 h-5 text-yellow-600 mt-0.5" />
<div> <div>
<h4 className="text-sm font-medium text-yellow-800"> <h4 className="text-sm font-medium text-yellow-800">Uyarı</h4>
Uyarı
</h4>
<p className="text-sm text-yellow-700 mt-1"> <p className="text-sm text-yellow-700 mt-1">
{impact.teamsToDeactivate.length} aktif ekip pasif {impact.teamsToDeactivate.length} aktif ekip pasif yapılacak. Bu ekipler
yapılacak. Bu ekipler artık yeni emirleri alamayacak. artık yeni emirleri alamayacak.
</p> </p>
</div> </div>
</div> </div>
@ -209,12 +191,10 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
<div className="flex items-start space-x-3"> <div className="flex items-start space-x-3">
<FaCheckCircle className="w-5 h-5 text-green-600 mt-0.5" /> <FaCheckCircle className="w-5 h-5 text-green-600 mt-0.5" />
<div> <div>
<h4 className="text-sm font-medium text-green-800"> <h4 className="text-sm font-medium text-green-800">Bilgi</h4>
Bilgi
</h4>
<p className="text-sm text-green-700 mt-1"> <p className="text-sm text-green-700 mt-1">
{impact.teamsToActivate.length} pasif ekip aktif hale {impact.teamsToActivate.length} pasif ekip aktif hale gelecek. Bu ekipler
gelecek. Bu ekipler tekrar emirleri alabilecek. tekrar emirleri alabilecek.
</p> </p>
</div> </div>
</div> </div>
@ -224,9 +204,7 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
{/* Selected Teams List */} {/* Selected Teams List */}
<div> <div>
<h3 className="text-sm font-medium text-gray-900 mb-2"> <h3 className="text-sm font-medium text-gray-900 mb-2">Etkilenecek Ekipler</h3>
Etkilenecek Ekipler
</h3>
<div className="max-h-32 overflow-y-auto border border-gray-200 rounded-lg"> <div className="max-h-32 overflow-y-auto border border-gray-200 rounded-lg">
{selectedTeams.map((team) => ( {selectedTeams.map((team) => (
<div <div
@ -234,30 +212,26 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
className="flex items-center justify-between p-2 border-b border-gray-100 last:border-b-0" className="flex items-center justify-between p-2 border-b border-gray-100 last:border-b-0"
> >
<div> <div>
<h4 className="font-medium text-sm text-gray-900"> <h4 className="font-medium text-sm text-gray-900">{team.name}</h4>
{team.name}
</h4>
<p className="text-sm text-gray-600">{team.code}</p> <p className="text-sm text-gray-600">{team.code}</p>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<span <span
className={`px-2 py-1 text-xs font-semibold rounded-full ${ className={`px-2 py-1 text-xs font-semibold rounded-full ${
team.isActive team.isActive
? "bg-green-100 text-green-800" ? 'bg-green-100 text-green-800'
: "bg-gray-100 text-gray-800" : 'bg-gray-100 text-gray-800'
}`} }`}
> >
{team.isActive ? "Aktif" : "Pasif"} {team.isActive ? 'Aktif' : 'Pasif'}
</span> </span>
<span className="text-sm text-gray-500"></span> <span className="text-sm text-gray-500"></span>
<span <span
className={`px-2 py-1 text-xs font-semibold rounded-full ${ className={`px-2 py-1 text-xs font-semibold rounded-full ${
newStatus newStatus ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'
? "bg-green-100 text-green-800"
: "bg-gray-100 text-gray-800"
}`} }`}
> >
{newStatus ? "Aktif" : "Pasif"} {newStatus ? 'Aktif' : 'Pasif'}
</span> </span>
</div> </div>
</div> </div>
@ -277,9 +251,7 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
<button <button
onClick={handleSave} onClick={handleSave}
className={`px-3 py-1.5 text-sm text-white rounded-lg transition-colors flex items-center space-x-2 ${ className={`px-3 py-1.5 text-sm text-white rounded-lg transition-colors flex items-center space-x-2 ${
newStatus newStatus ? 'bg-green-600 hover:bg-green-700' : 'bg-red-600 hover:bg-red-700'
? "bg-green-600 hover:bg-green-700"
: "bg-red-600 hover:bg-red-700"
}`} }`}
> >
<FaSave className="w-4 h-4" /> <FaSave className="w-4 h-4" />
@ -289,7 +261,7 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
</div> </div>
</div> </div>
) )
); )
}; }
export default TeamStatusChangeModal; export default TeamStatusChangeModal

View file

@ -1,4 +1,4 @@
import React from "react"; import React from 'react'
import { import {
FaTimes, FaTimes,
FaEdit, FaEdit,
@ -10,8 +10,8 @@ import {
FaFileAlt, FaFileAlt,
FaTools, FaTools,
FaCalendarAlt, FaCalendarAlt,
} from "react-icons/fa"; } from 'react-icons/fa'
import { PmFaultNotification } from "../../../types/pm"; import { PmFaultNotification } from '../../../types/pm'
import { import {
getFaultTypeColor, getFaultTypeColor,
getFaultTypeText, getFaultTypeText,
@ -21,13 +21,13 @@ import {
getCriticalityLevelText, getCriticalityLevelText,
getNotificationStatusColor, getNotificationStatusColor,
getNotificationStatusText, getNotificationStatusText,
} from "../../../utils/erp"; } from '../../../utils/erp'
interface ViewFaultNotificationModalProps { interface ViewFaultNotificationModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onEdit: (notification: PmFaultNotification) => void; onEdit: (notification: PmFaultNotification) => void
notification: PmFaultNotification | null; notification: PmFaultNotification | null
} }
const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({ const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({
@ -36,7 +36,7 @@ const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({
onEdit, onEdit,
notification, notification,
}) => { }) => {
if (!isOpen || !notification) return null; if (!isOpen || !notification) return null
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -44,9 +44,7 @@ const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<div> <div>
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">{notification.notificationCode}</h2>
{notification.notificationCode}
</h2>
<p className="text-sm text-gray-500 mt-1">{notification.title}</p> <p className="text-sm text-gray-500 mt-1">{notification.title}</p>
</div> </div>
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
@ -72,28 +70,28 @@ const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({
<div className="flex flex-wrap gap-1.5"> <div className="flex flex-wrap gap-1.5">
<span <span
className={`px-2.5 py-1 rounded-full text-xs font-medium ${getNotificationStatusColor( className={`px-2.5 py-1 rounded-full text-xs font-medium ${getNotificationStatusColor(
notification.status notification.status,
)}`} )}`}
> >
{getNotificationStatusText(notification.status)} {getNotificationStatusText(notification.status)}
</span> </span>
<span <span
className={`px-2.5 py-1 rounded-full text-xs font-medium ${getPriorityColor( className={`px-2.5 py-1 rounded-full text-xs font-medium ${getPriorityColor(
notification.priority notification.priority,
)}`} )}`}
> >
{getPriorityText(notification.priority)} {getPriorityText(notification.priority)}
</span> </span>
<span <span
className={`px-2.5 py-1 rounded-full text-xs font-medium ${getFaultTypeColor( className={`px-2.5 py-1 rounded-full text-xs font-medium ${getFaultTypeColor(
notification.faultType notification.faultType,
)}`} )}`}
> >
{getFaultTypeText(notification.faultType)} {getFaultTypeText(notification.faultType)}
</span> </span>
<span <span
className={`px-2.5 py-1 rounded-full text-xs font-medium ${getCriticalityLevelColor( className={`px-2.5 py-1 rounded-full text-xs font-medium ${getCriticalityLevelColor(
notification.severity notification.severity,
)}`} )}`}
> >
Kritiklik: {getCriticalityLevelText(notification.severity)} Kritiklik: {getCriticalityLevelText(notification.severity)}
@ -104,42 +102,26 @@ const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4"> <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
<div className="space-y-3"> <div className="space-y-3">
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-3"> <h3 className="text-base font-medium text-gray-900 mb-3">Arıza Bilgileri</h3>
Arıza Bilgileri
</h3>
<div className="space-y-2"> <div className="space-y-2">
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">ıklama</label>
ıklama <p className="text-sm text-gray-800 mt-1">{notification.description}</p>
</label>
<p className="text-sm text-gray-800 mt-1">
{notification.description}
</p>
</div> </div>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">İş Merkezi Kodu</label>
İş Merkezi Kodu <p className="text-sm text-gray-800">{notification.workCenter.code}</p>
</label>
<p className="text-sm text-gray-800">
{notification.workCenter.code}
</p>
</div> </div>
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">İş Merkezi Adı</label>
İş Merkezi Adı <p className="text-sm text-gray-800">{notification.workCenter.name}</p>
</label>
<p className="text-sm text-gray-800">
{notification.workCenter.name}
</p>
</div> </div>
</div> </div>
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">Konum</label>
Konum
</label>
<p className="text-sm text-gray-800 flex items-center"> <p className="text-sm text-gray-800 flex items-center">
<FaMapMarkerAlt className="w-4 h-4 mr-2 text-gray-400" /> <FaMapMarkerAlt className="w-4 h-4 mr-2 text-gray-400" />
{notification.location} {notification.location}
@ -175,14 +157,10 @@ const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({
<div className="space-y-3"> <div className="space-y-3">
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-3"> <h3 className="text-base font-medium text-gray-900 mb-3">Süreç Bilgileri</h3>
Süreç Bilgileri
</h3>
<div className="space-y-2"> <div className="space-y-2">
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">Bildiren Kişi</label>
Bildiren Kişi
</label>
<p className="text-sm text-gray-800 flex items-center"> <p className="text-sm text-gray-800 flex items-center">
<FaUser className="w-4 h-4 mr-2 text-gray-400" /> <FaUser className="w-4 h-4 mr-2 text-gray-400" />
{notification.reportedBy} {notification.reportedBy}
@ -190,21 +168,17 @@ const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({
</div> </div>
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">Bildirim Tarihi</label>
Bildirim Tarihi
</label>
<p className="text-sm text-gray-800 flex items-center"> <p className="text-sm text-gray-800 flex items-center">
<FaCalendarAlt className="w-4 h-4 mr-2 text-gray-400" /> <FaCalendarAlt className="w-4 h-4 mr-2 text-gray-400" />
{notification.reportedAt.toLocaleDateString("tr-TR")}{" "} {notification.reportedAt.toLocaleDateString('tr-TR')}{' '}
{notification.reportedAt.toLocaleTimeString("tr-TR")} {notification.reportedAt.toLocaleTimeString('tr-TR')}
</p> </p>
</div> </div>
{notification.assignedTo && ( {notification.assignedTo && (
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">Atanan Kişi</label>
Atanan Kişi
</label>
<p className="text-sm text-gray-800 flex items-center"> <p className="text-sm text-gray-800 flex items-center">
<FaTools className="w-4 h-4 mr-2 text-gray-400" /> <FaTools className="w-4 h-4 mr-2 text-gray-400" />
{notification.assignedTo} {notification.assignedTo}
@ -214,26 +188,18 @@ const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({
{notification.workOrderId && ( {notification.workOrderId && (
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">İş Emri</label>
İş Emri <p className="text-sm text-gray-800">{notification.workOrderId}</p>
</label>
<p className="text-sm text-gray-800">
{notification.workOrderId}
</p>
</div> </div>
)} )}
{notification.closedBy && notification.closedAt && ( {notification.closedBy && notification.closedAt && (
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">Kapatan</label>
Kapatan <p className="text-sm text-gray-800">{notification.closedBy}</p>
</label>
<p className="text-sm text-gray-800">
{notification.closedBy}
</p>
<p className="text-sm text-gray-500"> <p className="text-sm text-gray-500">
{notification.closedAt.toLocaleDateString("tr-TR")}{" "} {notification.closedAt.toLocaleDateString('tr-TR')}{' '}
{notification.closedAt.toLocaleTimeString("tr-TR")} {notification.closedAt.toLocaleTimeString('tr-TR')}
</p> </p>
</div> </div>
)} )}
@ -257,12 +223,8 @@ const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({
<div className="flex items-start space-x-2"> <div className="flex items-start space-x-2">
<FaFileAlt className="w-5 h-5 text-green-600 mt-0.5" /> <FaFileAlt className="w-5 h-5 text-green-600 mt-0.5" />
<div className="flex-1"> <div className="flex-1">
<h4 className="text-sm font-medium text-green-800 mb-1"> <h4 className="text-sm font-medium text-green-800 mb-1">Çözüm Notları</h4>
Çözüm Notları <p className="text-sm text-green-700">{notification.resolutionNotes}</p>
</h4>
<p className="text-sm text-green-700">
{notification.resolutionNotes}
</p>
</div> </div>
</div> </div>
</div> </div>
@ -279,16 +241,11 @@ const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({
</div> </div>
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-3"> <div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-3">
{notification.images.map((image, index) => ( {notification.images.map((image, index) => (
<div <div key={index} className="border border-gray-200 rounded-lg p-2">
key={index}
className="border border-gray-200 rounded-lg p-2"
>
<div className="aspect-square bg-gray-100 rounded flex items-center justify-center"> <div className="aspect-square bg-gray-100 rounded flex items-center justify-center">
<FaCamera className="w-8 h-8 text-gray-400" /> <FaCamera className="w-8 h-8 text-gray-400" />
</div> </div>
<p className="text-xs text-gray-500 mt-1 truncate"> <p className="text-xs text-gray-500 mt-1 truncate">{image}</p>
{image}
</p>
</div> </div>
))} ))}
</div> </div>
@ -297,28 +254,22 @@ const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({
{/* Timeline */} {/* Timeline */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-3"> <h3 className="text-base font-medium text-gray-900 mb-3">Zaman Çizelgesi</h3>
Zaman Çizelgesi
</h3>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center space-x-3 text-sm"> <div className="flex items-center space-x-3 text-sm">
<div className="w-2 h-2 bg-blue-500 rounded-full"></div> <div className="w-2 h-2 bg-blue-500 rounded-full"></div>
<span className="text-gray-500">Oluşturuldu:</span> <span className="text-gray-500">Oluşturuldu:</span>
<span className="font-medium"> <span className="font-medium">
{notification.creationTime.toLocaleDateString("tr-TR")}{" "} {notification.creationTime.toLocaleDateString('tr-TR')}{' '}
{notification.creationTime.toLocaleTimeString("tr-TR")} {notification.creationTime.toLocaleTimeString('tr-TR')}
</span> </span>
</div> </div>
<div className="flex items-center space-x-3 text-sm"> <div className="flex items-center space-x-3 text-sm">
<div className="w-2 h-2 bg-green-500 rounded-full"></div> <div className="w-2 h-2 bg-green-500 rounded-full"></div>
<span className="text-gray-500">Son Güncelleme:</span> <span className="text-gray-500">Son Güncelleme:</span>
<span className="font-medium"> <span className="font-medium">
{notification.lastModificationTime.toLocaleDateString( {notification.lastModificationTime.toLocaleDateString('tr-TR')}{' '}
"tr-TR" {notification.lastModificationTime.toLocaleTimeString('tr-TR')}
)}{" "}
{notification.lastModificationTime.toLocaleTimeString(
"tr-TR"
)}
</span> </span>
</div> </div>
</div> </div>
@ -336,7 +287,7 @@ const ViewFaultNotificationModal: React.FC<ViewFaultNotificationModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default ViewFaultNotificationModal; export default ViewFaultNotificationModal

View file

@ -1,23 +1,13 @@
import React from "react"; import React from 'react'
import { import { FaTimes, FaTools, FaClock, FaUser, FaExclamationTriangle } from 'react-icons/fa'
FaTimes, import { PmMaintenancePlan, MaintenancePlanTypeEnum, FrequencyUnitEnum } from '../../../types/pm'
FaTools, import { mockMaterials } from '../../../mocks/mockMaterials'
FaClock, import { PriorityEnum } from '../../../types/common'
FaUser,
FaExclamationTriangle,
} from "react-icons/fa";
import {
PmMaintenancePlan,
MaintenancePlanTypeEnum,
FrequencyUnitEnum,
} from "../../../types/pm";
import { mockMaterials } from "../../../mocks/mockMaterials";
import { PriorityEnum } from "../../../types/common";
interface ViewMaintenancePlanModalProps { interface ViewMaintenancePlanModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
plan: PmMaintenancePlan | null; plan: PmMaintenancePlan | null
} }
const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
@ -25,93 +15,93 @@ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
onClose, onClose,
plan, plan,
}) => { }) => {
if (!isOpen || !plan) return null; if (!isOpen || !plan) return null
const getPlanTypeDisplay = (type: MaintenancePlanTypeEnum) => { const getPlanTypeDisplay = (type: MaintenancePlanTypeEnum) => {
const types = { const types = {
[MaintenancePlanTypeEnum.Preventive]: { [MaintenancePlanTypeEnum.Preventive]: {
label: "Önleyici Bakım", label: 'Önleyici Bakım',
color: "bg-green-100 text-green-800", color: 'bg-green-100 text-green-800',
}, },
[MaintenancePlanTypeEnum.Predictive]: { [MaintenancePlanTypeEnum.Predictive]: {
label: "Kestirimci Bakım", label: 'Kestirimci Bakım',
color: "bg-blue-100 text-blue-800", color: 'bg-blue-100 text-blue-800',
}, },
[MaintenancePlanTypeEnum.Corrective]: { [MaintenancePlanTypeEnum.Corrective]: {
label: "Düzeltici Bakım", label: 'Düzeltici Bakım',
color: "bg-orange-100 text-orange-800", color: 'bg-orange-100 text-orange-800',
}, },
[MaintenancePlanTypeEnum.Condition]: { [MaintenancePlanTypeEnum.Condition]: {
label: "Durum Bazlı Bakım", label: 'Durum Bazlı Bakım',
color: "bg-purple-100 text-purple-800", color: 'bg-purple-100 text-purple-800',
}, },
}; }
return types[type] || { label: type, color: "bg-gray-100 text-gray-800" }; return types[type] || { label: type, color: 'bg-gray-100 text-gray-800' }
}; }
const getPriorityDisplay = (priority: PriorityEnum) => { const getPriorityDisplay = (priority: PriorityEnum) => {
const priorities = { const priorities = {
[PriorityEnum.Low]: { [PriorityEnum.Low]: {
label: "Düşük", label: 'Düşük',
color: "bg-gray-100 text-gray-800", color: 'bg-gray-100 text-gray-800',
icon: null, icon: null,
}, },
[PriorityEnum.Normal]: { [PriorityEnum.Normal]: {
label: "Normal", label: 'Normal',
color: "bg-blue-100 text-blue-800", color: 'bg-blue-100 text-blue-800',
icon: null, icon: null,
}, },
[PriorityEnum.High]: { [PriorityEnum.High]: {
label: "Yüksek", label: 'Yüksek',
color: "bg-yellow-100 text-yellow-800", color: 'bg-yellow-100 text-yellow-800',
icon: FaExclamationTriangle, icon: FaExclamationTriangle,
}, },
[PriorityEnum.Urgent]: { [PriorityEnum.Urgent]: {
label: "Acil", label: 'Acil',
color: "bg-red-100 text-red-800", color: 'bg-red-100 text-red-800',
icon: FaExclamationTriangle, icon: FaExclamationTriangle,
}, },
}; }
return ( return (
priorities[priority] || { priorities[priority] || {
label: priority, label: priority,
color: "bg-gray-100 text-gray-800", color: 'bg-gray-100 text-gray-800',
icon: null, icon: null,
} }
); )
}; }
const getFrequencyDisplay = (frequency: number, unit: FrequencyUnitEnum) => { const getFrequencyDisplay = (frequency: number, unit: FrequencyUnitEnum) => {
const units = { const units = {
[FrequencyUnitEnum.Days]: frequency === 1 ? "gün" : "gün", [FrequencyUnitEnum.Days]: frequency === 1 ? 'gün' : 'gün',
[FrequencyUnitEnum.Weeks]: frequency === 1 ? "hafta" : "hafta", [FrequencyUnitEnum.Weeks]: frequency === 1 ? 'hafta' : 'hafta',
[FrequencyUnitEnum.Months]: frequency === 1 ? "ay" : "ay", [FrequencyUnitEnum.Months]: frequency === 1 ? 'ay' : 'ay',
[FrequencyUnitEnum.Years]: frequency === 1 ? "yıl" : "yıl", [FrequencyUnitEnum.Years]: frequency === 1 ? 'yıl' : 'yıl',
[FrequencyUnitEnum.Hours]: frequency === 1 ? "saat" : "saat", [FrequencyUnitEnum.Hours]: frequency === 1 ? 'saat' : 'saat',
[FrequencyUnitEnum.Cycles]: frequency === 1 ? "çevrim" : "çevrim", [FrequencyUnitEnum.Cycles]: frequency === 1 ? 'çevrim' : 'çevrim',
}; }
return `Her ${frequency} ${units[unit]}`; return `Her ${frequency} ${units[unit]}`
}; }
const formatDate = (date: Date) => { const formatDate = (date: Date) => {
return new Date(date).toLocaleDateString("tr-TR", { return new Date(date).toLocaleDateString('tr-TR', {
year: "numeric", year: 'numeric',
month: "long", month: 'long',
day: "numeric", day: 'numeric',
}); })
}; }
const formatDuration = (minutes: number) => { const formatDuration = (minutes: number) => {
if (minutes < 60) return `${minutes} dakika`; if (minutes < 60) return `${minutes} dakika`
const hours = Math.floor(minutes / 60); const hours = Math.floor(minutes / 60)
const remainingMinutes = minutes % 60; const remainingMinutes = minutes % 60
if (remainingMinutes === 0) return `${hours} saat`; if (remainingMinutes === 0) return `${hours} saat`
return `${hours} saat ${remainingMinutes} dakika`; return `${hours} saat ${remainingMinutes} dakika`
}; }
const isOverdue = plan.nextDue && new Date(plan.nextDue) < new Date(); const isOverdue = plan.nextDue && new Date(plan.nextDue) < new Date()
const planTypeInfo = getPlanTypeDisplay(plan.planType); const planTypeInfo = getPlanTypeDisplay(plan.planType)
const priorityInfo = getPriorityDisplay(plan.priority); const priorityInfo = getPriorityDisplay(plan.priority)
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -121,16 +111,11 @@ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<FaTools className="w-5 h-5 text-blue-600" /> <FaTools className="w-5 h-5 text-blue-600" />
<div> <div>
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">{plan.planCode}</h2>
{plan.planCode}
</h2>
<p className="text-sm text-gray-500">Bakım Planı Detayları</p> <p className="text-sm text-gray-500">Bakım Planı Detayları</p>
</div> </div>
</div> </div>
<button <button onClick={onClose} className="p-1 hover:bg-gray-100 rounded-lg transition-colors">
onClick={onClose}
className="p-1 hover:bg-gray-100 rounded-lg transition-colors"
>
<FaTimes className="w-4 h-4 text-gray-500" /> <FaTimes className="w-4 h-4 text-gray-500" />
</button> </button>
</div> </div>
@ -147,19 +132,15 @@ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
<span <span
className={`inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium ${priorityInfo.color}`} className={`inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium ${priorityInfo.color}`}
> >
{priorityInfo.icon && ( {priorityInfo.icon && <priorityInfo.icon className="w-3 h-3 mr-1" />}
<priorityInfo.icon className="w-3 h-3 mr-1" />
)}
{priorityInfo.label} {priorityInfo.label}
</span> </span>
<span <span
className={`inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium ${ className={`inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium ${
plan.isActive plan.isActive ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
? "bg-green-100 text-green-800"
: "bg-red-100 text-red-800"
}`} }`}
> >
{plan.isActive ? "Aktif" : "Pasif"} {plan.isActive ? 'Aktif' : 'Pasif'}
</span> </span>
{isOverdue && ( {isOverdue && (
<span className="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-red-100 text-red-800"> <span className="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-red-100 text-red-800">
@ -173,39 +154,25 @@ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4"> <div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
<div className="space-y-3"> <div className="space-y-3">
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Temel Bilgiler</h3>
Temel Bilgiler
</h3>
<div className="space-y-3"> <div className="space-y-3">
<div> <div>
<label className="block text-sm font-medium text-gray-500"> <label className="block text-sm font-medium text-gray-500">Plan Kodu</label>
Plan Kodu <p className="text-sm text-gray-900 font-mono">{plan.planCode}</p>
</label>
<p className="text-sm text-gray-900 font-mono">
{plan.planCode}
</p>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-500"> <label className="block text-sm font-medium text-gray-500">İş Merkezi</label>
İş Merkezi <p className="text-sm text-gray-900 font-mono">{plan.workCenter?.code}</p>
</label>
<p className="text-sm text-gray-900 font-mono">
{plan.workCenter?.code}
</p>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-500"> <label className="block text-sm font-medium text-gray-500">ıklama</label>
ıklama
</label>
<p className="text-sm text-gray-900">{plan.description}</p> <p className="text-sm text-gray-900">{plan.description}</p>
</div> </div>
</div> </div>
</div> </div>
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Sıklık ve Süre</h3>
Sıklık ve Süre
</h3>
<div className="space-y-3"> <div className="space-y-3">
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<FaClock className="w-4 h-4 text-gray-400" /> <FaClock className="w-4 h-4 text-gray-400" />
@ -214,25 +181,19 @@ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
</span> </span>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-500"> <label className="block text-sm font-medium text-gray-500">Tahmini Süre</label>
Tahmini Süre
</label>
<p className="text-sm text-gray-900"> <p className="text-sm text-gray-900">
{formatDuration(plan.estimatedDuration)} {formatDuration(plan.estimatedDuration)}
</p> </p>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-500"> <label className="block text-sm font-medium text-gray-500">Sonraki Bakım</label>
Sonraki Bakım
</label>
<p <p
className={`text-sm font-medium ${ className={`text-sm font-medium ${
isOverdue ? "text-red-600" : "text-gray-900" isOverdue ? 'text-red-600' : 'text-gray-900'
}`} }`}
> >
{plan.nextDue {plan.nextDue ? formatDate(plan.nextDue) : 'Belirtilmemiş'}
? formatDate(plan.nextDue)
: "Belirtilmemiş"}
</p> </p>
</div> </div>
</div> </div>
@ -241,46 +202,32 @@ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
<div className="space-y-3"> <div className="space-y-3">
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Tarih Bilgileri</h3>
Tarih Bilgileri
</h3>
<div className="space-y-3"> <div className="space-y-3">
<div> <div>
<label className="block text-sm font-medium text-gray-500"> <label className="block text-sm font-medium text-gray-500">Oluşturulma</label>
Oluşturulma <p className="text-sm text-gray-900">{formatDate(plan.creationTime)}</p>
</label>
<p className="text-sm text-gray-900">
{formatDate(plan.creationTime)}
</p>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-500"> <label className="block text-sm font-medium text-gray-500">
Son Güncelleme Son Güncelleme
</label> </label>
<p className="text-sm text-gray-900"> <p className="text-sm text-gray-900">{formatDate(plan.lastModificationTime)}</p>
{formatDate(plan.lastModificationTime)}
</p>
</div> </div>
</div> </div>
</div> </div>
<div> <div>
<h3 className="text-lg font-medium text-gray-900 mb-3"> <h3 className="text-lg font-medium text-gray-900 mb-3">İstatistikler</h3>
İstatistikler
</h3>
<div className="space-y-3"> <div className="space-y-3">
<div> <div>
<label className="block text-sm font-medium text-gray-500"> <label className="block text-sm font-medium text-gray-500">Durum</label>
Durum
</label>
<p className="text-sm text-gray-900"> <p className="text-sm text-gray-900">
{plan.isActive ? "Aktif plan" : "Pasif plan"} {plan.isActive ? 'Aktif plan' : 'Pasif plan'}
</p> </p>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-gray-500"> <label className="block text-sm font-medium text-gray-500">Tahmini Süre</label>
Tahmini Süre
</label>
<p className="text-sm text-gray-900"> <p className="text-sm text-gray-900">
{formatDuration(plan.estimatedDuration)} {formatDuration(plan.estimatedDuration)}
</p> </p>
@ -293,9 +240,7 @@ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
{/* Instructions */} {/* Instructions */}
{plan.instructions && ( {plan.instructions && (
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Bakım Talimatları</h3>
Bakım Talimatları
</h3>
<div className="bg-gray-50 rounded-lg p-3"> <div className="bg-gray-50 rounded-lg p-3">
<pre className="text-sm text-gray-700 whitespace-pre-wrap font-sans"> <pre className="text-sm text-gray-700 whitespace-pre-wrap font-sans">
{plan.instructions} {plan.instructions}
@ -327,9 +272,7 @@ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
{/* Required Materials */} {/* Required Materials */}
{plan.requiredMaterials && plan.requiredMaterials.length > 0 && ( {plan.requiredMaterials && plan.requiredMaterials.length > 0 && (
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Gerekli Malzemeler</h3>
Gerekli Malzemeler
</h3>
<div className="bg-white border border-gray-200 rounded-lg overflow-hidden"> <div className="bg-white border border-gray-200 rounded-lg overflow-hidden">
<table className="min-w-full divide-y divide-gray-200"> <table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50"> <thead className="bg-gray-50">
@ -350,9 +293,7 @@ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
</thead> </thead>
<tbody className="bg-white divide-y divide-gray-200"> <tbody className="bg-white divide-y divide-gray-200">
{plan.requiredMaterials.map((material, index) => { {plan.requiredMaterials.map((material, index) => {
const materialInfo = mockMaterials.find( const materialInfo = mockMaterials.find((m) => m.id === material.materialId)
(m) => m.id === material.materialId
);
return ( return (
<tr key={index} className="hover:bg-gray-50"> <tr key={index} className="hover:bg-gray-50">
<td className="px-4 py-3 whitespace-nowrap text-sm text-gray-900"> <td className="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
@ -361,9 +302,7 @@ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
{materialInfo?.code || material.materialId} {materialInfo?.code || material.materialId}
</div> </div>
{materialInfo && ( {materialInfo && (
<div className="text-xs text-gray-500"> <div className="text-xs text-gray-500">{materialInfo.name}</div>
{materialInfo.name}
</div>
)} )}
</div> </div>
</td> </td>
@ -377,15 +316,15 @@ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
<span <span
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${ className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
material.isRequired material.isRequired
? "bg-red-100 text-red-800" ? 'bg-red-100 text-red-800'
: "bg-green-100 text-green-800" : 'bg-green-100 text-green-800'
}`} }`}
> >
{material.isRequired ? "Zorunlu" : "Opsiyonel"} {material.isRequired ? 'Zorunlu' : 'Opsiyonel'}
</span> </span>
</td> </td>
</tr> </tr>
); )
})} })}
</tbody> </tbody>
</table> </table>
@ -406,7 +345,7 @@ const ViewMaintenancePlanModal: React.FC<ViewMaintenancePlanModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default ViewMaintenancePlanModal; export default ViewMaintenancePlanModal

View file

@ -1,39 +1,20 @@
import React from "react"; import React from 'react'
import { import { FaTimes, FaEdit, FaUser, FaAward, FaEnvelope, FaPhone, FaClock } from 'react-icons/fa'
FaTimes, import { Team, TeamRoleEnum } from '../../../types/common'
FaEdit, import { getTeamRoleColor, getTeamRoleIcon, getTeamRoleText } from '../../../utils/erp'
FaUser,
FaAward,
FaEnvelope,
FaPhone,
FaClock,
} from "react-icons/fa";
import { Team, TeamRoleEnum } from "../../../types/common";
import {
getTeamRoleColor,
getTeamRoleIcon,
getTeamRoleText,
} from "../../../utils/erp";
interface ViewTeamModalProps { interface ViewTeamModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onEdit: (team: Team) => void; onEdit: (team: Team) => void
team: Team | null; team: Team | null
} }
const ViewTeamModal: React.FC<ViewTeamModalProps> = ({ const ViewTeamModal: React.FC<ViewTeamModalProps> = ({ isOpen, onClose, onEdit, team }) => {
isOpen, if (!team) return null
onClose,
onEdit,
team,
}) => {
if (!team) return null;
const leader = team.members.find( const leader = team.members.find((member) => member.role === TeamRoleEnum.Lead)
(member) => member.role === TeamRoleEnum.Lead const activeMembers = team.members.filter((member) => member.isActive)
);
const activeMembers = team.members.filter((member) => member.isActive);
return ( return (
isOpen && isOpen &&
@ -43,9 +24,7 @@ const ViewTeamModal: React.FC<ViewTeamModalProps> = ({
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200"> <div className="flex items-center justify-between p-4 border-b border-gray-200">
<div> <div>
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">{team.name}</h2>
{team.name}
</h2>
<p className="text-sm text-gray-500 mt-1">{team.code}</p> <p className="text-sm text-gray-500 mt-1">{team.code}</p>
</div> </div>
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
@ -71,42 +50,30 @@ const ViewTeamModal: React.FC<ViewTeamModalProps> = ({
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-3"> <div className="space-y-3">
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-3"> <h3 className="text-base font-medium text-gray-900 mb-3">Ekip Bilgileri</h3>
Ekip Bilgileri
</h3>
<div className="space-y-2"> <div className="space-y-2">
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">Ekip Kodu</label>
Ekip Kodu
</label>
<p className="text-sm text-gray-900">{team.code}</p> <p className="text-sm text-gray-900">{team.code}</p>
</div> </div>
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">Ekip Adı</label>
Ekip Adı
</label>
<p className="text-sm text-gray-900">{team.name}</p> <p className="text-sm text-gray-900">{team.name}</p>
</div> </div>
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">ıklama</label>
ıklama <p className="text-sm text-gray-900">{team.description}</p>
</label>
<p className="text-sm text-gray-900">
{team.description}
</p>
</div> </div>
<div> <div>
<label className="text-sm font-medium text-gray-500"> <label className="text-sm font-medium text-gray-500">Durum</label>
Durum
</label>
<p <p
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${ className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
team.isActive team.isActive
? "bg-green-100 text-green-800" ? 'bg-green-100 text-green-800'
: "bg-gray-100 text-gray-800" : 'bg-gray-100 text-gray-800'
}`} }`}
> >
{team.isActive ? "Aktif" : "Pasif"} {team.isActive ? 'Aktif' : 'Pasif'}
</p> </p>
</div> </div>
</div> </div>
@ -115,9 +82,7 @@ const ViewTeamModal: React.FC<ViewTeamModalProps> = ({
{/* Specializations */} {/* Specializations */}
{team.specializations && team.specializations.length > 0 && ( {team.specializations && team.specializations.length > 0 && (
<div> <div>
<h4 className="text-sm font-medium text-gray-500 mb-1.5"> <h4 className="text-sm font-medium text-gray-500 mb-1.5">Uzmanlık Alanları</h4>
Uzmanlık Alanları
</h4>
<div className="flex flex-wrap gap-1.5"> <div className="flex flex-wrap gap-1.5">
{team.specializations.map((spec, index) => ( {team.specializations.map((spec, index) => (
<span <span
@ -133,22 +98,16 @@ const ViewTeamModal: React.FC<ViewTeamModalProps> = ({
</div> </div>
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-3"> <h3 className="text-base font-medium text-gray-900 mb-3">Zaman Bilgileri</h3>
Zaman Bilgileri
</h3>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center space-x-2 text-sm text-gray-600"> <div className="flex items-center space-x-2 text-sm text-gray-600">
<FaClock className="w-4 h-4" /> <FaClock className="w-4 h-4" />
<span> <span>Oluşturuldu: {team.creationTime.toLocaleDateString('tr-TR')}</span>
Oluşturuldu:{" "}
{team.creationTime.toLocaleDateString("tr-TR")}
</span>
</div> </div>
<div className="flex items-center space-x-2 text-sm text-gray-600"> <div className="flex items-center space-x-2 text-sm text-gray-600">
<FaClock className="w-4 h-4" /> <FaClock className="w-4 h-4" />
<span> <span>
Son Güncelleme:{" "} Son Güncelleme: {team.lastModificationTime.toLocaleDateString('tr-TR')}
{team.lastModificationTime.toLocaleDateString("tr-TR")}
</span> </span>
</div> </div>
</div> </div>
@ -158,9 +117,7 @@ const ViewTeamModal: React.FC<ViewTeamModalProps> = ({
{/* Team Leader */} {/* Team Leader */}
{leader && ( {leader && (
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-3"> <h3 className="text-base font-medium text-gray-900 mb-3">Ekip Lideri</h3>
Ekip Lideri
</h3>
<div className="bg-purple-50 rounded-lg p-3"> <div className="bg-purple-50 rounded-lg p-3">
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<div className="w-10 h-10 bg-purple-600 rounded-full flex items-center justify-center"> <div className="w-10 h-10 bg-purple-600 rounded-full flex items-center justify-center">
@ -169,12 +126,11 @@ const ViewTeamModal: React.FC<ViewTeamModalProps> = ({
<div className="flex-1"> <div className="flex-1">
<div className="flex items-center space-x-2 mb-1"> <div className="flex items-center space-x-2 mb-1">
<h4 className="font-medium text-gray-900"> <h4 className="font-medium text-gray-900">
{leader.employee?.firstName}{" "} {leader.employee?.firstName} {leader.employee?.lastName}
{leader.employee?.lastName}
</h4> </h4>
<span <span
className={`px-2 py-1 rounded-full text-xs font-medium flex items-center space-x-1 ${getTeamRoleColor( className={`px-2 py-1 rounded-full text-xs font-medium flex items-center space-x-1 ${getTeamRoleColor(
leader.role leader.role,
)}`} )}`}
> >
{getTeamRoleIcon(leader.role)} {getTeamRoleIcon(leader.role)}
@ -199,8 +155,7 @@ const ViewTeamModal: React.FC<ViewTeamModalProps> = ({
)} )}
</div> </div>
<div className="text-xs text-gray-500 mt-2"> <div className="text-xs text-gray-500 mt-2">
Katılma Tarihi:{" "} Katılma Tarihi: {leader.joinDate.toLocaleDateString('tr-TR')}
{leader.joinDate.toLocaleDateString("tr-TR")}
</div> </div>
</div> </div>
</div> </div>
@ -230,12 +185,11 @@ const ViewTeamModal: React.FC<ViewTeamModalProps> = ({
<div className="flex-1"> <div className="flex-1">
<div className="flex items-center space-x-2 mb-1"> <div className="flex items-center space-x-2 mb-1">
<h4 className="font-medium text-gray-900"> <h4 className="font-medium text-gray-900">
{member.employee?.firstName}{" "} {member.employee?.firstName} {member.employee?.lastName}
{member.employee?.lastName}
</h4> </h4>
<span <span
className={`px-2 py-1 rounded-full text-xs font-medium flex items-center space-x-1 ${getTeamRoleColor( className={`px-2 py-1 rounded-full text-xs font-medium flex items-center space-x-1 ${getTeamRoleColor(
member.role member.role,
)}`} )}`}
> >
{getTeamRoleIcon(member.role)} {getTeamRoleIcon(member.role)}
@ -259,8 +213,7 @@ const ViewTeamModal: React.FC<ViewTeamModalProps> = ({
</div> </div>
)} )}
<div className="text-xs text-gray-500"> <div className="text-xs text-gray-500">
Katılma Tarihi:{" "} Katılma Tarihi: {member.joinDate.toLocaleDateString('tr-TR')}
{member.joinDate.toLocaleDateString("tr-TR")}
</div> </div>
</div> </div>
</div> </div>
@ -283,7 +236,7 @@ const ViewTeamModal: React.FC<ViewTeamModalProps> = ({
</div> </div>
</div> </div>
) )
); )
}; }
export default ViewTeamModal; export default ViewTeamModal

View file

@ -1,4 +1,4 @@
import React from "react"; import React from 'react'
import { import {
FaTimes, FaTimes,
FaCog, FaCog,
@ -7,20 +7,20 @@ import {
FaUser, FaUser,
FaWrench, FaWrench,
FaExclamationTriangle, FaExclamationTriangle,
} from "react-icons/fa"; } from 'react-icons/fa'
import { PmWorkCenter, WorkOrderStatusEnum } from "../../../types/pm"; import { PmWorkCenter, WorkOrderStatusEnum } from '../../../types/pm'
import { import {
getWorkCenterStatusColor, getWorkCenterStatusColor,
getWorkCenterStatusIcon, getWorkCenterStatusIcon,
getWorkCenterStatusText, getWorkCenterStatusText,
getCriticalityLevelColor, getCriticalityLevelColor,
getCriticalityLevelText, getCriticalityLevelText,
} from "../../../utils/erp"; } from '../../../utils/erp'
interface ViewWorkCenterModalProps { interface ViewWorkCenterModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
workCenter: PmWorkCenter; workCenter: PmWorkCenter
} }
const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
@ -28,28 +28,28 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
onClose, onClose,
workCenter, workCenter,
}) => { }) => {
if (!isOpen || !workCenter) return null; if (!isOpen || !workCenter) return null
const isWarrantyExpiring = (workCenter: PmWorkCenter) => { const isWarrantyExpiring = (workCenter: PmWorkCenter) => {
if (!workCenter.warrantyExpiry) return false; if (!workCenter.warrantyExpiry) return false
const today = new Date(); const today = new Date()
const diffTime = workCenter.warrantyExpiry.getTime() - today.getTime(); const diffTime = workCenter.warrantyExpiry.getTime() - today.getTime()
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
return diffDays <= 90 && diffDays > 0; return diffDays <= 90 && diffDays > 0
}; }
const isWarrantyExpired = (workCenter: PmWorkCenter) => { const isWarrantyExpired = (workCenter: PmWorkCenter) => {
if (!workCenter.warrantyExpiry) return false; if (!workCenter.warrantyExpiry) return false
const today = new Date(); const today = new Date()
return workCenter.warrantyExpiry < today; return workCenter.warrantyExpiry < today
}; }
const getWorkCenterAge = (installationDate: Date) => { const getWorkCenterAge = (installationDate: Date) => {
const today = new Date(); const today = new Date()
const diffTime = today.getTime() - installationDate.getTime(); const diffTime = today.getTime() - installationDate.getTime()
const diffYears = Math.floor(diffTime / (1000 * 60 * 60 * 24 * 365)); const diffYears = Math.floor(diffTime / (1000 * 60 * 60 * 24 * 365))
return diffYears; return diffYears
}; }
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -59,16 +59,11 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<FaCog className="w-5 h-5 text-blue-600" /> <FaCog className="w-5 h-5 text-blue-600" />
<div> <div>
<h2 className="text-lg font-semibold text-gray-900"> <h2 className="text-lg font-semibold text-gray-900">{workCenter.name}</h2>
{workCenter.name}
</h2>
<p className="text-sm text-gray-500">{workCenter.code}</p> <p className="text-sm text-gray-500">{workCenter.code}</p>
</div> </div>
</div> </div>
<button <button onClick={onClose} className="p-1 hover:bg-gray-100 rounded-lg transition-colors">
onClick={onClose}
className="p-1 hover:bg-gray-100 rounded-lg transition-colors"
>
<FaTimes className="w-4 h-4 text-gray-500" /> <FaTimes className="w-4 h-4 text-gray-500" />
</button> </button>
</div> </div>
@ -79,15 +74,13 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-3"> <div className="space-y-3">
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Durum Bilgileri</h3>
Durum Bilgileri
</h3>
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<span className="text-gray-700">Operasyonel Durum:</span> <span className="text-gray-700">Operasyonel Durum:</span>
<span <span
className={`px-2.5 py-1 rounded-full text-xs font-medium flex items-center space-x-1.5 ${getWorkCenterStatusColor( className={`px-2.5 py-1 rounded-full text-xs font-medium flex items-center space-x-1.5 ${getWorkCenterStatusColor(
workCenter.status workCenter.status,
)}`} )}`}
> >
{getWorkCenterStatusIcon(workCenter.status)} {getWorkCenterStatusIcon(workCenter.status)}
@ -98,7 +91,7 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
<span className="text-gray-700">Kritiklik Seviyesi:</span> <span className="text-gray-700">Kritiklik Seviyesi:</span>
<span <span
className={`px-2.5 py-1 rounded-full text-xs font-medium ${getCriticalityLevelColor( className={`px-2.5 py-1 rounded-full text-xs font-medium ${getCriticalityLevelColor(
workCenter.criticality workCenter.criticality,
)}`} )}`}
> >
{getCriticalityLevelText(workCenter.criticality)} {getCriticalityLevelText(workCenter.criticality)}
@ -109,20 +102,18 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
<span <span
className={`px-2.5 py-1 rounded-full text-xs font-medium ${ className={`px-2.5 py-1 rounded-full text-xs font-medium ${
workCenter.isActive workCenter.isActive
? "bg-green-100 text-green-800" ? 'bg-green-100 text-green-800'
: "bg-red-100 text-red-800" : 'bg-red-100 text-red-800'
}`} }`}
> >
{workCenter.isActive ? "Aktif" : "Pasif"} {workCenter.isActive ? 'Aktif' : 'Pasif'}
</span> </span>
</div> </div>
</div> </div>
</div> </div>
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Lokasyon Bilgileri</h3>
Lokasyon Bilgileri
</h3>
<div className="flex items-center space-x-2 text-gray-700"> <div className="flex items-center space-x-2 text-gray-700">
<FaMapMarkerAlt className="w-4 h-4 text-blue-600" /> <FaMapMarkerAlt className="w-4 h-4 text-blue-600" />
<span>{workCenter.location}</span> <span>{workCenter.location}</span>
@ -132,38 +123,34 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
<div className="space-y-3"> <div className="space-y-3">
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Temel Bilgiler</h3>
Temel Bilgiler
</h3>
<div className="space-y-2 text-sm"> <div className="space-y-2 text-sm">
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600">Üretici:</span> <span className="text-gray-600">Üretici:</span>
<span className="text-gray-900 font-medium"> <span className="text-gray-900 font-medium">
{workCenter.manufacturer || "-"} {workCenter.manufacturer || '-'}
</span> </span>
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600">Model:</span> <span className="text-gray-600">Model:</span>
<span className="text-gray-900 font-medium"> <span className="text-gray-900 font-medium">{workCenter.model || '-'}</span>
{workCenter.model || "-"}
</span>
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600">Seri No:</span> <span className="text-gray-600">Seri No:</span>
<span className="text-gray-900 font-medium"> <span className="text-gray-900 font-medium">
{workCenter.serialNumber || "-"} {workCenter.serialNumber || '-'}
</span> </span>
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600">İş Merkezi Tipi:</span> <span className="text-gray-600">İş Merkezi Tipi:</span>
<span className="text-gray-900 font-medium"> <span className="text-gray-900 font-medium">
{workCenter.workCenterType?.name || "-"} {workCenter.workCenterType?.name || '-'}
</span> </span>
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-gray-600">Kategori:</span> <span className="text-gray-600">Kategori:</span>
<span className="text-gray-900 font-medium"> <span className="text-gray-900 font-medium">
{workCenter.workCenterType?.category || "-"} {workCenter.workCenterType?.category || '-'}
</span> </span>
</div> </div>
</div> </div>
@ -174,9 +161,7 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
{/* Description */} {/* Description */}
{workCenter.description && ( {workCenter.description && (
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">ıklama</h3>
ıklama
</h3>
<p className="text-sm text-gray-700 bg-gray-50 p-3 rounded-lg"> <p className="text-sm text-gray-700 bg-gray-50 p-3 rounded-lg">
{workCenter.description} {workCenter.description}
</p> </p>
@ -185,19 +170,15 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
{/* Date Information */} {/* Date Information */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Tarih Bilgileri</h3>
Tarih Bilgileri
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3"> <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<div className="bg-gray-50 p-3 rounded-lg"> <div className="bg-gray-50 p-3 rounded-lg">
<div className="flex items-center space-x-2 mb-2"> <div className="flex items-center space-x-2 mb-2">
<FaCalendar className="w-4 h-4 text-blue-600" /> <FaCalendar className="w-4 h-4 text-blue-600" />
<span className="font-medium text-gray-900"> <span className="font-medium text-gray-900">Kurulum Tarihi</span>
Kurulum Tarihi
</span>
</div> </div>
<p className="text-gray-700"> <p className="text-gray-700">
{workCenter.installationDate.toLocaleDateString("tr-TR")} {workCenter.installationDate.toLocaleDateString('tr-TR')}
</p> </p>
<p className="text-sm text-gray-500 mt-1"> <p className="text-sm text-gray-500 mt-1">
Yaş: {getWorkCenterAge(workCenter.installationDate)} yıl Yaş: {getWorkCenterAge(workCenter.installationDate)} yıl
@ -208,30 +189,23 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
<div className="bg-gray-50 p-3 rounded-lg"> <div className="bg-gray-50 p-3 rounded-lg">
<div className="flex items-center space-x-2 mb-2"> <div className="flex items-center space-x-2 mb-2">
<FaCalendar className="w-4 h-4 text-orange-600" /> <FaCalendar className="w-4 h-4 text-orange-600" />
<span className="font-medium text-gray-900"> <span className="font-medium text-gray-900">Garanti Bitiş Tarihi</span>
Garanti Bitiş Tarihi
</span>
</div> </div>
<p <p
className={`font-medium ${ className={`font-medium ${
isWarrantyExpired(workCenter) isWarrantyExpired(workCenter)
? "text-red-600" ? 'text-red-600'
: isWarrantyExpiring(workCenter) : isWarrantyExpiring(workCenter)
? "text-orange-600" ? 'text-orange-600'
: "text-gray-700" : 'text-gray-700'
}`} }`}
> >
{workCenter.warrantyExpiry.toLocaleDateString("tr-TR")} {workCenter.warrantyExpiry.toLocaleDateString('tr-TR')}
{isWarrantyExpiring(workCenter) && {isWarrantyExpiring(workCenter) && !isWarrantyExpired(workCenter) && (
!isWarrantyExpired(workCenter) && ( <span className="text-xs text-orange-600 ml-2">(Yakında sona eriyor)</span>
<span className="text-xs text-orange-600 ml-2"> )}
(Yakında sona eriyor)
</span>
)}
{isWarrantyExpired(workCenter) && ( {isWarrantyExpired(workCenter) && (
<span className="text-xs text-red-600 ml-2"> <span className="text-xs text-red-600 ml-2">(Garanti doldu)</span>
(Garanti doldu)
</span>
)} )}
</p> </p>
</div> </div>
@ -243,58 +217,49 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
<span className="font-medium text-gray-900">Oluşturan</span> <span className="font-medium text-gray-900">Oluşturan</span>
</div> </div>
<p className="text-sm text-gray-500 mt-1"> <p className="text-sm text-gray-500 mt-1">
{workCenter.creationTime.toLocaleDateString("tr-TR")} {workCenter.creationTime.toLocaleDateString('tr-TR')}
</p> </p>
</div> </div>
<div className="bg-gray-50 p-3 rounded-lg"> <div className="bg-gray-50 p-3 rounded-lg">
<div className="flex items-center space-x-2 mb-2"> <div className="flex items-center space-x-2 mb-2">
<FaCalendar className="w-4 h-4 text-gray-600" /> <FaCalendar className="w-4 h-4 text-gray-600" />
<span className="font-medium text-gray-900"> <span className="font-medium text-gray-900">Son Güncelleme</span>
Son Güncelleme
</span>
</div> </div>
<p className="text-gray-700"> <p className="text-gray-700">
{workCenter.lastModificationTime.toLocaleDateString("tr-TR")} {workCenter.lastModificationTime.toLocaleDateString('tr-TR')}
</p> </p>
</div> </div>
</div> </div>
</div> </div>
{/* Technical Specifications */} {/* Technical Specifications */}
{workCenter.specifications && {workCenter.specifications && workCenter.specifications.length > 0 && (
workCenter.specifications.length > 0 && ( <div>
<div> <h3 className="text-base font-medium text-gray-900 mb-2">Teknik Özellikler</h3>
<h3 className="text-base font-medium text-gray-900 mb-2"> <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
Teknik Özellikler {workCenter.specifications.map((spec) => (
</h3> <div key={spec.id} className="bg-gray-50 p-3 rounded-lg">
<div className="grid grid-cols-1 md:grid-cols-2 gap-3"> <div className="flex items-center justify-between mb-1">
{workCenter.specifications.map((spec) => ( <span className="font-medium text-gray-900">{spec.specificationName}</span>
<div key={spec.id} className="bg-gray-50 p-3 rounded-lg"> {spec.isRequired && (
<div className="flex items-center justify-between mb-1"> <span className="px-2 py-0.5 bg-blue-100 text-blue-800 text-xs rounded-full">
<span className="font-medium text-gray-900"> Zorunlu
{spec.specificationName}
</span> </span>
{spec.isRequired && ( )}
<span className="px-2 py-0.5 bg-blue-100 text-blue-800 text-xs rounded-full">
Zorunlu
</span>
)}
</div>
<p className="text-gray-700">
{spec.specificationValue} {spec.unit}
</p>
</div> </div>
))} <p className="text-gray-700">
</div> {spec.specificationValue} {spec.unit}
</p>
</div>
))}
</div> </div>
)} </div>
)}
{/* Maintenance Plans Summary */} {/* Maintenance Plans Summary */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">Bakım Planları</h3>
Bakım Planları
</h3>
<div className="bg-gray-50 p-3 rounded-lg"> <div className="bg-gray-50 p-3 rounded-lg">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
@ -310,9 +275,7 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
{/* Work Orders Summary */} {/* Work Orders Summary */}
<div> <div>
<h3 className="text-base font-medium text-gray-900 mb-2"> <h3 className="text-base font-medium text-gray-900 mb-2">İş Emirleri</h3>
İş Emirleri
</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-3"> <div className="grid grid-cols-1 md:grid-cols-3 gap-3">
<div className="bg-gray-50 p-3 rounded-lg"> <div className="bg-gray-50 p-3 rounded-lg">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
@ -331,7 +294,7 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
<div> <div>
<p className="text-lg font-semibold text-gray-900"> <p className="text-lg font-semibold text-gray-900">
{workCenter.workOrders?.filter( {workCenter.workOrders?.filter(
(wo) => wo.status === WorkOrderStatusEnum.InProgress (wo) => wo.status === WorkOrderStatusEnum.InProgress,
).length || 0} ).length || 0}
</p> </p>
<p className="text-sm text-gray-600">Devam Eden</p> <p className="text-sm text-gray-600">Devam Eden</p>
@ -367,7 +330,7 @@ const ViewWorkCenterModal: React.FC<ViewWorkCenterModalProps> = ({
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default ViewWorkCenterModal; export default ViewWorkCenterModal

View file

@ -1,4 +1,4 @@
import React from "react"; import React from 'react'
import { import {
FaTimes, FaTimes,
FaEye, FaEye,
@ -11,21 +11,21 @@ import {
FaDollarSign, FaDollarSign,
FaCheck, FaCheck,
FaExclamationTriangle, FaExclamationTriangle,
} from "react-icons/fa"; } from 'react-icons/fa'
import { PmMaintenanceWorkOrder, WorkOrderStatusEnum } from "../../../types/pm"; import { PmMaintenanceWorkOrder, WorkOrderStatusEnum } from '../../../types/pm'
import { import {
getPriorityColor, getPriorityColor,
getPriorityText, getPriorityText,
getWorkOrderStatusColor, getWorkOrderStatusColor,
getWorkOrderStatusText, getWorkOrderStatusText,
getWorkOrderTypeText, getWorkOrderTypeText,
} from "../../../utils/erp"; } from '../../../utils/erp'
interface ViewWorkOrderModalProps { interface ViewWorkOrderModalProps {
isOpen: boolean; isOpen: boolean
onClose: () => void; onClose: () => void
onEdit: (workOrder: PmMaintenanceWorkOrder) => void; onEdit: (workOrder: PmMaintenanceWorkOrder) => void
workOrder: PmMaintenanceWorkOrder; workOrder: PmMaintenanceWorkOrder
} }
const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
@ -36,36 +36,25 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
}) => { }) => {
const getCompletionPercentage = () => { const getCompletionPercentage = () => {
const completedActivities = workOrder.activities.filter( const completedActivities = workOrder.activities.filter(
(activity) => activity.completedAt (activity) => activity.completedAt,
).length; ).length
const totalActivities = workOrder.activities.length; const totalActivities = workOrder.activities.length
return totalActivities > 0 return totalActivities > 0 ? Math.round((completedActivities / totalActivities) * 100) : 0
? Math.round((completedActivities / totalActivities) * 100) }
: 0;
};
const getTotalMaterialCost = () => { const getTotalMaterialCost = () => {
return workOrder.materials.reduce( return workOrder.materials.reduce((total, material) => total + material.totalCost, 0)
(total, material) => total + material.totalCost, }
0
);
};
const getTotalPlannedDuration = () => { const getTotalPlannedDuration = () => {
return workOrder.activities.reduce( return workOrder.activities.reduce((total, activity) => total + activity.plannedDuration, 0)
(total, activity) => total + activity.plannedDuration, }
0
);
};
const getTotalActualDuration = () => { const getTotalActualDuration = () => {
return workOrder.activities.reduce( return workOrder.activities.reduce((total, activity) => total + activity.actualDuration, 0)
(total, activity) => total + activity.actualDuration, }
0
);
};
if (!isOpen) return null; if (!isOpen) return null
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
@ -74,13 +63,11 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<FaEye className="w-5 h-5 text-blue-600" /> <FaEye className="w-5 h-5 text-blue-600" />
<h3 className="text-lg font-semibold text-gray-900"> <h3 className="text-lg font-semibold text-gray-900">İş Emri Detayları</h3>
İş Emri Detayları
</h3>
</div> </div>
<span <span
className={`px-2.5 py-1 rounded-full text-xs font-medium ${getWorkOrderStatusColor( className={`px-2.5 py-1 rounded-full text-xs font-medium ${getWorkOrderStatusColor(
workOrder.status workOrder.status,
)}`} )}`}
> >
{getWorkOrderStatusText(workOrder.status)} {getWorkOrderStatusText(workOrder.status)}
@ -94,10 +81,7 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<FaEdit className="w-4 h-4" /> <FaEdit className="w-4 h-4" />
<span>Düzenle</span> <span>Düzenle</span>
</button> </button>
<button <button onClick={onClose} className="text-gray-400 hover:text-gray-600">
onClick={onClose}
className="text-gray-400 hover:text-gray-600"
>
<FaTimes className="w-5 h-5" /> <FaTimes className="w-5 h-5" />
</button> </button>
</div> </div>
@ -113,14 +97,14 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div className="space-y-1"> <div className="space-y-1">
<span <span
className={`inline-block px-2 py-0.5 rounded-full text-xs font-medium ${getWorkOrderStatusColor( className={`inline-block px-2 py-0.5 rounded-full text-xs font-medium ${getWorkOrderStatusColor(
workOrder.status workOrder.status,
)}`} )}`}
> >
{getWorkOrderTypeText(workOrder.orderType)} {getWorkOrderTypeText(workOrder.orderType)}
</span> </span>
<span <span
className={`inline-block px-2 py-0.5 rounded-full text-xs font-medium ml-2 ${getPriorityColor( className={`inline-block px-2 py-0.5 rounded-full text-xs font-medium ml-2 ${getPriorityColor(
workOrder.priority workOrder.priority,
)}`} )}`}
> >
{getPriorityText(workOrder.priority)} {getPriorityText(workOrder.priority)}
@ -133,7 +117,7 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
{workOrder.workCenter?.code || workOrder.workCenterId} {workOrder.workCenter?.code || workOrder.workCenterId}
</p> </p>
<p className="text-xs text-gray-600"> <p className="text-xs text-gray-600">
{workOrder.workCenter?.name || "İş merkezi bilgisi bulunamadı"} {workOrder.workCenter?.name || 'İş merkezi bilgisi bulunamadı'}
</p> </p>
</div> </div>
<div> <div>
@ -147,7 +131,7 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<label className="text-xs text-gray-600">Atanan</label> <label className="text-xs text-gray-600">Atanan</label>
<p className="font-medium text-sm text-gray-900 flex items-center"> <p className="font-medium text-sm text-gray-900 flex items-center">
<FaWrench className="w-4 h-4 mr-2 text-gray-500" /> <FaWrench className="w-4 h-4 mr-2 text-gray-500" />
{workOrder.assignedTo || "Atanmadı"} {workOrder.assignedTo || 'Atanmadı'}
</p> </p>
</div> </div>
</div> </div>
@ -155,9 +139,7 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
{/* Description */} {/* Description */}
<div className="mb-4"> <div className="mb-4">
<h4 className="text-base font-semibold text-gray-900 mb-2"> <h4 className="text-base font-semibold text-gray-900 mb-2">ıklama</h4>
ıklama
</h4>
<div className="bg-gray-50 rounded-lg p-3"> <div className="bg-gray-50 rounded-lg p-3">
<p className="text-sm text-gray-800">{workOrder.description}</p> <p className="text-sm text-gray-800">{workOrder.description}</p>
</div> </div>
@ -175,14 +157,14 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div className="flex justify-between items-center p-2 bg-gray-50 rounded-lg text-sm"> <div className="flex justify-between items-center p-2 bg-gray-50 rounded-lg text-sm">
<span className="text-gray-600">Oluşturulma</span> <span className="text-gray-600">Oluşturulma</span>
<span className="font-medium"> <span className="font-medium">
{workOrder.creationTime.toLocaleDateString("tr-TR")} {workOrder.creationTime.toLocaleDateString('tr-TR')}
</span> </span>
</div> </div>
{workOrder.scheduledStart && ( {workOrder.scheduledStart && (
<div className="flex justify-between items-center p-2 bg-blue-50 rounded-lg text-sm"> <div className="flex justify-between items-center p-2 bg-blue-50 rounded-lg text-sm">
<span className="text-gray-600">Planlanan Başlangıç</span> <span className="text-gray-600">Planlanan Başlangıç</span>
<span className="font-medium"> <span className="font-medium">
{workOrder.scheduledStart.toLocaleDateString("tr-TR")} {workOrder.scheduledStart.toLocaleDateString('tr-TR')}
</span> </span>
</div> </div>
)} )}
@ -190,7 +172,7 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div className="flex justify-between items-center p-2 bg-blue-50 rounded-lg text-sm"> <div className="flex justify-between items-center p-2 bg-blue-50 rounded-lg text-sm">
<span className="text-gray-600">Planlanan Bitiş</span> <span className="text-gray-600">Planlanan Bitiş</span>
<span className="font-medium"> <span className="font-medium">
{workOrder.scheduledEnd.toLocaleDateString("tr-TR")} {workOrder.scheduledEnd.toLocaleDateString('tr-TR')}
</span> </span>
</div> </div>
)} )}
@ -198,7 +180,7 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div className="flex justify-between items-center p-2 bg-green-50 rounded-lg text-sm"> <div className="flex justify-between items-center p-2 bg-green-50 rounded-lg text-sm">
<span className="text-gray-600">Gerçek Başlangıç</span> <span className="text-gray-600">Gerçek Başlangıç</span>
<span className="font-medium"> <span className="font-medium">
{workOrder.actualStart.toLocaleDateString("tr-TR")} {workOrder.actualStart.toLocaleDateString('tr-TR')}
</span> </span>
</div> </div>
)} )}
@ -206,7 +188,7 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div className="flex justify-between items-center p-2 bg-green-50 rounded-lg text-sm"> <div className="flex justify-between items-center p-2 bg-green-50 rounded-lg text-sm">
<span className="text-gray-600">Gerçek Bitiş</span> <span className="text-gray-600">Gerçek Bitiş</span>
<span className="font-medium"> <span className="font-medium">
{workOrder.actualEnd.toLocaleDateString("tr-TR")} {workOrder.actualEnd.toLocaleDateString('tr-TR')}
</span> </span>
</div> </div>
)} )}
@ -224,13 +206,13 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div className="flex justify-between items-center mb-2"> <div className="flex justify-between items-center mb-2">
<span className="text-gray-600">Tahmini Maliyet</span> <span className="text-gray-600">Tahmini Maliyet</span>
<span className="font-medium"> <span className="font-medium">
{workOrder.estimatedCost.toLocaleString("tr-TR")} {workOrder.estimatedCost.toLocaleString('tr-TR')}
</span> </span>
</div> </div>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<span className="text-gray-600">Gerçek Maliyet</span> <span className="text-gray-600">Gerçek Maliyet</span>
<span className="font-medium"> <span className="font-medium">
{workOrder.actualCost.toLocaleString("tr-TR")} {workOrder.actualCost.toLocaleString('tr-TR')}
</span> </span>
</div> </div>
</div> </div>
@ -239,9 +221,7 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div className="p-2 bg-orange-50 rounded-lg text-sm"> <div className="p-2 bg-orange-50 rounded-lg text-sm">
<div className="flex justify-between items-center mb-2"> <div className="flex justify-between items-center mb-2">
<span className="text-gray-600">İlerleme</span> <span className="text-gray-600">İlerleme</span>
<span className="font-medium"> <span className="font-medium">{getCompletionPercentage()}%</span>
{getCompletionPercentage()}%
</span>
</div> </div>
<div className="w-full bg-gray-200 rounded-full h-2"> <div className="w-full bg-gray-200 rounded-full h-2">
<div <div
@ -255,15 +235,11 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div className="p-2 bg-blue-50 rounded-lg text-sm"> <div className="p-2 bg-blue-50 rounded-lg text-sm">
<div className="flex justify-between items-center mb-2"> <div className="flex justify-between items-center mb-2">
<span className="text-gray-600">Planlanan Süre</span> <span className="text-gray-600">Planlanan Süre</span>
<span className="font-medium"> <span className="font-medium">{getTotalPlannedDuration()} dk</span>
{getTotalPlannedDuration()} dk
</span>
</div> </div>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<span className="text-gray-600">Gerçek Süre</span> <span className="text-gray-600">Gerçek Süre</span>
<span className="font-medium"> <span className="font-medium">{getTotalActualDuration()} dk</span>
{getTotalActualDuration()} dk
</span>
</div> </div>
</div> </div>
</div> </div>
@ -275,8 +251,7 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div className="mb-4"> <div className="mb-4">
<h4 className="text-base font-semibold text-gray-900 mb-2 flex items-center"> <h4 className="text-base font-semibold text-gray-900 mb-2 flex items-center">
<FaTools className="w-5 h-5 mr-2" /> <FaTools className="w-5 h-5 mr-2" />
Aktiviteler ( Aktiviteler ({workOrder.activities.filter((a) => a.completedAt).length}/
{workOrder.activities.filter((a) => a.completedAt).length}/
{workOrder.activities.length}) {workOrder.activities.length})
</h4> </h4>
<div className="space-y-2"> <div className="space-y-2">
@ -285,8 +260,8 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
key={activity.id} key={activity.id}
className={`p-3 rounded-lg border ${ className={`p-3 rounded-lg border ${
activity.completedAt activity.completedAt
? "bg-green-50 border-green-200" ? 'bg-green-50 border-green-200'
: "bg-gray-50 border-gray-200" : 'bg-gray-50 border-gray-200'
}`} }`}
> >
<div className="flex items-start justify-between"> <div className="flex items-start justify-between">
@ -304,27 +279,21 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 text-xs"> <div className="grid grid-cols-2 md:grid-cols-4 gap-3 text-xs">
<div> <div>
<span className="text-gray-600">Planlanan Süre:</span> <span className="text-gray-600">Planlanan Süre:</span>
<p className="font-medium"> <p className="font-medium">{activity.plannedDuration} dk</p>
{activity.plannedDuration} dk
</p>
</div> </div>
<div> <div>
<span className="text-gray-600">Gerçek Süre:</span> <span className="text-gray-600">Gerçek Süre:</span>
<p className="font-medium"> <p className="font-medium">{activity.actualDuration} dk</p>
{activity.actualDuration} dk
</p>
</div> </div>
<div> <div>
<span className="text-gray-600">Yapan:</span> <span className="text-gray-600">Yapan:</span>
<p className="font-medium"> <p className="font-medium">{activity.performedBy || 'Atanmadı'}</p>
{activity.performedBy || "Atanmadı"}
</p>
</div> </div>
{activity.completedAt && ( {activity.completedAt && (
<div> <div>
<span className="text-gray-600">Tamamlanma:</span> <span className="text-gray-600">Tamamlanma:</span>
<p className="font-medium"> <p className="font-medium">
{activity.completedAt.toLocaleDateString("tr-TR")} {activity.completedAt.toLocaleDateString('tr-TR')}
</p> </p>
</div> </div>
)} )}
@ -376,25 +345,19 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<tr key={material.id}> <tr key={material.id}>
<td className="px-3 py-2 text-sm"> <td className="px-3 py-2 text-sm">
<div> <div>
<p className="font-medium text-gray-900"> <p className="font-medium text-gray-900">{material.materialCode}</p>
{material.materialCode} <p className="text-gray-600">{material.materialName}</p>
</p>
<p className="text-gray-600">
{material.materialName}
</p>
</div> </div>
</td> </td>
<td className="px-3 py-2 text-sm text-gray-900"> <td className="px-3 py-2 text-sm text-gray-900">
{material.plannedQuantity} {material.plannedQuantity}
</td> </td>
<td className="px-3 py-2 text-sm text-gray-900">{material.actualQuantity}</td>
<td className="px-3 py-2 text-sm text-gray-900"> <td className="px-3 py-2 text-sm text-gray-900">
{material.actualQuantity} {material.unitCost.toLocaleString('tr-TR')}
</td>
<td className="px-3 py-2 text-sm text-gray-900">
{material.unitCost.toLocaleString("tr-TR")}
</td> </td>
<td className="px-3 py-2 text-sm font-medium text-gray-900"> <td className="px-3 py-2 text-sm font-medium text-gray-900">
{material.totalCost.toLocaleString("tr-TR")} {material.totalCost.toLocaleString('tr-TR')}
</td> </td>
</tr> </tr>
))} ))}
@ -408,7 +371,7 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
Toplam Malzeme Maliyeti Toplam Malzeme Maliyeti
</td> </td>
<td className="px-3 py-2 text-sm font-bold text-gray-900"> <td className="px-3 py-2 text-sm font-bold text-gray-900">
{getTotalMaterialCost().toLocaleString("tr-TR")} {getTotalMaterialCost().toLocaleString('tr-TR')}
</td> </td>
</tr> </tr>
</tfoot> </tfoot>
@ -420,18 +383,14 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
{/* Notes */} {/* Notes */}
{(workOrder.notes || workOrder.completionNotes) && ( {(workOrder.notes || workOrder.completionNotes) && (
<div className="mb-4"> <div className="mb-4">
<h4 className="text-base font-semibold text-gray-900 mb-2"> <h4 className="text-base font-semibold text-gray-900 mb-2">Notlar</h4>
Notlar
</h4>
<div className="space-y-2"> <div className="space-y-2">
{workOrder.notes && ( {workOrder.notes && (
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-3"> <div className="bg-yellow-50 border border-yellow-200 rounded-lg p-3">
<div className="flex items-start space-x-2"> <div className="flex items-start space-x-2">
<FaExclamationTriangle className="w-5 h-5 text-yellow-600 mt-0.5" /> <FaExclamationTriangle className="w-5 h-5 text-yellow-600 mt-0.5" />
<div> <div>
<h5 className="font-medium text-yellow-800 mb-1"> <h5 className="font-medium text-yellow-800 mb-1">İş Emri Notları</h5>
İş Emri Notları
</h5>
<p className="text-yellow-700">{workOrder.notes}</p> <p className="text-yellow-700">{workOrder.notes}</p>
</div> </div>
</div> </div>
@ -442,12 +401,8 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div className="flex items-start space-x-2"> <div className="flex items-start space-x-2">
<FaCheck className="w-5 h-5 text-green-600 mt-0.5" /> <FaCheck className="w-5 h-5 text-green-600 mt-0.5" />
<div> <div>
<h5 className="font-medium text-green-800 mb-1"> <h5 className="font-medium text-green-800 mb-1">Tamamlanma Notları</h5>
Tamamlanma Notları <p className="text-green-700">{workOrder.completionNotes}</p>
</h5>
<p className="text-green-700">
{workOrder.completionNotes}
</p>
</div> </div>
</div> </div>
</div> </div>
@ -462,22 +417,22 @@ const ViewWorkOrderModal: React.FC<ViewWorkOrderModalProps> = ({
<div> <div>
<span>Oluşturulma:</span> <span>Oluşturulma:</span>
<span className="ml-2 font-medium"> <span className="ml-2 font-medium">
{workOrder.creationTime.toLocaleDateString("tr-TR")}{" "} {workOrder.creationTime.toLocaleDateString('tr-TR')}{' '}
{workOrder.creationTime.toLocaleTimeString("tr-TR")} {workOrder.creationTime.toLocaleTimeString('tr-TR')}
</span> </span>
</div> </div>
<div> <div>
<span>Son Güncelleme:</span> <span>Son Güncelleme:</span>
<span className="ml-2 font-medium"> <span className="ml-2 font-medium">
{workOrder.lastModificationTime.toLocaleDateString("tr-TR")}{" "} {workOrder.lastModificationTime.toLocaleDateString('tr-TR')}{' '}
{workOrder.lastModificationTime.toLocaleTimeString("tr-TR")} {workOrder.lastModificationTime.toLocaleTimeString('tr-TR')}
</span> </span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default ViewWorkOrderModal; export default ViewWorkOrderModal

File diff suppressed because it is too large Load diff