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,
"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",
"Code": "App.Maintenance.Workcenters",
@ -3373,7 +3363,7 @@
{
"ParentCode": "App.Maintenance",
"Code": "App.Maintenance.Teams",
"DisplayName": "Bakım Takımları",
"DisplayName": "Bakım Ekipleri",
"Order": 5,
"Url": "/admin/maintenance/teams",
"Icon": "FcConferenceCall",

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,30 +1,23 @@
import React, { useState, useEffect } from "react";
import {
FaTimes,
FaPlus,
FaTrash,
FaCalendar,
FaClock,
FaSave,
} from "react-icons/fa";
import React, { useState, useEffect } from 'react'
import { FaTimes, FaPlus, FaTrash, FaCalendar, FaClock, FaSave } from 'react-icons/fa'
import {
PmMaintenanceWorkOrder,
WorkOrderTypeEnum,
WorkOrderStatusEnum,
PmWorkOrderMaterial,
PmWorkOrderActivity,
} from "../../../types/pm";
import { mockWorkCenters } from "../../../mocks/mockWorkCenters";
import { mockMaintenanceTeams } from "../../../mocks/mockMaintenanceTeams";
import { mockEmployees } from "../../../mocks/mockEmployees";
import { mockMaterials } from "../../../mocks/mockMaterials";
import { PriorityEnum } from "../../../types/common";
} from '../../../types/pm'
import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
import { mockMaintenanceTeams } from '../../../mocks/mockMaintenanceTeams'
import { mockEmployees } from '../../../mocks/mockEmployees'
import { mockMaterials } from '../../../mocks/mockMaterials'
import { PriorityEnum } from '../../../types/common'
interface EditWorkOrderModalProps {
isOpen: boolean;
onClose: () => void;
onSave: (workOrder: PmMaintenanceWorkOrder) => void;
workOrder: PmMaintenanceWorkOrder;
isOpen: boolean
onClose: () => void
onSave: (workOrder: PmMaintenanceWorkOrder) => void
workOrder: PmMaintenanceWorkOrder
}
const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
@ -34,28 +27,28 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
workOrder,
}) => {
const [formData, setFormData] = useState({
workOrderNumber: "",
workCenterId: "",
workOrderNumber: '',
workCenterId: '',
orderType: WorkOrderTypeEnum.Corrective,
priority: PriorityEnum.Normal,
status: WorkOrderStatusEnum.Created,
description: "",
reportedBy: "",
assignedTo: "",
maintenanceTeamId: "",
scheduledStart: "",
scheduledEnd: "",
actualStart: "",
actualEnd: "",
description: '',
reportedBy: '',
assignedTo: '',
maintenanceTeamId: '',
scheduledStart: '',
scheduledEnd: '',
actualStart: '',
actualEnd: '',
estimatedCost: 0,
actualCost: 0,
notes: "",
completionNotes: "",
});
notes: '',
completionNotes: '',
})
const [materials, setMaterials] = useState<PmWorkOrderMaterial[]>([]);
const [activities, setActivities] = useState<PmWorkOrderActivity[]>([]);
const [errors, setErrors] = useState<Record<string, string>>({});
const [materials, setMaterials] = useState<PmWorkOrderMaterial[]>([])
const [activities, setActivities] = useState<PmWorkOrderActivity[]>([])
const [errors, setErrors] = useState<Record<string, string>>({})
useEffect(() => {
if (workOrder && isOpen) {
@ -67,56 +60,52 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
status: workOrder.status,
description: workOrder.description,
reportedBy: workOrder.reportedBy,
assignedTo: workOrder.assignedTo || "",
maintenanceTeamId: workOrder.maintenanceTeamId || "",
assignedTo: workOrder.assignedTo || '',
maintenanceTeamId: workOrder.maintenanceTeamId || '',
scheduledStart: workOrder.scheduledStart
? workOrder.scheduledStart.toISOString().slice(0, 16)
: "",
: '',
scheduledEnd: workOrder.scheduledEnd
? workOrder.scheduledEnd.toISOString().slice(0, 16)
: "",
actualStart: workOrder.actualStart
? workOrder.actualStart.toISOString().slice(0, 16)
: "",
actualEnd: workOrder.actualEnd
? workOrder.actualEnd.toISOString().slice(0, 16)
: "",
: '',
actualStart: workOrder.actualStart ? workOrder.actualStart.toISOString().slice(0, 16) : '',
actualEnd: workOrder.actualEnd ? workOrder.actualEnd.toISOString().slice(0, 16) : '',
estimatedCost: workOrder.estimatedCost,
actualCost: workOrder.actualCost,
notes: workOrder.notes || "",
completionNotes: workOrder.completionNotes || "",
});
setMaterials(workOrder.materials);
setActivities(workOrder.activities);
notes: workOrder.notes || '',
completionNotes: workOrder.completionNotes || '',
})
setMaterials(workOrder.materials)
setActivities(workOrder.activities)
}
}, [workOrder, isOpen]);
}, [workOrder, isOpen])
const validateForm = () => {
const newErrors: Record<string, string> = {};
const newErrors: Record<string, string> = {}
if (!formData.description.trim()) {
newErrors.description = "Açıklama alanı zorunludur";
newErrors.description = 'Açıklama alanı zorunludur'
}
if (!formData.workCenterId) {
newErrors.workCenterId = "İş merkezi seçimi zorunludur";
newErrors.workCenterId = 'İş merkezi seçimi zorunludur'
}
if (!formData.reportedBy.trim()) {
newErrors.reportedBy = "Bildiren kişi zorunludur";
newErrors.reportedBy = 'Bildiren kişi zorunludur'
}
if (formData.estimatedCost < 0) {
newErrors.estimatedCost = "Tahmini maliyet negatif olamaz";
newErrors.estimatedCost = 'Tahmini maliyet negatif olamaz'
}
if (formData.actualCost < 0) {
newErrors.actualCost = "Gerçek maliyet negatif olamaz";
newErrors.actualCost = 'Gerçek maliyet negatif olamaz'
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
setErrors(newErrors)
return Object.keys(newErrors).length === 0
}
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!validateForm()) return;
e.preventDefault()
if (!validateForm()) return
const updatedWorkOrder: PmMaintenanceWorkOrder = {
...workOrder,
@ -129,15 +118,9 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
reportedBy: formData.reportedBy,
assignedTo: formData.assignedTo || undefined,
maintenanceTeamId: formData.maintenanceTeamId || undefined,
scheduledStart: formData.scheduledStart
? new Date(formData.scheduledStart)
: undefined,
scheduledEnd: formData.scheduledEnd
? new Date(formData.scheduledEnd)
: undefined,
actualStart: formData.actualStart
? new Date(formData.actualStart)
: undefined,
scheduledStart: formData.scheduledStart ? new Date(formData.scheduledStart) : 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,
estimatedCost: formData.estimatedCost,
actualCost: formData.actualCost,
@ -146,39 +129,35 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
notes: formData.notes || undefined,
completionNotes: formData.completionNotes || undefined,
lastModificationTime: new Date(),
};
}
onSave(updatedWorkOrder);
onClose();
};
onSave(updatedWorkOrder)
onClose()
}
const addMaterial = () => {
const newMaterial: PmWorkOrderMaterial = {
id: `mat-${Date.now()}`,
workOrderId: workOrder.id,
materialId: "",
materialCode: "",
materialName: "",
materialId: '',
materialCode: '',
materialName: '',
plannedQuantity: 1,
actualQuantity: 0,
unitCost: 0,
totalCost: 0,
};
setMaterials([...materials, newMaterial]);
};
}
setMaterials([...materials, newMaterial])
}
const removeMaterial = (index: number) => {
setMaterials(materials.filter((_, i) => i !== index));
};
setMaterials(materials.filter((_, i) => i !== index))
}
const updateMaterial = (
index: number,
field: string,
value: string | number
) => {
const updated = [...materials];
if (field === "materialId") {
const selectedMaterial = mockMaterials.find((m) => m.id === value);
const updateMaterial = (index: number, field: string, value: string | number) => {
const updated = [...materials]
if (field === 'materialId') {
const selectedMaterial = mockMaterials.find((m) => m.id === value)
if (selectedMaterial) {
updated[index] = {
...updated[index],
@ -186,75 +165,70 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
materialCode: selectedMaterial.code,
materialName: selectedMaterial.name,
unitCost: selectedMaterial.costPrice,
totalCost:
updated[index].plannedQuantity * selectedMaterial.costPrice,
};
totalCost: updated[index].plannedQuantity * selectedMaterial.costPrice,
}
}
} else {
const material = updated[index];
if (field === "plannedQuantity") {
material.plannedQuantity = value as number;
material.totalCost = material.plannedQuantity * material.unitCost;
} else if (field === "actualQuantity") {
material.actualQuantity = value as number;
} else if (field === "unitCost") {
material.unitCost = value as number;
material.totalCost = material.plannedQuantity * material.unitCost;
const material = updated[index]
if (field === 'plannedQuantity') {
material.plannedQuantity = value as number
material.totalCost = material.plannedQuantity * material.unitCost
} else if (field === 'actualQuantity') {
material.actualQuantity = value as number
} else if (field === 'unitCost') {
material.unitCost = value as number
material.totalCost = material.plannedQuantity * material.unitCost
}
}
setMaterials(updated);
};
setMaterials(updated)
}
const addActivity = () => {
const newActivity: PmWorkOrderActivity = {
id: `act-${Date.now()}`,
workOrderId: workOrder.id,
activityDescription: "",
activityDescription: '',
plannedDuration: 60,
actualDuration: 0,
performedBy: "",
notes: "",
};
setActivities([...activities, newActivity]);
};
performedBy: '',
notes: '',
}
setActivities([...activities, newActivity])
}
const removeActivity = (index: number) => {
setActivities(activities.filter((_, i) => i !== index));
};
setActivities(activities.filter((_, i) => i !== index))
}
const updateActivity = (
index: number,
field: string,
value: string | number
) => {
const updated = [...activities];
const activity = updated[index];
if (field === "activityDescription") {
activity.activityDescription = value as string;
} else if (field === "plannedDuration") {
activity.plannedDuration = value as number;
} else if (field === "actualDuration") {
activity.actualDuration = value as number;
} else if (field === "performedBy") {
activity.performedBy = value as string;
} else if (field === "notes") {
activity.notes = value as string;
const updateActivity = (index: number, field: string, value: string | number) => {
const updated = [...activities]
const activity = updated[index]
if (field === 'activityDescription') {
activity.activityDescription = value as string
} else if (field === 'plannedDuration') {
activity.plannedDuration = value as number
} else if (field === 'actualDuration') {
activity.actualDuration = value as number
} else if (field === 'performedBy') {
activity.performedBy = value as string
} else if (field === 'notes') {
activity.notes = value as string
}
setActivities(updated);
};
setActivities(updated)
}
const toggleActivityCompletion = (index: number) => {
const updated = [...activities];
const activity = updated[index];
const updated = [...activities]
const activity = updated[index]
if (activity.completedAt) {
activity.completedAt = undefined;
activity.completedAt = undefined
} else {
activity.completedAt = new Date();
activity.completedAt = new Date()
}
setActivities(updated);
};
setActivities(updated)
}
if (!isOpen) return null;
if (!isOpen) return null
return (
<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" />
İş Emrini Düzenle
</h3>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600"
>
<button onClick={onClose} className="text-gray-400 hover:text-gray-600">
<FaTimes className="w-5 h-5" />
</button>
</div>
@ -276,24 +247,18 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
{/* Basic Information */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
İş Emri No
</label>
<label className="block text-sm font-medium text-gray-700 mb-2">İş Emri No</label>
<input
type="text"
value={formData.workOrderNumber}
onChange={(e) =>
setFormData({ ...formData, workOrderNumber: e.target.value })
}
onChange={(e) => 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"
readOnly
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Durum
</label>
<label className="block text-sm font-medium text-gray-700 mb-2">Durum</label>
<select
value={formData.status}
onChange={(e) =>
@ -306,33 +271,21 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
>
<option value={WorkOrderStatusEnum.Created}>Oluşturuldu</option>
<option value={WorkOrderStatusEnum.Planned}>Planlandı</option>
<option value={WorkOrderStatusEnum.Released}>
Serbest Bırakıldı
</option>
<option value={WorkOrderStatusEnum.InProgress}>
Devam Ediyor
</option>
<option value={WorkOrderStatusEnum.Released}>Serbest Bırakıldı</option>
<option value={WorkOrderStatusEnum.InProgress}>Devam Ediyor</option>
<option value={WorkOrderStatusEnum.OnHold}>Beklemede</option>
<option value={WorkOrderStatusEnum.Completed}>
Tamamlandı
</option>
<option value={WorkOrderStatusEnum.Cancelled}>
İptal Edildi
</option>
<option value={WorkOrderStatusEnum.Completed}>Tamamlandı</option>
<option value={WorkOrderStatusEnum.Cancelled}>İptal Edildi</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
İş Merkezi *
</label>
<label className="block text-sm font-medium text-gray-700 mb-2">İş Merkezi *</label>
<select
value={formData.workCenterId}
onChange={(e) =>
setFormData({ ...formData, workCenterId: e.target.value })
}
onChange={(e) => 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 ${
errors.workCenterId ? "border-red-500" : "border-gray-300"
errors.workCenterId ? 'border-red-500' : 'border-gray-300'
}`}
>
<option value="">İş Merkezi Seçin</option>
@ -343,16 +296,12 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
))}
</select>
{errors.workCenterId && (
<p className="mt-1 text-sm text-red-600">
{errors.workCenterId}
</p>
<p className="mt-1 text-sm text-red-600">{errors.workCenterId}</p>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
İş Emri Tipi
</label>
<label className="block text-sm font-medium text-gray-700 mb-2">İş Emri Tipi</label>
<select
value={formData.orderType}
onChange={(e) =>
@ -367,16 +316,12 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<option value={WorkOrderTypeEnum.Corrective}>Düzeltici</option>
<option value={WorkOrderTypeEnum.Emergency}>Acil</option>
<option value={WorkOrderTypeEnum.Inspection}>İnceleme</option>
<option value={WorkOrderTypeEnum.Calibration}>
Kalibrasyon
</option>
<option value={WorkOrderTypeEnum.Calibration}>Kalibrasyon</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Öncelik
</label>
<label className="block text-sm font-medium text-gray-700 mb-2">Öncelik</label>
<select
value={formData.priority}
onChange={(e) =>
@ -396,17 +341,13 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
ıklama *
</label>
<label className="block text-sm font-medium text-gray-700 mb-2">ıklama *</label>
<textarea
value={formData.description}
onChange={(e) =>
setFormData({ ...formData, description: e.target.value })
}
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
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 ${
errors.description ? "border-red-500" : "border-gray-300"
errors.description ? 'border-red-500' : 'border-gray-300'
}`}
placeholder="İş emri açıklaması..."
/>
@ -418,17 +359,13 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
{/* Assignment */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Bildiren *
</label>
<label className="block text-sm font-medium text-gray-700 mb-2">Bildiren *</label>
<input
type="text"
value={formData.reportedBy}
onChange={(e) =>
setFormData({ ...formData, reportedBy: e.target.value })
}
onChange={(e) => 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 ${
errors.reportedBy ? "border-red-500" : "border-gray-300"
errors.reportedBy ? 'border-red-500' : 'border-gray-300'
}`}
placeholder="Bildiren kişi adı"
/>
@ -438,14 +375,10 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Atanan Kişi
</label>
<label className="block text-sm font-medium text-gray-700 mb-2">Atanan Kişi</label>
<select
value={formData.assignedTo}
onChange={(e) =>
setFormData({ ...formData, assignedTo: e.target.value })
}
onChange={(e) => 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"
>
<option value="">Kişi Seçin</option>
@ -458,9 +391,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Bakım Ekibi
</label>
<label className="block text-sm font-medium text-gray-700 mb-2">Bakım Ekibi</label>
<select
value={formData.maintenanceTeamId}
onChange={(e) =>
@ -491,9 +422,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<input
type="datetime-local"
value={formData.scheduledStart}
onChange={(e) =>
setFormData({ ...formData, scheduledStart: e.target.value })
}
onChange={(e) => 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"
/>
</div>
@ -506,9 +435,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<input
type="datetime-local"
value={formData.scheduledEnd}
onChange={(e) =>
setFormData({ ...formData, scheduledEnd: e.target.value })
}
onChange={(e) => 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"
/>
</div>
@ -521,9 +448,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<input
type="datetime-local"
value={formData.actualStart}
onChange={(e) =>
setFormData({ ...formData, actualStart: e.target.value })
}
onChange={(e) => 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"
/>
</div>
@ -536,9 +461,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<input
type="datetime-local"
value={formData.actualEnd}
onChange={(e) =>
setFormData({ ...formData, actualEnd: e.target.value })
}
onChange={(e) => 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"
/>
</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 ${
errors.estimatedCost ? "border-red-500" : "border-gray-300"
errors.estimatedCost ? 'border-red-500' : 'border-gray-300'
}`}
placeholder="0.00"
/>
{errors.estimatedCost && (
<p className="mt-1 text-sm text-red-600">
{errors.estimatedCost}
</p>
<p className="mt-1 text-sm text-red-600">{errors.estimatedCost}</p>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Gerçek Maliyet
</label>
<label className="block text-sm font-medium text-gray-700 mb-2">Gerçek Maliyet</label>
<input
type="number"
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 ${
errors.actualCost ? "border-red-500" : "border-gray-300"
errors.actualCost ? 'border-red-500' : 'border-gray-300'
}`}
placeholder="0.00"
/>
@ -614,20 +533,13 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</div>
{materials.map((material, index) => (
<div
key={material.id || index}
className="bg-gray-50 p-3 rounded-lg mb-2"
>
<div 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>
<label className="block text-sm font-medium text-gray-700 mb-1">
Malzeme
</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Malzeme</label>
<select
value={material.materialId}
onChange={(e) =>
updateMaterial(index, "materialId", e.target.value)
}
onChange={(e) => 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"
>
<option value="">Malzeme Seçin</option>
@ -647,11 +559,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
min="0"
value={material.plannedQuantity}
onChange={(e) =>
updateMaterial(
index,
"plannedQuantity",
parseInt(e.target.value) || 0
)
updateMaterial(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"
/>
@ -665,11 +573,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
min="0"
value={material.actualQuantity}
onChange={(e) =>
updateMaterial(
index,
"actualQuantity",
parseInt(e.target.value) || 0
)
updateMaterial(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"
/>
@ -684,19 +588,13 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
step="0.01"
value={material.unitCost}
onChange={(e) =>
updateMaterial(
index,
"unitCost",
parseFloat(e.target.value) || 0
)
updateMaterial(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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Toplam
</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Toplam</label>
<input
type="text"
value={`${material.totalCost.toFixed(2)}`}
@ -733,10 +631,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</div>
{activities.map((activity, index) => (
<div
key={activity.id || index}
className="bg-gray-50 p-3 rounded-lg mb-2"
>
<div 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="md:col-span-2">
<label className="block text-sm font-medium text-gray-700 mb-1">
@ -745,13 +640,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
<input
type="text"
value={activity.activityDescription}
onChange={(e) =>
updateActivity(
index,
"activityDescription",
e.target.value
)
}
onChange={(e) => 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"
placeholder="Aktivite açıklaması"
/>
@ -766,11 +655,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
min="0"
value={activity.plannedDuration}
onChange={(e) =>
updateActivity(
index,
"plannedDuration",
parseInt(e.target.value) || 0
)
updateActivity(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"
/>
@ -785,25 +670,17 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
min="0"
value={activity.actualDuration}
onChange={(e) =>
updateActivity(
index,
"actualDuration",
parseInt(e.target.value) || 0
)
updateActivity(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"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Yapan
</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Yapan</label>
<input
type="text"
value={activity.performedBy}
onChange={(e) =>
updateActivity(index, "performedBy", e.target.value)
}
onChange={(e) => 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"
placeholder="Yapan kişi"
/>
@ -814,11 +691,11 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
onClick={() => toggleActivityCompletion(index)}
className={`px-3 py-2 rounded text-xs ${
activity.completedAt
? "bg-green-600 text-white"
: "bg-gray-300 text-gray-700"
? 'bg-green-600 text-white'
: 'bg-gray-300 text-gray-700'
}`}
>
{activity.completedAt ? "Tamamlandı" : "Bekliyor"}
{activity.completedAt ? 'Tamamlandı' : 'Bekliyor'}
</button>
<button
type="button"
@ -836,9 +713,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</label>
<textarea
value={activity.notes}
onChange={(e) =>
updateActivity(index, "notes", e.target.value)
}
onChange={(e) => updateActivity(index, 'notes', e.target.value)}
rows={1}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="Aktivite hakkında notlar..."
@ -857,9 +732,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</label>
<textarea
value={formData.notes}
onChange={(e) =>
setFormData({ ...formData, notes: e.target.value })
}
onChange={(e) => setFormData({ ...formData, notes: e.target.value })}
rows={2}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="Genel notlar..."
@ -872,9 +745,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</label>
<textarea
value={formData.completionNotes}
onChange={(e) =>
setFormData({ ...formData, completionNotes: e.target.value })
}
onChange={(e) => setFormData({ ...formData, completionNotes: e.target.value })}
rows={2}
className="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="Tamamlanma ile ilgili notlar..."
@ -902,7 +773,7 @@ const EditWorkOrderModal: React.FC<EditWorkOrderModalProps> = ({
</form>
</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 {
FaPlus,
FaSearch,
@ -13,21 +13,17 @@ import {
FaFileAlt,
FaCamera,
FaPhone,
} from "react-icons/fa";
import {
NotificationStatusEnum,
PmFaultNotification,
PmWorkCenter,
} from "../../../types/pm";
import { mockFaultNotifications } from "../../../mocks/mockFaultNotifications";
import NewFaultNotificationModal from "./NewFaultNotificationModal";
import ViewFaultNotificationModal from "./ViewFaultNotificationModal";
import EditFaultNotificationModal from "./EditFaultNotificationModal";
import CreateWorkOrderFromNotificationModal from "./CreateWorkOrderFromNotificationModal";
import AssignNotificationModal from "./AssignNotificationModal";
import ChangeNotificationStatusModal from "./ChangeNotificationStatusModal";
import Widget from "../../../components/common/Widget";
import { PriorityEnum } from "../../../types/common";
} from 'react-icons/fa'
import { NotificationStatusEnum, PmFaultNotification, PmWorkCenter } from '../../../types/pm'
import { mockFaultNotifications } from '../../../mocks/mockFaultNotifications'
import NewFaultNotificationModal from './NewFaultNotificationModal'
import ViewFaultNotificationModal from './ViewFaultNotificationModal'
import EditFaultNotificationModal from './EditFaultNotificationModal'
import CreateWorkOrderFromNotificationModal from './CreateWorkOrderFromNotificationModal'
import AssignNotificationModal from './AssignNotificationModal'
import ChangeNotificationStatusModal from './ChangeNotificationStatusModal'
import Widget from '../../../components/common/Widget'
import { PriorityEnum } from '../../../types/common'
import {
getFaultTypeColor,
getFaultTypeText,
@ -37,139 +33,116 @@ import {
getNotificationStatusColor,
getNotificationStatusIcon,
getNotificationStatusText,
} from "../../../utils/erp";
} from '../../../utils/erp'
import { Container } from '@/components/shared'
interface AssignmentData {
notificationIds: string[];
assignedTo?: string;
teamId?: string;
notificationIds: string[]
assignedTo?: string
teamId?: string
}
interface StatusChangeData {
notificationIds: string[];
status: NotificationStatusEnum;
notificationIds: string[]
status: NotificationStatusEnum
}
const FaultNotifications: React.FC = () => {
const [searchTerm, setSearchTerm] = useState("");
const [statusFilter, setStatusFilter] = useState<
NotificationStatusEnum | "all"
>("all");
const [priorityFilter, setPriorityFilter] = useState<PriorityEnum | "all">(
"all"
);
const [showModal, setShowModal] = useState(false);
const [editingNotification, setEditingNotification] =
useState<PmFaultNotification | null>(null);
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);
const [searchTerm, setSearchTerm] = useState('')
const [statusFilter, setStatusFilter] = useState<NotificationStatusEnum | 'all'>('all')
const [priorityFilter, setPriorityFilter] = useState<PriorityEnum | 'all'>('all')
const [showModal, setShowModal] = useState(false)
const [editingNotification, setEditingNotification] = useState<PmFaultNotification | null>(null)
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
const [notifications, setNotifications] = useState<PmFaultNotification[]>(
mockFaultNotifications
);
const [notifications, setNotifications] = useState<PmFaultNotification[]>(mockFaultNotifications)
const filteredNotifications = notifications.filter((notification) => {
const matchesSearch =
notification.notificationCode
.toLowerCase()
.includes(searchTerm.toLowerCase()) ||
notification.notificationCode.toLowerCase().includes(searchTerm.toLowerCase()) ||
notification.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
notification.workCenter.code
.toLowerCase()
.includes(searchTerm.toLowerCase()) ||
notification.reportedBy.toLowerCase().includes(searchTerm.toLowerCase());
const matchesStatus =
statusFilter === "all" || notification.status === statusFilter;
const matchesPriority =
priorityFilter === "all" || notification.priority === priorityFilter;
return matchesSearch && matchesStatus && matchesPriority;
});
notification.workCenter.code.toLowerCase().includes(searchTerm.toLowerCase()) ||
notification.reportedBy.toLowerCase().includes(searchTerm.toLowerCase())
const matchesStatus = statusFilter === 'all' || notification.status === statusFilter
const matchesPriority = priorityFilter === 'all' || notification.priority === priorityFilter
return matchesSearch && matchesStatus && matchesPriority
})
const getTimeAgo = (date: Date) => {
const now = new Date();
const diffInMs = now.getTime() - date.getTime();
const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60));
const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24));
const now = new Date()
const diffInMs = now.getTime() - date.getTime()
const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60))
const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24))
if (diffInHours < 1) {
const diffInMinutes = Math.floor(diffInMs / (1000 * 60));
return `${diffInMinutes} dakika önce`;
const diffInMinutes = Math.floor(diffInMs / (1000 * 60))
return `${diffInMinutes} dakika önce`
} else if (diffInHours < 24) {
return `${diffInHours} saat önce`;
return `${diffInHours} saat önce`
} else {
return `${diffInDays} gün önce`;
return `${diffInDays} gün önce`
}
};
}
const handleAddNotification = () => {
setEditingNotification(null);
setShowModal(true);
};
setEditingNotification(null)
setShowModal(true)
}
const handleEdit = (notification: PmFaultNotification) => {
setEditingNotification(notification);
setShowModal(true);
};
setEditingNotification(notification)
setShowModal(true)
}
const handleView = (notification: PmFaultNotification) => {
setViewingNotification(notification);
};
setViewingNotification(notification)
}
const handleSelectNotification = (notificationId: string) => {
setSelectedNotifications((prev) =>
prev.includes(notificationId)
? prev.filter((id) => id !== notificationId)
: [...prev, notificationId]
);
};
: [...prev, notificationId],
)
}
const handleSaveNotification = (
notificationData: Partial<PmFaultNotification>
) => {
const handleSaveNotification = (notificationData: Partial<PmFaultNotification>) => {
if (editingNotification) {
// Update existing notification
setNotifications((prev) =>
prev.map((n) =>
n.id === editingNotification.id ? { ...n, ...notificationData } : n
)
);
prev.map((n) => (n.id === editingNotification.id ? { ...n, ...notificationData } : n)),
)
} else {
// Add new notification
setNotifications((prev) => [
...prev,
notificationData as PmFaultNotification,
]);
setNotifications((prev) => [...prev, notificationData as PmFaultNotification])
}
};
}
const handleCreateWorkOrder = () => {
setShowCreateWorkOrderModal(true);
};
setShowCreateWorkOrderModal(true)
}
const handleAssignNotifications = () => {
setShowAssignModal(true);
};
setShowAssignModal(true)
}
const handleChangeStatus = () => {
setShowStatusChangeModal(true);
};
setShowStatusChangeModal(true)
}
const handleWorkOrderSave = (workOrderData: PmWorkCenter) => {
console.log("İş emri oluşturuldu:", workOrderData);
console.log('İş emri oluşturuldu:', workOrderData)
// Here you would typically save to backend
setSelectedNotifications([]);
};
setSelectedNotifications([])
}
const handleAssignmentSave = (assignmentData: AssignmentData) => {
console.log("Atama yapıldı:", assignmentData);
console.log('Atama yapıldı:', assignmentData)
// Here you would typically save to backend
// Update notifications with assignment
setNotifications((prev) =>
@ -180,14 +153,14 @@ const FaultNotifications: React.FC = () => {
assignedTo: assignmentData.assignedTo,
status: NotificationStatusEnum.Assigned,
}
: n
)
);
setSelectedNotifications([]);
};
: n,
),
)
setSelectedNotifications([])
}
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
// Update notifications with new status
setNotifications((prev) =>
@ -198,359 +171,322 @@ const FaultNotifications: React.FC = () => {
status: statusChangeData.status,
lastModificationTime: new Date(),
}
: n
)
);
setSelectedNotifications([]);
};
: n,
),
)
setSelectedNotifications([])
}
return (
<div className="space-y-4 pt-2">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900">
Arıza Bildirimleri
</h2>
<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>
<Container>
<div className="space-y-2">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900">Arıza Bildirimleri</h2>
<p className="text-gray-600">İş merkezi arızalarını takip edin ve yönetin</p>
</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"
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>
</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>
{/* 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>
{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 */}
{showModal && !editingNotification && (
@ -565,8 +501,8 @@ const FaultNotifications: React.FC = () => {
<EditFaultNotificationModal
isOpen={showModal}
onClose={() => {
setShowModal(false);
setEditingNotification(null);
setShowModal(false)
setEditingNotification(null)
}}
onSave={handleSaveNotification}
notification={editingNotification}
@ -578,9 +514,9 @@ const FaultNotifications: React.FC = () => {
isOpen={!!viewingNotification}
onClose={() => setViewingNotification(null)}
onEdit={(notification) => {
setViewingNotification(null);
setEditingNotification(notification);
setShowModal(true);
setViewingNotification(null)
setEditingNotification(notification)
setShowModal(true)
}}
notification={viewingNotification}
/>
@ -591,9 +527,7 @@ const FaultNotifications: React.FC = () => {
isOpen={showCreateWorkOrderModal}
onClose={() => setShowCreateWorkOrderModal(false)}
onSave={handleWorkOrderSave}
notifications={notifications.filter((n) =>
selectedNotifications.includes(n.id)
)}
notifications={notifications.filter((n) => selectedNotifications.includes(n.id))}
/>
)}
@ -602,9 +536,7 @@ const FaultNotifications: React.FC = () => {
isOpen={showAssignModal}
onClose={() => setShowAssignModal(false)}
onSave={handleAssignmentSave}
notifications={notifications.filter((n) =>
selectedNotifications.includes(n.id)
)}
notifications={notifications.filter((n) => selectedNotifications.includes(n.id))}
/>
)}
@ -613,13 +545,11 @@ const FaultNotifications: React.FC = () => {
isOpen={showStatusChangeModal}
onClose={() => setShowStatusChangeModal(false)}
onSave={handleStatusChangeSave}
notifications={notifications.filter((n) =>
selectedNotifications.includes(n.id)
)}
notifications={notifications.filter((n) => 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 {
FaCalendar,
FaClock,
@ -8,124 +8,109 @@ import {
FaChevronRight,
FaEdit,
FaUser,
} from "react-icons/fa";
import {
WorkOrderStatusEnum,
CalendarView,
PmCalendarEvent,
} from "../../../types/pm";
import { mockCalendarEvents } from "../../../mocks/mockMaintenanceCalendarEvent";
import NewCalendarEventModal from "./NewCalendarEventModal";
} from 'react-icons/fa'
import { WorkOrderStatusEnum, CalendarView, PmCalendarEvent } from '../../../types/pm'
import { mockCalendarEvents } from '../../../mocks/mockMaintenanceCalendarEvent'
import NewCalendarEventModal from './NewCalendarEventModal'
import {
getPriorityColor,
getWorkOrderStatusColor,
getWorkOrderStatusIcon,
} from "../../../utils/erp";
} from '../../../utils/erp'
import { Container } from '@/components/shared'
const MaintenanceCalendar: React.FC = () => {
const [currentDate, setCurrentDate] = useState(new Date());
const [view, setView] = useState<CalendarView>("month");
const [showEventDetailModal, setShowEventDetailModal] = useState(false);
const [showNewEventModal, setShowNewEventModal] = useState(false);
const [selectedEvent, setSelectedEvent] = useState<PmCalendarEvent | null>(
null
);
const [selectedDate, setSelectedDate] = useState<Date | null>(null);
const [statusFilter, setStatusFilter] = useState<"all" | WorkOrderStatusEnum>(
"all"
);
const [currentDate, setCurrentDate] = useState(new Date())
const [view, setView] = useState<CalendarView>('month')
const [showEventDetailModal, setShowEventDetailModal] = useState(false)
const [showNewEventModal, setShowNewEventModal] = useState(false)
const [selectedEvent, setSelectedEvent] = useState<PmCalendarEvent | null>(null)
const [selectedDate, setSelectedDate] = useState<Date | null>(null)
const [statusFilter, setStatusFilter] = useState<'all' | WorkOrderStatusEnum>('all')
// Mock data - replace with actual API calls
const [events, setEvents] = useState<PmCalendarEvent[]>(mockCalendarEvents);
const [events, setEvents] = useState<PmCalendarEvent[]>(mockCalendarEvents)
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) => {
return new Date(date.getFullYear(), date.getMonth(), 1).getDay();
};
return new Date(date.getFullYear(), date.getMonth(), 1).getDay()
}
const formatDate = (date: Date) => {
return date.toLocaleDateString("tr-TR", {
year: "numeric",
month: "long",
});
};
return date.toLocaleDateString('tr-TR', {
year: 'numeric',
month: 'long',
})
}
const getEventsForDate = (date: Date) => {
return events.filter((event) => {
const eventDate = new Date(event.date);
return eventDate.toDateString() === date.toDateString();
});
};
const eventDate = new Date(event.date)
return eventDate.toDateString() === date.toDateString()
})
}
const navigateMonth = (direction: "prev" | "next") => {
const newDate = new Date(currentDate);
if (direction === "prev") {
newDate.setMonth(newDate.getMonth() - 1);
const navigateMonth = (direction: 'prev' | 'next') => {
const newDate = new Date(currentDate)
if (direction === 'prev') {
newDate.setMonth(newDate.getMonth() - 1)
} else {
newDate.setMonth(newDate.getMonth() + 1);
newDate.setMonth(newDate.getMonth() + 1)
}
setCurrentDate(newDate);
};
setCurrentDate(newDate)
}
const handleEventClick = (event: PmCalendarEvent) => {
setSelectedEvent(event);
setShowEventDetailModal(true);
};
setSelectedEvent(event)
setShowEventDetailModal(true)
}
const handleDayClick = (date: Date) => {
setSelectedDate(date);
setShowNewEventModal(true);
};
setSelectedDate(date)
setShowNewEventModal(true)
}
const handleNewEventSave = (newEvent: Partial<PmCalendarEvent>) => {
if (newEvent.id) {
setEvents((prevEvents) => [...prevEvents, newEvent as PmCalendarEvent]);
setEvents((prevEvents) => [...prevEvents, newEvent as PmCalendarEvent])
}
setShowNewEventModal(false);
setSelectedDate(null);
};
setShowNewEventModal(false)
setSelectedDate(null)
}
const renderMonthView = () => {
const daysInMonth = getDaysInMonth(currentDate);
const firstDay = getFirstDayOfMonth(currentDate);
const days = [];
const daysInMonth = getDaysInMonth(currentDate)
const firstDay = getFirstDayOfMonth(currentDate)
const days = []
// Empty cells for days before the first day of the month
for (let i = 0; i < firstDay; i++) {
days.push(
<div key={`empty-${i}`} className="p-1 border border-gray-200"></div>
);
days.push(<div key={`empty-${i}`} className="p-1 border border-gray-200"></div>)
}
// Days of the month
for (let day = 1; day <= daysInMonth; day++) {
const date = new Date(
currentDate.getFullYear(),
currentDate.getMonth(),
day
);
const dayEvents = getEventsForDate(date);
const date = new Date(currentDate.getFullYear(), currentDate.getMonth(), day)
const dayEvents = getEventsForDate(date)
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(
<div
key={day}
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)}
>
<div
className={`text-xs font-medium mb-1 ${
isToday ? "text-blue-600" : "text-gray-900"
}`}
className={`text-xs font-medium mb-1 ${isToday ? 'text-blue-600' : 'text-gray-900'}`}
>
{day}
</div>
@ -134,11 +119,11 @@ const MaintenanceCalendar: React.FC = () => {
<div
key={event.id}
onClick={(e) => {
e.stopPropagation();
handleEventClick(event);
e.stopPropagation()
handleEventClick(event)
}}
className={`text-xs p-0.5 rounded border-l-2 cursor-pointer hover:bg-gray-50 ${getPriorityColor(
event.priority
event.priority,
)} ${getWorkOrderStatusColor(event.status)}`}
>
<div className="font-medium truncate">{event.title}</div>
@ -146,9 +131,7 @@ const MaintenanceCalendar: React.FC = () => {
{getWorkOrderStatusIcon(event.status)}
<span>{event.startTime}</span>
{event.workCenterCode && (
<span className="text-gray-500">
({event.workCenterCode})
</span>
<span className="text-gray-500">({event.workCenterCode})</span>
)}
</div>
</div>
@ -159,14 +142,14 @@ const MaintenanceCalendar: React.FC = () => {
</div>
)}
</div>
</div>
);
</div>,
)
}
return (
<div className="grid grid-cols-7 gap-0 bg-white rounded-lg shadow overflow-hidden">
{/* Header */}
{["Pzt", "Sal", "Çar", "Per", "Cum", "Cmt", "Paz"].map((day) => (
{['Pzt', 'Sal', 'Çar', 'Per', 'Cum', 'Cmt', 'Paz'].map((day) => (
<div
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"
@ -176,261 +159,233 @@ const MaintenanceCalendar: React.FC = () => {
))}
{days}
</div>
);
};
)
}
const renderWeekView = () => {
const startOfWeek = new Date(currentDate);
startOfWeek.setDate(currentDate.getDate() - currentDate.getDay() + 1); // Start from Monday
const startOfWeek = new Date(currentDate)
startOfWeek.setDate(currentDate.getDate() - currentDate.getDay() + 1) // Start from Monday
const weekDays: Date[] = [];
const weekDays: Date[] = []
for (let i = 0; i < 7; i++) {
const date = new Date(startOfWeek);
date.setDate(startOfWeek.getDate() + i);
weekDays.push(date);
const date = new Date(startOfWeek)
date.setDate(startOfWeek.getDate() + i)
weekDays.push(date)
}
return (
<div className="bg-white rounded-lg shadow overflow-hidden">
<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">
Saat
</div>
<div className="p-2 bg-gray-50 text-xs font-medium text-gray-700">Saat</div>
{weekDays.map((date, index) => (
<div
key={index}
className="p-2 bg-gray-50 text-center border-l border-gray-200"
>
<div key={index} className="p-2 bg-gray-50 text-center border-l border-gray-200">
<div className="text-sm font-medium text-gray-700">
{date.toLocaleDateString("tr-TR", { weekday: "short" })}
</div>
<div className="text-lg font-bold text-gray-900">
{date.getDate()}
{date.toLocaleDateString('tr-TR', { weekday: 'short' })}
</div>
<div className="text-lg font-bold text-gray-900">{date.getDate()}</div>
</div>
))}
</div>
<div className="max-h-96 overflow-y-auto">
{Array.from({ length: 12 }, (_, hour) => hour + 8).map((hour) => (
<div
key={hour}
className="grid grid-cols-8 border-b border-gray-100"
>
<div 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">
{hour}:00
</div>
{weekDays.map((date, dayIndex) => {
const dayEvents = getEventsForDate(date).filter((event) => {
const eventHour = parseInt(
event.startTime?.split(":")[0] || "0"
);
const eventHour = parseInt(event.startTime?.split(':')[0] || '0')
return (
eventHour === hour &&
(statusFilter === "all" || event.status === statusFilter)
);
});
eventHour === hour && (statusFilter === 'all' || event.status === statusFilter)
)
})
return (
<div
key={dayIndex}
className="p-1 border-l border-gray-200 min-h-[50px] cursor-pointer hover:bg-gray-50"
onClick={() => {
const selectedDateTime = new Date(date);
selectedDateTime.setHours(hour, 0, 0, 0);
handleDayClick(selectedDateTime);
const selectedDateTime = new Date(date)
selectedDateTime.setHours(hour, 0, 0, 0)
handleDayClick(selectedDateTime)
}}
>
{dayEvents.map((event) => (
<div
key={event.id}
onClick={(e) => {
e.stopPropagation();
handleEventClick(event);
e.stopPropagation()
handleEventClick(event)
}}
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)}`}
>
<div className="font-medium truncate">
{event.title}
</div>
<div className="font-medium truncate">{event.title}</div>
<div className="text-gray-500">
{event.startTime}-{event.endTime}
</div>
</div>
))}
</div>
);
)
})}
</div>
))}
</div>
</div>
);
};
)
}
const getTodayEvents = () => {
const today = new Date();
const today = new Date()
return getEventsForDate(today).filter(
(event) => statusFilter === "all" || event.status === statusFilter
);
};
(event) => statusFilter === 'all' || event.status === statusFilter,
)
}
return (
<div className="space-y-4 pt-2">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900">Bakım Takvimi</h2>
<p className="text-gray-600">
Bakım planları ve emirlerini takip edin. Yeni planlama için
gün/saat seçin.
</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>
<Container>
<div className="space-y-2">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900">Bakım Takvimi</h2>
<p className="text-gray-600">
Bakım planları ve emirlerini takip edin. Yeni planlama için gün/saat seçin.
</p>
</div>
<button
onClick={() => setCurrentDate(new Date())}
className="px-3 py-1.5 text-sm text-blue-600 hover:bg-blue-50 rounded-lg"
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"
>
Bugün
<FaPlus className="w-4 h-4" />
<span>Yeni Planlama</span>
</button>
</div>
</div>
{/* Calendar View */}
<div className="grid grid-cols-1 lg:grid-cols-4 gap-4">
<div className="lg:col-span-3">
{view === "month" && renderMonthView()}
{view === "week" && renderWeekView()}
{/* 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>
<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>
{/* Today's Events Sidebar */}
<div className="bg-white rounded-lg shadow p-4">
<h4 className="text-base font-semibold text-gray-900 mb-3">
Bugünün Etkinlikleri
</h4>
<div className="space-y-3">
{getTodayEvents().map((event) => (
<div
key={event.id}
onClick={() => handleEventClick(event)}
className={`p-2 border-l-4 rounded-r-lg cursor-pointer hover:bg-gray-50 ${getPriorityColor(
event.priority
)}`}
>
<div className="flex items-start justify-between">
<div className="flex-1">
<h5 className="text-sm font-medium text-gray-900">
{event.title}
</h5>
<p className="text-xs text-gray-500 mt-1">
{event.workCenterCode}
</p>
<div className="flex items-center space-x-2 mt-2">
<FaClock className="w-3 h-3 text-gray-400" />
<span className="text-xs text-gray-500">
{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" />
{/* Calendar View */}
<div className="grid grid-cols-1 lg:grid-cols-4 gap-4">
<div className="lg:col-span-3">
{view === 'month' && renderMonthView()}
{view === 'week' && renderWeekView()}
</div>
{/* Today's Events Sidebar */}
<div className="bg-white rounded-lg shadow p-4">
<h4 className="text-base font-semibold text-gray-900 mb-3">Bugünün Etkinlikleri</h4>
<div className="space-y-3">
{getTodayEvents().map((event) => (
<div
key={event.id}
onClick={() => handleEventClick(event)}
className={`p-2 border-l-4 rounded-r-lg cursor-pointer hover:bg-gray-50 ${getPriorityColor(
event.priority,
)}`}
>
<div className="flex items-start justify-between">
<div className="flex-1">
<h5 className="text-sm font-medium text-gray-900">{event.title}</h5>
<p className="text-xs text-gray-500 mt-1">{event.workCenterCode}</p>
<div className="flex items-center space-x-2 mt-2">
<FaClock className="w-3 h-3 text-gray-400" />
<span className="text-xs text-gray-500">
{event.assignedTo}
{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">{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>
<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>
))}
{getTodayEvents().length === 0 && (
<div className="text-center py-8">
<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>
</div>
)}
))}
{getTodayEvents().length === 0 && (
<div className="text-center py-8">
<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>
</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="flex items-start justify-between mb-3">
<div>
<h3 className="text-base font-semibold text-gray-900">
{selectedEvent.title}
</h3>
<p className="text-sm text-gray-500 mt-1">
{selectedEvent.workCenterCode}
</p>
<h3 className="text-base font-semibold text-gray-900">{selectedEvent.title}</h3>
<p className="text-sm text-gray-500 mt-1">{selectedEvent.workCenterCode}</p>
</div>
<button
onClick={() => setShowEventDetailModal(false)}
@ -458,46 +409,34 @@ const MaintenanceCalendar: React.FC = () => {
<div className="grid grid-cols-2 gap-4 mb-4">
<div>
<label className="text-sm font-medium text-gray-500">
Tarih & Saat
</label>
<label className="text-sm font-medium text-gray-500">Tarih & Saat</label>
<p className="text-sm text-gray-900">
{selectedEvent.date.toLocaleDateString("tr-TR")} -{" "}
{selectedEvent.startTime} / {selectedEvent.endTime}
{selectedEvent.date.toLocaleDateString('tr-TR')} - {selectedEvent.startTime} /{' '}
{selectedEvent.endTime}
</p>
</div>
<div>
<label className="text-sm font-medium text-gray-500">
Süre
</label>
<p className="text-sm text-gray-900">
{selectedEvent.duration} dakika
</p>
<label className="text-sm font-medium text-gray-500">Süre</label>
<p className="text-sm text-gray-900">{selectedEvent.duration} dakika</p>
</div>
<div>
<label className="text-sm font-medium text-gray-500">
Atanan Kişi
</label>
<p className="text-sm text-gray-900">
{selectedEvent.assignedTo || "Atanmadı"}
</p>
<label className="text-sm font-medium text-gray-500">Atanan Kişi</label>
<p className="text-sm text-gray-900">{selectedEvent.assignedTo || 'Atanmadı'}</p>
</div>
<div>
<label className="text-sm font-medium text-gray-500">
Durum
</label>
<label className="text-sm font-medium text-gray-500">Durum</label>
<span
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${getWorkOrderStatusColor(
selectedEvent.status
selectedEvent.status,
)}`}
>
{selectedEvent.status === WorkOrderStatusEnum.Planned
? "Planlandı"
? 'Planlandı'
: selectedEvent.status === WorkOrderStatusEnum.InProgress
? "Devam Ediyor"
: selectedEvent.status === WorkOrderStatusEnum.Completed
? "Tamamlandı"
: "Bekliyor"}
? 'Devam Ediyor'
: selectedEvent.status === WorkOrderStatusEnum.Completed
? 'Tamamlandı'
: 'Bekliyor'}
</span>
</div>
</div>
@ -522,14 +461,14 @@ const MaintenanceCalendar: React.FC = () => {
<NewCalendarEventModal
isOpen={showNewEventModal}
onClose={() => {
setShowNewEventModal(false);
setSelectedDate(null);
setShowNewEventModal(false)
setSelectedDate(null)
}}
onSave={handleNewEventSave}
selectedDate={selectedDate || undefined}
/>
</div>
);
};
</Container>
)
}
export default MaintenanceCalendar;
export default MaintenanceCalendar

View file

@ -1,18 +1,18 @@
import React, { useState } from "react";
import { FaTimes, FaSave, FaPlus } from "react-icons/fa";
import React, { useState } from 'react'
import { FaTimes, FaSave, FaPlus } from 'react-icons/fa'
import {
PmWorkCenter,
MaintenancePlanTypeEnum,
FrequencyUnitEnum,
PmMaintenancePlan,
} from "../../../types/pm";
import { PriorityEnum } from "../../../types/common";
} from '../../../types/pm'
import { PriorityEnum } from '../../../types/common'
interface MaintenancePlanModalProps {
isOpen: boolean;
onClose: () => void;
onSave: (planData: PmMaintenancePlan[]) => void;
selectedWorkCenters: PmWorkCenter[];
isOpen: boolean
onClose: () => void
onSave: (planData: PmMaintenancePlan[]) => void
selectedWorkCenters: PmWorkCenter[]
}
const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
@ -23,55 +23,46 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
}) => {
const [planData, setPlanData] = useState({
planType: MaintenancePlanTypeEnum.Preventive,
description: "",
description: '',
frequency: 1,
frequencyUnit: FrequencyUnitEnum.Months,
estimatedDuration: 60,
priority: PriorityEnum.Normal,
instructions: "",
instructions: '',
requiredSkills: [] as string[],
nextDue: new Date(),
});
})
const [newSkill, setNewSkill] = useState("");
const [newSkill, setNewSkill] = useState('')
if (!isOpen) return null;
if (!isOpen) return null
const handleInputChange = (
e: React.ChangeEvent<
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
>
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>,
) => {
const { name, value, type } = e.target;
const { name, value, type } = e.target
setPlanData((prev) => ({
...prev,
[name]:
type === "date"
? new Date(value)
: type === "number"
? Number(value)
: value,
}));
};
[name]: type === 'date' ? new Date(value) : type === 'number' ? Number(value) : value,
}))
}
const addSkill = () => {
if (newSkill.trim() && !planData.requiredSkills.includes(newSkill.trim())) {
setPlanData((prev) => ({
...prev,
requiredSkills: [...prev.requiredSkills, newSkill.trim()],
}));
setNewSkill("");
}))
setNewSkill('')
}
};
}
const removeSkill = (skillToRemove: string) => {
setPlanData((prev) => ({
...prev,
requiredSkills: prev.requiredSkills.filter(
(skill) => skill !== skillToRemove
),
}));
};
requiredSkills: prev.requiredSkills.filter((skill) => skill !== skillToRemove),
}))
}
const handleSave = () => {
const plansToCreate = selectedWorkCenters.map((workCenter) => ({
@ -84,11 +75,11 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
isActive: true,
creationTime: new Date(),
lastModificationTime: new Date(),
}));
}))
onSave(plansToCreate);
onClose();
};
onSave(plansToCreate)
onClose()
}
return (
<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">
Bakım Planı Oluştur ({selectedWorkCenters.length} merkezi)
</h2>
<button
onClick={onClose}
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
>
<button onClick={onClose} className="p-2 hover:bg-gray-100 rounded-lg transition-colors">
<FaTimes className="w-5 h-5 text-gray-500" />
</button>
</div>
@ -110,21 +98,14 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
<div className="p-4 space-y-4">
{/* Selected Work Center List */}
<div>
<h3 className="text-sm font-medium text-gray-900 mb-2">
Seçili İş Merkezleri
</h3>
<h3 className="text-sm font-medium text-gray-900 mb-2">Seçili İş Merkezleri</h3>
<div className="max-h-28 overflow-y-auto bg-gray-50 rounded-lg p-2">
{selectedWorkCenters.map((workCenter) => (
<div
key={workCenter.id}
className="flex items-center justify-between py-0.5"
>
<div key={workCenter.id} className="flex items-center justify-between py-0.5">
<span className="text-sm text-gray-700">
{workCenter.code} - {workCenter.name}
</span>
<span className="text-xs text-gray-500">
{workCenter.location}
</span>
<span className="text-xs text-gray-500">{workCenter.location}</span>
</div>
))}
</div>
@ -132,38 +113,24 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
{/* Plan Details */}
<div>
<h3 className="text-sm font-medium text-gray-900 mb-2">
Plan Detayları
</h3>
<h3 className="text-sm font-medium text-gray-900 mb-2">Plan Detayları</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Plan Tipi
</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Plan Tipi</label>
<select
name="planType"
value={planData.planType}
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"
>
<option value={MaintenancePlanTypeEnum.Preventive}>
Önleyici Bakım
</option>
<option value={MaintenancePlanTypeEnum.Predictive}>
Kestirimci Bakım
</option>
<option value={MaintenancePlanTypeEnum.Corrective}>
Düzeltici Bakım
</option>
<option value={MaintenancePlanTypeEnum.Condition}>
Durum Bazlı Bakım
</option>
<option value={MaintenancePlanTypeEnum.Preventive}>Önleyici Bakım</option>
<option value={MaintenancePlanTypeEnum.Predictive}>Kestirimci Bakım</option>
<option value={MaintenancePlanTypeEnum.Corrective}>Düzeltici Bakım</option>
<option value={MaintenancePlanTypeEnum.Condition}>Durum Bazlı Bakım</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Öncelik
</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Öncelik</label>
<select
name="priority"
value={planData.priority}
@ -191,7 +158,7 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
onChange={(e) => setNewSkill(e.target.value)}
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"
onKeyPress={(e) => e.key === "Enter" && addSkill()}
onKeyPress={(e) => e.key === 'Enter' && addSkill()}
/>
<button
type="button"
@ -241,7 +208,7 @@ const MaintenancePlanModal: React.FC<MaintenancePlanModalProps> = ({
</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 {
FaPlus,
FaSearch,
@ -10,489 +10,442 @@ import {
FaTrash,
FaEye,
FaTasks,
} from "react-icons/fa";
} from 'react-icons/fa'
import {
PmMaintenancePlan,
MaintenancePlanTypeEnum,
PmMaintenanceWorkOrder,
} from "../../../types/pm";
import { mockMaintenancePlans } from "../../../mocks/mockMaintenancePlans";
import NewMaintenancePlanModal from "./NewMaintenancePlanModal";
import ViewMaintenancePlanModal from "./ViewMaintenancePlanModal";
import EditMaintenancePlanModal from "./EditMaintenancePlanModal";
import CreateWorkOrderModal from "./CreateWorkOrderModal";
import PlanStatusChangeModal from "./PlanStatusChangeModal";
import Widget from "../../../components/common/Widget";
import { PriorityEnum } from "../../../types/common";
} from '../../../types/pm'
import { mockMaintenancePlans } from '../../../mocks/mockMaintenancePlans'
import NewMaintenancePlanModal from './NewMaintenancePlanModal'
import ViewMaintenancePlanModal from './ViewMaintenancePlanModal'
import EditMaintenancePlanModal from './EditMaintenancePlanModal'
import CreateWorkOrderModal from './CreateWorkOrderModal'
import PlanStatusChangeModal from './PlanStatusChangeModal'
import Widget from '../../../components/common/Widget'
import { PriorityEnum } from '../../../types/common'
import {
getFrequencyUnitText,
getMaintenancePlanTypeColor,
getMaintenancePlanTypeText,
getPriorityColor,
} from "../../../utils/erp";
} from '../../../utils/erp'
import { Container } from '@/components/shared'
const MaintenancePlans: React.FC = () => {
const [searchTerm, setSearchTerm] = useState("");
const [typeFilter, setTypeFilter] = useState<MaintenancePlanTypeEnum | "all">(
"all"
);
const [statusFilter, setStatusFilter] = useState<
"active" | "inactive" | "all"
>("all");
const [editingPlan, setEditingPlan] = useState<PmMaintenancePlan | null>(
null
);
const [selectedPlans, setSelectedPlans] = useState<string[]>([]);
const [searchTerm, setSearchTerm] = useState('')
const [typeFilter, setTypeFilter] = useState<MaintenancePlanTypeEnum | 'all'>('all')
const [statusFilter, setStatusFilter] = useState<'active' | 'inactive' | 'all'>('all')
const [editingPlan, setEditingPlan] = useState<PmMaintenancePlan | null>(null)
const [selectedPlans, setSelectedPlans] = useState<string[]>([])
// Modal states
const [showNewModal, setShowNewModal] = useState(false);
const [showViewModal, setShowViewModal] = useState(false);
const [showEditModal, setShowEditModal] = useState(false);
const [showWorkOrderModal, setShowWorkOrderModal] = useState(false);
const [showStatusModal, setShowStatusModal] = useState(false);
const [viewingPlan, setViewingPlan] = useState<PmMaintenancePlan | null>(
null
);
const [showNewModal, setShowNewModal] = useState(false)
const [showViewModal, setShowViewModal] = useState(false)
const [showEditModal, setShowEditModal] = useState(false)
const [showWorkOrderModal, setShowWorkOrderModal] = useState(false)
const [showStatusModal, setShowStatusModal] = useState(false)
const [viewingPlan, setViewingPlan] = useState<PmMaintenancePlan | null>(null)
// Mock data - replace with actual API calls
const [plans] = useState<PmMaintenancePlan[]>(mockMaintenancePlans);
const [plans] = useState<PmMaintenancePlan[]>(mockMaintenancePlans)
const filteredPlans = plans.filter((plan) => {
const matchesSearch =
plan.planCode.toLowerCase().includes(searchTerm.toLowerCase()) ||
plan.description.toLowerCase().includes(searchTerm.toLowerCase());
const matchesType = typeFilter === "all" || plan.planType === typeFilter;
plan.description.toLowerCase().includes(searchTerm.toLowerCase())
const matchesType = typeFilter === 'all' || plan.planType === typeFilter
const matchesStatus =
statusFilter === "all" ||
(statusFilter === "active" && plan.isActive) ||
(statusFilter === "inactive" && !plan.isActive);
return matchesSearch && matchesType && matchesStatus;
});
statusFilter === 'all' ||
(statusFilter === 'active' && plan.isActive) ||
(statusFilter === 'inactive' && !plan.isActive)
return matchesSearch && matchesType && matchesStatus
})
const isOverdue = (plan: PmMaintenancePlan) => {
if (!plan.nextDue) return false;
return plan.nextDue < new Date();
};
if (!plan.nextDue) return false
return plan.nextDue < new Date()
}
const isDueSoon = (plan: PmMaintenancePlan) => {
if (!plan.nextDue) return false;
const today = new Date();
const diffTime = plan.nextDue.getTime() - today.getTime();
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return diffDays <= 7 && diffDays > 0;
};
if (!plan.nextDue) return false
const today = new Date()
const diffTime = plan.nextDue.getTime() - today.getTime()
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
return diffDays <= 7 && diffDays > 0
}
const getTotalMaterialCost = (plan: PmMaintenancePlan) => {
return plan.priority;
};
return plan.priority
}
// Event handlers
const handleAddPlan = () => {
setShowNewModal(true);
};
setShowNewModal(true)
}
const handleEdit = (plan: PmMaintenancePlan) => {
setEditingPlan(plan);
setShowEditModal(true);
};
setEditingPlan(plan)
setShowEditModal(true)
}
const handleView = (plan: PmMaintenancePlan) => {
setViewingPlan(plan);
setShowViewModal(true);
};
setViewingPlan(plan)
setShowViewModal(true)
}
const handleSelectPlan = (planId: string) => {
setSelectedPlans((prev) =>
prev.includes(planId)
? prev.filter((id) => id !== planId)
: [...prev, planId]
);
};
prev.includes(planId) ? prev.filter((id) => id !== planId) : [...prev, planId],
)
}
const handleCreateWorkOrder = () => {
setShowWorkOrderModal(true);
};
setShowWorkOrderModal(true)
}
const handleStatusChange = () => {
setShowStatusModal(true);
};
setShowStatusModal(true)
}
// Modal handlers
const handleSaveNewPlan = (newPlan: Partial<PmMaintenancePlan>) => {
console.log("New plan:", newPlan);
console.log('New plan:', newPlan)
// TODO: API call to save new plan
};
}
const handleSaveEditPlan = (updatedPlan: PmMaintenancePlan) => {
console.log("Updated plan:", updatedPlan);
console.log('Updated plan:', updatedPlan)
// TODO: API call to update plan
};
}
const handleSaveWorkOrders = (
workOrders: Partial<PmMaintenanceWorkOrder>[]
) => {
console.log("Work orders:", workOrders);
const handleSaveWorkOrders = (workOrders: Partial<PmMaintenanceWorkOrder>[]) => {
console.log('Work orders:', workOrders)
// TODO: API call to create work orders
setSelectedPlans([]);
};
setSelectedPlans([])
}
const handleSaveStatusChange = (
planIds: string[],
isActive: boolean,
reason: string
) => {
console.log("Status change:", { planIds, isActive, reason });
const handleSaveStatusChange = (planIds: string[], isActive: boolean, reason: string) => {
console.log('Status change:', { planIds, isActive, reason })
// TODO: API call to update plan statuses
setSelectedPlans([]);
};
setSelectedPlans([])
}
return (
<div className="space-y-4 pt-2">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900">Bakım Planları</h2>
<p className="text-gray-600">
Periyodik ve düzeltici bakım planlarını yönetin
</p>
<Container>
<div className="space-y-2">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900">Bakım Planları</h2>
<p className="text-gray-600">Periyodik ve düzeltici bakım planlarını yönetin</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>
<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 */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
<Widget
title="Toplam Plan"
value={plans.length}
color="blue"
icon="FaCalendar"
/>
{/* Summary Cards */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
<Widget title="Toplam Plan" value={plans.length} color="blue" icon="FaCalendar" />
<Widget
title="Aktif Plan"
value={plans.filter((p) => p.isActive).length}
color="green"
icon="FaCheckCircle"
/>
<Widget
title="Aktif Plan"
value={plans.filter((p) => p.isActive).length}
color="green"
icon="FaCheckCircle"
/>
<Widget
title="Geciken"
value={plans.filter((p) => isOverdue(p)).length}
color="red"
icon="FaExclamationTriangle"
/>
<Widget
title="Geciken"
value={plans.filter((p) => isOverdue(p)).length}
color="red"
icon="FaExclamationTriangle"
/>
<Widget
title="Bu Hafta"
value={plans.filter((p) => isDueSoon(p)).length}
color="orange"
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"
<Widget
title="Bu Hafta"
value={plans.filter((p) => isDueSoon(p)).length}
color="orange"
icon="FaClock"
/>
</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 */}
<div className="bg-white rounded-lg shadow-md overflow-hidden">
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<input
type="checkbox"
checked={
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"
/>
</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Plan Bilgileri
</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
İş Merkezi
</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Tip/Öncelik
</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
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">
{/* 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 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 */}
<div className="bg-white rounded-lg shadow-md overflow-hidden">
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<input
type="checkbox"
checked={selectedPlans.includes(plan.id)}
onChange={() => handleSelectPlan(plan.id)}
checked={
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"
/>
</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}
</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Plan Bilgileri
</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
İş Merkezi
</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Tip/Öncelik
</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
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>
</td>
<td className="px-4 py-3 whitespace-nowrap">
<div className="text-sm text-gray-900">
{plan.workCenterId}
</div>
<div className="text-sm text-gray-500">İş Merkezi Adı</div>
</td>
<td className="px-4 py-3 whitespace-nowrap">
<div className="space-y-1">
</td>
<td className="px-4 py-3 whitespace-nowrap">
<div className="text-sm text-gray-900">{plan.workCenterId}</div>
<div className="text-sm text-gray-500">İş Merkezi Adı</div>
</td>
<td className="px-4 py-3 whitespace-nowrap">
<div className="space-y-1">
<span
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${getMaintenancePlanTypeColor(
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
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${getMaintenancePlanTypeColor(
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"
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
plan.isActive
? 'bg-green-100 text-green-800'
: 'bg-gray-100 text-gray-800'
}`}
>
{plan.nextDue.toLocaleDateString("tr-TR")}
{isOverdue(plan) && (
<div className="text-xs">GECİKMİŞ</div>
)}
{isDueSoon(plan) && !isOverdue(plan) && (
<div className="text-xs">YAKINDA</div>
)}
{plan.isActive ? 'Aktif' : 'Pasif'}
</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>
) : (
<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
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
plan.isActive
? "bg-green-100 text-green-800"
: "bg-gray-100 text-gray-800"
}`}
>
{plan.isActive ? "Aktif" : "Pasif"}
</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>
</td>
</tr>
))}
</tbody>
</table>
</div>
{filteredPlans.length === 0 && (
<div className="text-center py-12">
<FaCalendar className="w-16 h-16 text-gray-400 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2">Plan bulunamadı</h3>
<p className="text-gray-500 mb-4">
Arama kriterlerinizi değiştirin veya yeni bir plan oluşturun.
</p>
<button
onClick={handleAddPlan}
className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700"
>
Yeni Plan Oluştur
</button>
</div>
)}
</div>
{filteredPlans.length === 0 && (
<div className="text-center py-12">
<FaCalendar className="w-16 h-16 text-gray-400 mx-auto mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-2">
Plan bulunamadı
</h3>
<p className="text-gray-500 mb-4">
Arama kriterlerinizi değiştirin veya yeni bir plan oluşturun.
</p>
<button
onClick={handleAddPlan}
className="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700"
>
Yeni Plan Oluştur
</button>
{/* 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>
)}
</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 */}
<NewMaintenancePlanModal
isOpen={showNewModal}
@ -517,21 +470,17 @@ const MaintenancePlans: React.FC = () => {
isOpen={showWorkOrderModal}
onClose={() => setShowWorkOrderModal(false)}
onSave={handleSaveWorkOrders}
selectedPlans={selectedPlans
.map((id) => plans.find((p) => p.id === id)!)
.filter(Boolean)}
selectedPlans={selectedPlans.map((id) => plans.find((p) => p.id === id)!).filter(Boolean)}
/>
<PlanStatusChangeModal
isOpen={showStatusModal}
onClose={() => setShowStatusModal(false)}
onSave={handleSaveStatusChange}
selectedPlans={selectedPlans
.map((id) => plans.find((p) => p.id === id)!)
.filter(Boolean)}
selectedPlans={selectedPlans.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 {
FaPlus,
FaSearch,
@ -12,44 +12,38 @@ import {
FaEnvelope,
FaAward,
FaClock,
} from "react-icons/fa";
import { TeamRoleEnum } from "../../../types/common";
import { mockMaintenanceTeams } from "../../../mocks/mockMaintenanceTeams";
import NewTeamModal from "./NewTeamModal";
import ViewTeamModal from "./ViewTeamModal";
import EditTeamModal from "./EditTeamModal";
import AssignWorkOrderModal from "./AssignWorkOrderModal";
import TeamStatusChangeModal from "./TeamStatusChangeModal";
import Widget from "../../../components/common/Widget";
import { Team } from "../../../types/common";
import {
getTeamRoleColor,
getTeamRoleIcon,
getTeamRoleText,
} from "../../../utils/erp";
} from 'react-icons/fa'
import { TeamRoleEnum } from '../../../types/common'
import { mockMaintenanceTeams } from '../../../mocks/mockMaintenanceTeams'
import NewTeamModal from './NewTeamModal'
import ViewTeamModal from './ViewTeamModal'
import EditTeamModal from './EditTeamModal'
import AssignWorkOrderModal from './AssignWorkOrderModal'
import TeamStatusChangeModal from './TeamStatusChangeModal'
import Widget from '../../../components/common/Widget'
import { Team } from '../../../types/common'
import { getTeamRoleColor, getTeamRoleIcon, getTeamRoleText } from '../../../utils/erp'
import { Container } from '@/components/shared'
const MaintenanceTeams: React.FC = () => {
const [searchTerm, setSearchTerm] = useState("");
const [roleFilter, setRoleFilter] = useState<TeamRoleEnum | "all">("all");
const [statusFilter, setStatusFilter] = useState<
"active" | "inactive" | "all"
>("all");
const [searchTerm, setSearchTerm] = useState('')
const [roleFilter, setRoleFilter] = useState<TeamRoleEnum | 'all'>('all')
const [statusFilter, setStatusFilter] = useState<'active' | 'inactive' | 'all'>('all')
// Modal states
const [showNewTeamModal, setShowNewTeamModal] = useState(false);
const [showViewTeamModal, setShowViewTeamModal] = useState(false);
const [showEditTeamModal, setShowEditTeamModal] = useState(false);
const [showAssignWorkOrderModal, setShowAssignWorkOrderModal] =
useState(false);
const [showStatusChangeModal, setShowStatusChangeModal] = useState(false);
const [showNewTeamModal, setShowNewTeamModal] = useState(false)
const [showViewTeamModal, setShowViewTeamModal] = useState(false)
const [showEditTeamModal, setShowEditTeamModal] = useState(false)
const [showAssignWorkOrderModal, setShowAssignWorkOrderModal] = useState(false)
const [showStatusChangeModal, setShowStatusChangeModal] = useState(false)
// Selected data
const [viewingTeam, setViewingTeam] = useState<Team | null>(null);
const [editingTeam, setEditingTeam] = useState<Team | null>(null);
const [selectedTeams, setSelectedTeams] = useState<string[]>([]);
const [viewingTeam, setViewingTeam] = useState<Team | null>(null)
const [editingTeam, setEditingTeam] = useState<Team | null>(null)
const [selectedTeams, setSelectedTeams] = useState<string[]>([])
// 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 matchesSearch =
@ -57,441 +51,389 @@ const MaintenanceTeams: React.FC = () => {
team.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
team.members.some(
(member) =>
member.employee?.firstName
.toLowerCase()
.includes(searchTerm.toLowerCase()) ||
member.employee?.lastName
.toLowerCase()
.includes(searchTerm.toLowerCase())
);
member.employee?.firstName.toLowerCase().includes(searchTerm.toLowerCase()) ||
member.employee?.lastName.toLowerCase().includes(searchTerm.toLowerCase()),
)
const matchesRole =
roleFilter === "all" ||
team.members.some((member) => member.role === roleFilter);
roleFilter === 'all' || team.members.some((member) => member.role === roleFilter)
const matchesStatus =
statusFilter === "all" ||
(statusFilter === "active" && team.isActive) ||
(statusFilter === "inactive" && !team.isActive);
return matchesSearch && matchesRole && matchesStatus;
});
statusFilter === 'all' ||
(statusFilter === 'active' && team.isActive) ||
(statusFilter === 'inactive' && !team.isActive)
return matchesSearch && matchesRole && matchesStatus
})
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) => {
return team.members.filter((member) => member.isActive);
};
return team.members.filter((member) => member.isActive)
}
const handleAddTeam = () => {
setEditingTeam(null);
setShowNewTeamModal(true);
};
setEditingTeam(null)
setShowNewTeamModal(true)
}
const handleViewTeam = (team: Team) => {
setViewingTeam(team);
setShowViewTeamModal(true);
};
setViewingTeam(team)
setShowViewTeamModal(true)
}
const handleEditTeam = (team: Team) => {
setEditingTeam(team);
setShowEditTeamModal(true);
};
setEditingTeam(team)
setShowEditTeamModal(true)
}
const handleSelectTeam = (teamId: string) => {
setSelectedTeams((prev) =>
prev.includes(teamId)
? prev.filter((id) => id !== teamId)
: [...prev, teamId]
);
};
prev.includes(teamId) ? prev.filter((id) => id !== teamId) : [...prev, teamId],
)
}
const handleNewTeamSave = (newTeam: Partial<Team>) => {
if (newTeam.id) {
setTeams((prev) => [...prev, newTeam as Team]);
setTeams((prev) => [...prev, newTeam as Team])
}
};
}
const handleEditTeamSave = (updatedTeam: Team) => {
setTeams((prev) =>
prev.map((team) => (team.id === updatedTeam.id ? updatedTeam : team))
);
};
setTeams((prev) => prev.map((team) => (team.id === updatedTeam.id ? updatedTeam : team)))
}
const handleAssignWorkOrders = (
assignments: { teamId: string; planIds: string[] }[]
) => {
const handleAssignWorkOrders = (assignments: { teamId: string; planIds: string[] }[]) => {
// 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
};
}
const handleStatusChange = (
teamIds: string[],
newStatus: boolean,
reason?: string
) => {
const handleStatusChange = (teamIds: string[], newStatus: boolean, reason?: string) => {
setTeams((prev) =>
prev.map((team) =>
teamIds.includes(team.id)
? { ...team, isActive: newStatus, lastModificationTime: new Date() }
: team
)
);
setSelectedTeams([]);
: team,
),
)
setSelectedTeams([])
// 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) =>
selectedTeams.includes(team.id)
);
const selectedTeamObjects = teams.filter((team) => selectedTeams.includes(team.id))
return (
<div className="space-y-4 pt-2">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900">Bakım Ekipleri</h2>
<p className="text-gray-600">
Bakım ekiplerini ve üyelerini yönetin
</p>
</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>
<Container>
<div className="space-y-2">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold text-gray-900">Bakım Ekipleri</h2>
<p className="text-gray-600">Bakım ekiplerini ve üyelerini yönetin</p>
</div>
<button
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>
</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>
{/* 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
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 */}
<NewTeamModal
@ -527,8 +469,8 @@ const MaintenanceTeams: React.FC = () => {
onSave={handleStatusChange}
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 { FaTimes, FaSave, FaCalendar, FaClock } from "react-icons/fa";
import { PmCalendarEvent, WorkOrderStatusEnum } from "../../../types/pm";
import { mockWorkCenters } from "../../../mocks/mockWorkCenters";
import { mockEmployees } from "../../../mocks/mockEmployees";
import { PriorityEnum } from "../../../types/common";
import React, { useState, useEffect } from 'react'
import { FaTimes, FaSave, FaCalendar, FaClock } from 'react-icons/fa'
import { PmCalendarEvent, WorkOrderStatusEnum } from '../../../types/pm'
import { mockWorkCenters } from '../../../mocks/mockWorkCenters'
import { mockEmployees } from '../../../mocks/mockEmployees'
import { PriorityEnum } from '../../../types/common'
interface NewCalendarEventModalProps {
isOpen: boolean;
onClose: () => void;
onSave: (event: Partial<PmCalendarEvent>) => void;
selectedDate?: Date;
isOpen: boolean
onClose: () => void
onSave: (event: Partial<PmCalendarEvent>) => void
selectedDate?: Date
}
const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
@ -20,185 +20,165 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
}) => {
const getInitialStartTime = () => {
if (selectedDate) {
const hour = selectedDate.getHours();
const minute = selectedDate.getMinutes();
return `${hour.toString().padStart(2, "0")}:${minute
.toString()
.padStart(2, "0")}`;
const hour = selectedDate.getHours()
const minute = selectedDate.getMinutes()
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`
}
return "09:00";
};
return '09:00'
}
const getInitialEndTime = () => {
if (selectedDate) {
const endTime = new Date(selectedDate);
endTime.setHours(endTime.getHours() + 1);
const hour = endTime.getHours();
const minute = endTime.getMinutes();
return `${hour.toString().padStart(2, "0")}:${minute
.toString()
.padStart(2, "0")}`;
const endTime = new Date(selectedDate)
endTime.setHours(endTime.getHours() + 1)
const hour = endTime.getHours()
const minute = endTime.getMinutes()
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`
}
return "10:00";
};
return '10:00'
}
const [eventData, setEventData] = useState<Partial<PmCalendarEvent>>({
title: "",
type: "plan",
title: '',
type: 'plan',
date: selectedDate || new Date(),
startTime: getInitialStartTime(),
endTime: getInitialEndTime(),
status: WorkOrderStatusEnum.Planned,
priority: PriorityEnum.Normal,
assignedTo: "",
workCenterCode: "",
assignedTo: '',
workCenterCode: '',
duration: 60,
});
})
const [errors, setErrors] = useState<Record<string, string>>({});
const [errors, setErrors] = useState<Record<string, string>>({})
// Update form data when selectedDate changes
useEffect(() => {
if (selectedDate) {
const getInitialStartTime = () => {
const hour = selectedDate.getHours();
const minute = selectedDate.getMinutes();
return `${hour.toString().padStart(2, "0")}:${minute
.toString()
.padStart(2, "0")}`;
};
const hour = selectedDate.getHours()
const minute = selectedDate.getMinutes()
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`
}
const getInitialEndTime = () => {
const endTime = new Date(selectedDate);
endTime.setHours(endTime.getHours() + 1);
const hour = endTime.getHours();
const minute = endTime.getMinutes();
return `${hour.toString().padStart(2, "0")}:${minute
.toString()
.padStart(2, "0")}`;
};
const endTime = new Date(selectedDate)
endTime.setHours(endTime.getHours() + 1)
const hour = endTime.getHours()
const minute = endTime.getMinutes()
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`
}
setEventData((prev) => ({
...prev,
date: selectedDate,
startTime: getInitialStartTime(),
endTime: getInitialEndTime(),
}));
}))
}
}, [selectedDate]);
}, [selectedDate])
if (!isOpen) return null;
if (!isOpen) return null
const validateForm = () => {
const newErrors: Record<string, string> = {};
const newErrors: Record<string, string> = {}
if (!eventData.title?.trim()) {
newErrors.title = "Başlık gerekli";
newErrors.title = 'Başlık gerekli'
}
if (!eventData.workCenterCode?.trim()) {
newErrors.workCenterCode = "İş Merkezi seçimi gerekli";
newErrors.workCenterCode = 'İş Merkezi seçimi gerekli'
}
if (!eventData.startTime) {
newErrors.startTime = "Başlangıç saati gerekli";
newErrors.startTime = 'Başlangıç saati gerekli'
}
if (!eventData.endTime) {
newErrors.endTime = "Bitiş saati gerekli";
newErrors.endTime = 'Bitiş saati gerekli'
}
if (eventData.startTime && eventData.endTime) {
const start = new Date(`2000-01-01 ${eventData.startTime}`);
const end = new Date(`2000-01-01 ${eventData.endTime}`);
const start = new Date(`2000-01-01 ${eventData.startTime}`)
const end = new Date(`2000-01-01 ${eventData.endTime}`)
if (start >= end) {
newErrors.endTime = "Bitiş saati başlangıç saatinden sonra olmalı";
newErrors.endTime = 'Bitiş saati başlangıç saatinden sonra olmalı'
}
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
setErrors(newErrors)
return Object.keys(newErrors).length === 0
}
const handleSave = () => {
if (validateForm()) {
// Calculate duration
if (eventData.startTime && eventData.endTime) {
const start = new Date(`2000-01-01 ${eventData.startTime}`);
const end = new Date(`2000-01-01 ${eventData.endTime}`);
const durationMinutes = (end.getTime() - start.getTime()) / (1000 * 60);
eventData.duration = durationMinutes;
const start = new Date(`2000-01-01 ${eventData.startTime}`)
const end = new Date(`2000-01-01 ${eventData.endTime}`)
const durationMinutes = (end.getTime() - start.getTime()) / (1000 * 60)
eventData.duration = durationMinutes
}
onSave({
...eventData,
id: `E${Date.now()}`, // Generate a simple ID
});
onClose();
})
onClose()
// Reset form
setEventData({
title: "",
type: "plan",
title: '',
type: 'plan',
date: selectedDate || new Date(),
startTime: getInitialStartTime(),
endTime: getInitialEndTime(),
status: WorkOrderStatusEnum.Planned,
priority: PriorityEnum.Normal,
assignedTo: "",
workCenterCode: "",
assignedTo: '',
workCenterCode: '',
duration: 60,
});
setErrors({});
})
setErrors({})
}
};
}
const handleInputChange = (
field: keyof PmCalendarEvent,
value:
| string
| Date
| PriorityEnum
| WorkOrderStatusEnum
| "plan"
| "workorder"
| "scheduled"
value: string | Date | PriorityEnum | WorkOrderStatusEnum | 'plan' | 'workorder' | 'scheduled',
) => {
setEventData((prev) => ({
...prev,
[field]: value,
}));
}))
// Clear error when user starts typing
if (errors[field]) {
setErrors((prev) => ({
...prev,
[field]: "",
}));
[field]: '',
}))
}
};
}
const generateTimeOptions = () => {
const options = [];
const options = []
for (let hour = 0; hour < 24; hour++) {
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()
.padStart(2, "0")}`;
options.push(timeString);
.padStart(2, '0')}`
options.push(timeString)
}
}
return options;
};
return options
}
const timeOptions = generateTimeOptions();
const timeOptions = generateTimeOptions()
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg w-full max-w-lg mx-4 max-h-[90vh] overflow-y-auto">
{/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200">
<h2 className="text-xl font-bold text-gray-900">
Yeni Bakım Planlaması
</h2>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors"
>
<h2 className="text-xl font-bold text-gray-900">Yeni Bakım Planlaması</h2>
<button onClick={onClose} className="text-gray-400 hover:text-gray-600 transition-colors">
<FaTimes className="w-5 h-5" />
</button>
</div>
@ -208,35 +188,24 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
{/* Basic Info */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="md:col-span-2">
<label className="block text-sm font-medium text-gray-700 mb-1">
Başlık *
</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Başlık *</label>
<input
type="text"
value={eventData.title || ""}
onChange={(e) => handleInputChange("title", e.target.value)}
value={eventData.title || ''}
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 ${
errors.title ? "border-red-500" : "border-gray-300"
errors.title ? 'border-red-500' : 'border-gray-300'
}`}
placeholder="Bakım planı başlığı"
/>
{errors.title && (
<p className="text-red-500 text-xs mt-1">{errors.title}</p>
)}
{errors.title && <p className="text-red-500 text-xs mt-1">{errors.title}</p>}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Tip
</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Tip</label>
<select
value={eventData.type || "plan"}
onChange={(e) =>
handleInputChange(
"type",
e.target.value as "plan" | "workorder"
)
}
value={eventData.type || 'plan'}
onChange={(e) => 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"
>
<option value="plan">Bakım Planı</option>
@ -245,14 +214,10 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Öncelik
</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Öncelik</label>
<select
value={eventData.priority || PriorityEnum.Normal}
onChange={(e) =>
handleInputChange("priority", e.target.value as PriorityEnum)
}
onChange={(e) => 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"
>
<option value={PriorityEnum.Low}>Düşük</option>
@ -263,16 +228,12 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
İş Merkezi *
</label>
<label className="block text-sm font-medium text-gray-700 mb-1">İş Merkezi *</label>
<select
value={eventData.workCenterCode || ""}
onChange={(e) =>
handleInputChange("workCenterCode", e.target.value)
}
value={eventData.workCenterCode || ''}
onChange={(e) => 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 ${
errors.workCenterCode ? "border-red-500" : "border-gray-300"
errors.workCenterCode ? 'border-red-500' : 'border-gray-300'
}`}
>
<option value="">İş merkezi seçin</option>
@ -283,21 +244,15 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
))}
</select>
{errors.workCenterCode && (
<p className="text-red-500 text-xs mt-1">
{errors.workCenterCode}
</p>
<p className="text-red-500 text-xs mt-1">{errors.workCenterCode}</p>
)}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Atanan Kişi
</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Atanan Kişi</label>
<select
value={eventData.assignedTo || ""}
onChange={(e) =>
handleInputChange("assignedTo", e.target.value)
}
value={eventData.assignedTo || ''}
onChange={(e) => 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"
>
<option value="">Kişi seçin</option>
@ -319,10 +274,8 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
</label>
<input
type="date"
value={eventData.date?.toISOString().split("T")[0] || ""}
onChange={(e) =>
handleInputChange("date", new Date(e.target.value))
}
value={eventData.date?.toISOString().split('T')[0] || ''}
onChange={(e) => 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"
/>
</div>
@ -333,10 +286,10 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
Başlangıç Saati *
</label>
<select
value={eventData.startTime || "09:00"}
onChange={(e) => handleInputChange("startTime", e.target.value)}
value={eventData.startTime || '09:00'}
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 ${
errors.startTime ? "border-red-500" : "border-gray-300"
errors.startTime ? 'border-red-500' : 'border-gray-300'
}`}
>
{timeOptions.map((time) => (
@ -345,20 +298,16 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
</option>
))}
</select>
{errors.startTime && (
<p className="text-red-500 text-xs mt-1">{errors.startTime}</p>
)}
{errors.startTime && <p className="text-red-500 text-xs mt-1">{errors.startTime}</p>}
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Bitiş Saati *
</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Bitiş Saati *</label>
<select
value={eventData.endTime || "10:00"}
onChange={(e) => handleInputChange("endTime", e.target.value)}
value={eventData.endTime || '10:00'}
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 ${
errors.endTime ? "border-red-500" : "border-gray-300"
errors.endTime ? 'border-red-500' : 'border-gray-300'
}`}
>
{timeOptions.map((time) => (
@ -367,44 +316,29 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
</option>
))}
</select>
{errors.endTime && (
<p className="text-red-500 text-xs mt-1">{errors.endTime}</p>
)}
{errors.endTime && <p className="text-red-500 text-xs mt-1">{errors.endTime}</p>}
</div>
</div>
{/* Status */}
{eventData.type === "workorder" && (
{eventData.type === 'workorder' && (
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Durum
</label>
<label className="block text-sm font-medium text-gray-700 mb-1">Durum</label>
<select
value={eventData.status || "scheduled"}
value={eventData.status || 'scheduled'}
onChange={(e) =>
handleInputChange(
"status",
e.target.value as WorkOrderStatusEnum | "scheduled"
)
handleInputChange('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"
>
<option value="scheduled">Planlanmış</option>
<option value={WorkOrderStatusEnum.Created}>Oluşturuldu</option>
<option value={WorkOrderStatusEnum.Planned}>Planlandı</option>
<option value={WorkOrderStatusEnum.Released}>
Serbest Bırakıldı
</option>
<option value={WorkOrderStatusEnum.InProgress}>
Devam Ediyor
</option>
<option value={WorkOrderStatusEnum.Released}>Serbest Bırakıldı</option>
<option value={WorkOrderStatusEnum.InProgress}>Devam Ediyor</option>
<option value={WorkOrderStatusEnum.OnHold}>Beklemede</option>
<option value={WorkOrderStatusEnum.Completed}>
Tamamlandı
</option>
<option value={WorkOrderStatusEnum.Cancelled}>
İptal Edildi
</option>
<option value={WorkOrderStatusEnum.Completed}>Tamamlandı</option>
<option value={WorkOrderStatusEnum.Cancelled}>İptal Edildi</option>
</select>
</div>
)}
@ -428,7 +362,7 @@ const NewCalendarEventModal: React.FC<NewCalendarEventModalProps> = ({
</div>
</div>
</div>
);
};
)
}
export default NewCalendarEventModal;
export default NewCalendarEventModal

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,20 +1,13 @@
import React, { useState } from "react";
import { FaTimes, FaSave, FaExclamationTriangle } from "react-icons/fa";
import {
PmWorkCenter,
WorkCenterStatusEnum,
CriticalityLevelEnum,
} from "../../../types/pm";
import {
getCriticalityLevelText,
getWorkCenterStatusText,
} from "../../../utils/erp";
import React, { useState } from 'react'
import { FaTimes, FaSave, FaExclamationTriangle } from 'react-icons/fa'
import { PmWorkCenter, WorkCenterStatusEnum, CriticalityLevelEnum } from '../../../types/pm'
import { getCriticalityLevelText, getWorkCenterStatusText } from '../../../utils/erp'
interface StatusUpdateModalProps {
isOpen: boolean;
onClose: () => void;
onSave: (updatedWorkCenters: PmWorkCenter[]) => void;
selectedWorkCenters: PmWorkCenter[];
isOpen: boolean
onClose: () => void
onSave: (updatedWorkCenters: PmWorkCenter[]) => void
selectedWorkCenters: PmWorkCenter[]
}
const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
@ -23,17 +16,15 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
onSave,
selectedWorkCenters,
}) => {
const [newStatus, setNewStatus] = useState<WorkCenterStatusEnum>(
WorkCenterStatusEnum.Operational
);
const [newStatus, setNewStatus] = useState<WorkCenterStatusEnum>(WorkCenterStatusEnum.Operational)
const [newCriticality, setNewCriticality] = useState<CriticalityLevelEnum>(
CriticalityLevelEnum.Medium
);
const [updateStatus, setUpdateStatus] = useState(true);
const [updateCriticality, setUpdateCriticality] = useState(false);
const [reason, setReason] = useState("");
CriticalityLevelEnum.Medium,
)
const [updateStatus, setUpdateStatus] = useState(true)
const [updateCriticality, setUpdateCriticality] = useState(false)
const [reason, setReason] = useState('')
if (!isOpen) return null;
if (!isOpen) return null
const handleSave = () => {
const updatedWorkCenters = selectedWorkCenters.map((workCenter) => ({
@ -41,15 +32,15 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
status: updateStatus ? newStatus : workCenter.status,
criticality: updateCriticality ? newCriticality : workCenter.criticality,
lastModificationTime: new Date(),
}));
}))
onSave(updatedWorkCenters);
onClose();
};
onSave(updatedWorkCenters)
onClose()
}
const isStatusCritical =
newStatus === WorkCenterStatusEnum.OutOfOrder ||
newStatus === WorkCenterStatusEnum.UnderMaintenance;
newStatus === WorkCenterStatusEnum.UnderMaintenance
return (
<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">
Durum Güncelle ({selectedWorkCenters.length} merkezi)
</h2>
<button
onClick={onClose}
className="p-1 hover:bg-gray-100 rounded-lg transition-colors"
>
<button onClick={onClose} className="p-1 hover:bg-gray-100 rounded-lg transition-colors">
<FaTimes className="w-4 h-4 text-gray-500" />
</button>
</div>
@ -71,15 +59,10 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
<div className="p-4 space-y-4">
{/* Selected WorkCenter List */}
<div>
<h3 className="text-base font-medium text-gray-900 mb-2">
Seçili İş Merkezleri
</h3>
<h3 className="text-base font-medium text-gray-900 mb-2">Seçili İş Merkezleri</h3>
<div className="max-h-28 overflow-y-auto bg-gray-50 rounded-lg p-2">
{selectedWorkCenters.map((workCenter) => (
<div
key={workCenter.id}
className="flex items-center justify-between py-0.5"
>
<div key={workCenter.id} className="flex items-center justify-between py-0.5">
<span className="text-sm text-gray-700">
{workCenter.code} - {workCenter.name}
</span>
@ -106,35 +89,22 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
onChange={(e) => setUpdateStatus(e.target.checked)}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<label
htmlFor="updateStatus"
className="text-sm font-medium text-gray-700"
>
<label htmlFor="updateStatus" className="text-sm font-medium text-gray-700">
Operasyonel durumu güncelle
</label>
</div>
{updateStatus && (
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Yeni Durum
</label>
<label className="block text-sm font-medium text-gray-700 mb-2">Yeni Durum</label>
<select
value={newStatus}
onChange={(e) =>
setNewStatus(e.target.value as WorkCenterStatusEnum)
}
onChange={(e) => 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"
>
<option value={WorkCenterStatusEnum.Operational}>
Operasyonel
</option>
<option value={WorkCenterStatusEnum.UnderMaintenance}>
Bakımda
</option>
<option value={WorkCenterStatusEnum.OutOfOrder}>
Arızalı
</option>
<option value={WorkCenterStatusEnum.Operational}>Operasyonel</option>
<option value={WorkCenterStatusEnum.UnderMaintenance}>Bakımda</option>
<option value={WorkCenterStatusEnum.OutOfOrder}>Arızalı</option>
<option value={WorkCenterStatusEnum.Retired}>Emekli</option>
</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="flex items-center space-x-2">
<FaExclamationTriangle className="w-4 h-4 text-yellow-600" />
<span className="text-sm text-yellow-800 font-medium">
Dikkat!
</span>
<span className="text-sm text-yellow-800 font-medium">Dikkat!</span>
</div>
<p className="text-sm text-yellow-700 mt-1">
Bu durum değişikliği merkezinin üretim kapasitesini
etkileyebilir.
Bu durum değişikliği merkezinin üretim kapasitesini etkileyebilir.
</p>
</div>
)}
@ -163,10 +130,7 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
onChange={(e) => setUpdateCriticality(e.target.checked)}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<label
htmlFor="updateCriticality"
className="text-sm font-medium text-gray-700"
>
<label htmlFor="updateCriticality" className="text-sm font-medium text-gray-700">
Kritiklik seviyesini güncelle
</label>
</div>
@ -178,9 +142,7 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
</label>
<select
value={newCriticality}
onChange={(e) =>
setNewCriticality(e.target.value as CriticalityLevelEnum)
}
onChange={(e) => 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"
>
<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">
<p> {selectedWorkCenters.length} merkezi güncellenecek</p>
{updateStatus && (
<p>
Durum "{getWorkCenterStatusText(newStatus)}" olarak
değiştirilecek
</p>
<p> Durum "{getWorkCenterStatusText(newStatus)}" olarak değiştirilecek</p>
)}
{updateCriticality && (
<p>
Kritiklik seviyesi "
{getCriticalityLevelText(newCriticality)}" olarak
Kritiklik seviyesi "{getCriticalityLevelText(newCriticality)}" olarak
değiştirilecek
</p>
)}
@ -249,7 +207,7 @@ const StatusUpdateModal: React.FC<StatusUpdateModalProps> = ({
</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 {
FaTimes,
FaSave,
FaExclamationTriangle,
FaCheckCircle,
FaTimesCircle,
} from "react-icons/fa";
import { Team } from "../../../types/common";
} from 'react-icons/fa'
import { Team } from '../../../types/common'
interface TeamStatusChangeModalProps {
isOpen: boolean;
onClose: () => void;
onSave: (teamIds: string[], newStatus: boolean, reason?: string) => void;
selectedTeams: Team[];
isOpen: boolean
onClose: () => void
onSave: (teamIds: string[], newStatus: boolean, reason?: string) => void
selectedTeams: Team[]
}
const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
@ -21,60 +21,60 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
onSave,
selectedTeams,
}) => {
const [newStatus, setNewStatus] = useState<boolean>(true);
const [reason, setReason] = useState("");
const [errors, setErrors] = useState<Record<string, string>>({});
const [newStatus, setNewStatus] = useState<boolean>(true)
const [reason, setReason] = useState('')
const [errors, setErrors] = useState<Record<string, string>>({})
const activeTeams = selectedTeams.filter((team) => team.isActive);
const inactiveTeams = selectedTeams.filter((team) => !team.isActive);
const activeTeams = selectedTeams.filter((team) => team.isActive)
const inactiveTeams = selectedTeams.filter((team) => !team.isActive)
useEffect(() => {
if (isOpen) {
// Reset form when modal opens
setNewStatus(true);
setReason("");
setErrors({});
setNewStatus(true)
setReason('')
setErrors({})
}
}, [isOpen]);
}, [isOpen])
const validateForm = () => {
const newErrors: Record<string, string> = {};
const newErrors: Record<string, string> = {}
if (!newStatus && !reason.trim()) {
newErrors.reason = "Ekipleri pasif yaparken sebep belirtmeniz gerekli";
newErrors.reason = 'Ekipleri pasif yaparken sebep belirtmeniz gerekli'
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
setErrors(newErrors)
return Object.keys(newErrors).length === 0
}
const handleSave = () => {
if (validateForm()) {
const teamIds = selectedTeams.map((team) => team.id);
onSave(teamIds, newStatus, reason.trim() || undefined);
onClose();
const teamIds = selectedTeams.map((team) => team.id)
onSave(teamIds, newStatus, reason.trim() || undefined)
onClose()
}
};
}
const getImpactAnalysis = () => {
const teamsToActivate = newStatus ? inactiveTeams : [];
const teamsToDeactivate = newStatus ? [] : activeTeams;
const teamsToActivate = newStatus ? inactiveTeams : []
const teamsToDeactivate = newStatus ? [] : activeTeams
return {
teamsToActivate,
teamsToDeactivate,
totalMembers: selectedTeams.reduce(
(total, team) => total + team.members.filter((m) => m.isActive).length,
0
0,
),
activeMembers: activeTeams.reduce(
(total, team) => total + team.members.filter((m) => m.isActive).length,
0
0,
),
};
};
}
}
const impact = getImpactAnalysis();
const impact = getImpactAnalysis()
return (
isOpen && (
@ -83,12 +83,8 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
{/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200">
<div>
<h2 className="text-2xl font-bold text-gray-900">
Ekip Durumu Değiştir
</h2>
<p className="text-gray-600">
{selectedTeams.length} ekibin durumunu değiştirin
</p>
<h2 className="text-2xl font-bold text-gray-900">Ekip Durumu Değiştir</h2>
<p className="text-gray-600">{selectedTeams.length} ekibin durumunu değiştirin</p>
</div>
<button
onClick={onClose}
@ -102,9 +98,7 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
<div className="p-3 space-y-3">
{/* Status Selection */}
<div>
<h3 className="text-sm font-medium text-gray-900 mb-2">
Yeni Durum
</h3>
<h3 className="text-sm font-medium text-gray-900 mb-2">Yeni Durum</h3>
<div className="space-y-3">
<label className="flex items-center p-2 border border-gray-200 rounded-lg hover:bg-gray-50 cursor-pointer">
<input
@ -148,41 +142,31 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
<textarea
value={reason}
onChange={(e) => {
setReason(e.target.value);
setReason(e.target.value)
if (errors.reason) {
setErrors((prev) => ({ ...prev, reason: "" }));
setErrors((prev) => ({ ...prev, reason: '' }))
}
}}
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 ${
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..."
/>
{errors.reason && (
<p className="text-red-500 text-xs mt-1">{errors.reason}</p>
)}
{errors.reason && <p className="text-red-500 text-xs mt-1">{errors.reason}</p>}
</div>
)}
{/* Impact Analysis */}
<div className="bg-gray-50 rounded-lg p-3">
<h3 className="text-sm font-medium text-gray-900 mb-3">
Etki Analizi
</h3>
<h3 className="text-sm font-medium text-gray-900 mb-3">Etki Analizi</h3>
<div className="grid grid-cols-2 gap-3 mb-3">
<div className="text-center">
<div className="text-base font-bold text-blue-600">
{selectedTeams.length}
</div>
<div className="text-sm text-gray-600">
Toplam Seçili Ekip
</div>
<div className="text-base font-bold text-blue-600">{selectedTeams.length}</div>
<div className="text-sm text-gray-600">Toplam Seçili Ekip</div>
</div>
<div className="text-center">
<div className="text-base font-bold text-green-600">
{impact.totalMembers}
</div>
<div className="text-base font-bold text-green-600">{impact.totalMembers}</div>
<div className="text-sm text-gray-600">Toplam Üye Sayısı</div>
</div>
</div>
@ -192,12 +176,10 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
<div className="flex items-start space-x-3">
<FaExclamationTriangle className="w-5 h-5 text-yellow-600 mt-0.5" />
<div>
<h4 className="text-sm font-medium text-yellow-800">
Uyarı
</h4>
<h4 className="text-sm font-medium text-yellow-800">Uyarı</h4>
<p className="text-sm text-yellow-700 mt-1">
{impact.teamsToDeactivate.length} aktif ekip pasif
yapılacak. Bu ekipler artık yeni emirleri alamayacak.
{impact.teamsToDeactivate.length} aktif ekip pasif yapılacak. Bu ekipler
artık yeni emirleri alamayacak.
</p>
</div>
</div>
@ -209,12 +191,10 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
<div className="flex items-start space-x-3">
<FaCheckCircle className="w-5 h-5 text-green-600 mt-0.5" />
<div>
<h4 className="text-sm font-medium text-green-800">
Bilgi
</h4>
<h4 className="text-sm font-medium text-green-800">Bilgi</h4>
<p className="text-sm text-green-700 mt-1">
{impact.teamsToActivate.length} pasif ekip aktif hale
gelecek. Bu ekipler tekrar emirleri alabilecek.
{impact.teamsToActivate.length} pasif ekip aktif hale gelecek. Bu ekipler
tekrar emirleri alabilecek.
</p>
</div>
</div>
@ -224,9 +204,7 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
{/* Selected Teams List */}
<div>
<h3 className="text-sm font-medium text-gray-900 mb-2">
Etkilenecek Ekipler
</h3>
<h3 className="text-sm font-medium text-gray-900 mb-2">Etkilenecek Ekipler</h3>
<div className="max-h-32 overflow-y-auto border border-gray-200 rounded-lg">
{selectedTeams.map((team) => (
<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"
>
<div>
<h4 className="font-medium text-sm text-gray-900">
{team.name}
</h4>
<h4 className="font-medium text-sm text-gray-900">{team.name}</h4>
<p className="text-sm text-gray-600">{team.code}</p>
</div>
<div className="flex items-center space-x-2">
<span
className={`px-2 py-1 text-xs font-semibold rounded-full ${
team.isActive
? "bg-green-100 text-green-800"
: "bg-gray-100 text-gray-800"
? 'bg-green-100 text-green-800'
: 'bg-gray-100 text-gray-800'
}`}
>
{team.isActive ? "Aktif" : "Pasif"}
{team.isActive ? 'Aktif' : 'Pasif'}
</span>
<span className="text-sm text-gray-500"></span>
<span
className={`px-2 py-1 text-xs font-semibold rounded-full ${
newStatus
? "bg-green-100 text-green-800"
: "bg-gray-100 text-gray-800"
newStatus ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'
}`}
>
{newStatus ? "Aktif" : "Pasif"}
{newStatus ? 'Aktif' : 'Pasif'}
</span>
</div>
</div>
@ -277,9 +251,7 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
<button
onClick={handleSave}
className={`px-3 py-1.5 text-sm text-white rounded-lg transition-colors flex items-center space-x-2 ${
newStatus
? "bg-green-600 hover:bg-green-700"
: "bg-red-600 hover:bg-red-700"
newStatus ? 'bg-green-600 hover:bg-green-700' : 'bg-red-600 hover:bg-red-700'
}`}
>
<FaSave className="w-4 h-4" />
@ -289,7 +261,7 @@ const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
</div>
</div>
)
);
};
)
}
export default TeamStatusChangeModal;
export default TeamStatusChangeModal

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff