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

268 lines
10 KiB
TypeScript
Raw Normal View History

2025-09-15 21:29:07 +00:00
import React, { useState, useEffect } from 'react'
2025-09-15 09:31:47 +00:00
import {
FaTimes,
FaSave,
FaExclamationTriangle,
FaCheckCircle,
FaTimesCircle,
2025-09-15 21:29:07 +00:00
} from 'react-icons/fa'
import { Team } from '../../../types/common'
2025-09-15 09:31:47 +00:00
interface TeamStatusChangeModalProps {
2025-09-15 21:29:07 +00:00
isOpen: boolean
onClose: () => void
onSave: (teamIds: string[], newStatus: boolean, reason?: string) => void
selectedTeams: Team[]
2025-09-15 09:31:47 +00:00
}
const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
isOpen,
onClose,
onSave,
selectedTeams,
}) => {
2025-09-15 21:29:07 +00:00
const [newStatus, setNewStatus] = useState<boolean>(true)
const [reason, setReason] = useState('')
const [errors, setErrors] = useState<Record<string, string>>({})
2025-09-15 09:31:47 +00:00
2025-09-15 21:29:07 +00:00
const activeTeams = selectedTeams.filter((team) => team.isActive)
const inactiveTeams = selectedTeams.filter((team) => !team.isActive)
2025-09-15 09:31:47 +00:00
useEffect(() => {
if (isOpen) {
// Reset form when modal opens
2025-09-15 21:29:07 +00:00
setNewStatus(true)
setReason('')
setErrors({})
2025-09-15 09:31:47 +00:00
}
2025-09-15 21:29:07 +00:00
}, [isOpen])
2025-09-15 09:31:47 +00:00
const validateForm = () => {
2025-09-15 21:29:07 +00:00
const newErrors: Record<string, string> = {}
2025-09-15 09:31:47 +00:00
if (!newStatus && !reason.trim()) {
2025-09-15 21:29:07 +00:00
newErrors.reason = 'Ekipleri pasif yaparken sebep belirtmeniz gerekli'
2025-09-15 09:31:47 +00:00
}
2025-09-15 21:29:07 +00:00
setErrors(newErrors)
return Object.keys(newErrors).length === 0
}
2025-09-15 09:31:47 +00:00
const handleSave = () => {
if (validateForm()) {
2025-09-15 21:29:07 +00:00
const teamIds = selectedTeams.map((team) => team.id)
onSave(teamIds, newStatus, reason.trim() || undefined)
onClose()
2025-09-15 09:31:47 +00:00
}
2025-09-15 21:29:07 +00:00
}
2025-09-15 09:31:47 +00:00
const getImpactAnalysis = () => {
2025-09-15 21:29:07 +00:00
const teamsToActivate = newStatus ? inactiveTeams : []
const teamsToDeactivate = newStatus ? [] : activeTeams
2025-09-15 09:31:47 +00:00
return {
teamsToActivate,
teamsToDeactivate,
totalMembers: selectedTeams.reduce(
(total, team) => total + team.members.filter((m) => m.isActive).length,
2025-09-15 21:29:07 +00:00
0,
2025-09-15 09:31:47 +00:00
),
activeMembers: activeTeams.reduce(
(total, team) => total + team.members.filter((m) => m.isActive).length,
2025-09-15 21:29:07 +00:00
0,
2025-09-15 09:31:47 +00:00
),
2025-09-15 21:29:07 +00:00
}
}
2025-09-15 09:31:47 +00:00
2025-09-15 21:29:07 +00:00
const impact = getImpactAnalysis()
2025-09-15 09:31:47 +00:00
return (
isOpen && (
<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">
<div>
2025-09-15 21:29:07 +00:00
<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>
2025-09-15 09:31:47 +00:00
</div>
<button
onClick={onClose}
className="p-2 text-gray-400 hover:text-gray-600 transition-colors"
>
<FaTimes className="w-4 h-4" />
</button>
</div>
{/* Content */}
<div className="p-3 space-y-3">
{/* Status Selection */}
<div>
2025-09-15 21:29:07 +00:00
<h3 className="text-sm font-medium text-gray-900 mb-2">Yeni Durum</h3>
2025-09-15 09:31:47 +00:00
<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
type="radio"
checked={newStatus === true}
onChange={() => setNewStatus(true)}
className="text-green-600 focus:ring-green-500"
/>
<FaCheckCircle className="w-5 h-5 text-green-600 ml-3 mr-2" />
<div>
<span className="font-medium text-gray-900">Aktif</span>
<p className="text-xs text-gray-600">
Ekipler aktif hale gelir ve emirleri alabilir
</p>
</div>
</label>
<label className="flex items-center p-2 border border-gray-200 rounded-lg hover:bg-gray-50 cursor-pointer">
<input
type="radio"
checked={newStatus === false}
onChange={() => setNewStatus(false)}
className="text-red-600 focus:ring-red-500"
/>
<FaTimesCircle className="w-5 h-5 text-red-600 ml-3 mr-2" />
<div>
<span className="font-medium text-gray-900">Pasif</span>
<p className="text-xs text-gray-600">
Ekipler pasif hale gelir ve yeni emirleri alamaz
</p>
</div>
</label>
</div>
</div>
{/* Reason (required for deactivation) */}
{!newStatus && (
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Pasif Yapma Sebebi *
</label>
<textarea
value={reason}
onChange={(e) => {
2025-09-15 21:29:07 +00:00
setReason(e.target.value)
2025-09-15 09:31:47 +00:00
if (errors.reason) {
2025-09-15 21:29:07 +00:00
setErrors((prev) => ({ ...prev, reason: '' }))
2025-09-15 09:31:47 +00:00
}
}}
rows={2}
className={`w-full px-3 py-1.5 text-sm border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 ${
2025-09-15 21:29:07 +00:00
errors.reason ? 'border-red-500' : 'border-gray-300'
2025-09-15 09:31:47 +00:00
}`}
placeholder="Ekiplerin neden pasif yapıldığınııklayın..."
/>
2025-09-15 21:29:07 +00:00
{errors.reason && <p className="text-red-500 text-xs mt-1">{errors.reason}</p>}
2025-09-15 09:31:47 +00:00
</div>
)}
{/* Impact Analysis */}
<div className="bg-gray-50 rounded-lg p-3">
2025-09-15 21:29:07 +00:00
<h3 className="text-sm font-medium text-gray-900 mb-3">Etki Analizi</h3>
2025-09-15 09:31:47 +00:00
<div className="grid grid-cols-2 gap-3 mb-3">
<div className="text-center">
2025-09-15 21:29:07 +00:00
<div className="text-base font-bold text-blue-600">{selectedTeams.length}</div>
<div className="text-sm text-gray-600">Toplam Seçili Ekip</div>
2025-09-15 09:31:47 +00:00
</div>
<div className="text-center">
2025-09-15 21:29:07 +00:00
<div className="text-base font-bold text-green-600">{impact.totalMembers}</div>
2025-09-15 09:31:47 +00:00
<div className="text-sm text-gray-600">Toplam Üye Sayısı</div>
</div>
</div>
{!newStatus && impact.teamsToDeactivate.length > 0 && (
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-2">
<div className="flex items-start space-x-3">
<FaExclamationTriangle className="w-5 h-5 text-yellow-600 mt-0.5" />
<div>
2025-09-15 21:29:07 +00:00
<h4 className="text-sm font-medium text-yellow-800">Uyarı</h4>
2025-09-15 09:31:47 +00:00
<p className="text-sm text-yellow-700 mt-1">
2025-09-15 21:29:07 +00:00
{impact.teamsToDeactivate.length} aktif ekip pasif yapılacak. Bu ekipler
artık yeni emirleri alamayacak.
2025-09-15 09:31:47 +00:00
</p>
</div>
</div>
</div>
)}
{newStatus && impact.teamsToActivate.length > 0 && (
<div className="bg-green-50 border border-green-200 rounded-lg p-2">
<div className="flex items-start space-x-3">
<FaCheckCircle className="w-5 h-5 text-green-600 mt-0.5" />
<div>
2025-09-15 21:29:07 +00:00
<h4 className="text-sm font-medium text-green-800">Bilgi</h4>
2025-09-15 09:31:47 +00:00
<p className="text-sm text-green-700 mt-1">
2025-09-15 21:29:07 +00:00
{impact.teamsToActivate.length} pasif ekip aktif hale gelecek. Bu ekipler
tekrar emirleri alabilecek.
2025-09-15 09:31:47 +00:00
</p>
</div>
</div>
</div>
)}
</div>
{/* Selected Teams List */}
<div>
2025-09-15 21:29:07 +00:00
<h3 className="text-sm font-medium text-gray-900 mb-2">Etkilenecek Ekipler</h3>
2025-09-15 09:31:47 +00:00
<div className="max-h-32 overflow-y-auto border border-gray-200 rounded-lg">
{selectedTeams.map((team) => (
<div
key={team.id}
className="flex items-center justify-between p-2 border-b border-gray-100 last:border-b-0"
>
<div>
2025-09-15 21:29:07 +00:00
<h4 className="font-medium text-sm text-gray-900">{team.name}</h4>
2025-09-15 09:31:47 +00:00
<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
2025-09-15 21:29:07 +00:00
? 'bg-green-100 text-green-800'
: 'bg-gray-100 text-gray-800'
2025-09-15 09:31:47 +00:00
}`}
>
2025-09-15 21:29:07 +00:00
{team.isActive ? 'Aktif' : 'Pasif'}
2025-09-15 09:31:47 +00:00
</span>
<span className="text-sm text-gray-500"></span>
<span
className={`px-2 py-1 text-xs font-semibold rounded-full ${
2025-09-15 21:29:07 +00:00
newStatus ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'
2025-09-15 09:31:47 +00:00
}`}
>
2025-09-15 21:29:07 +00:00
{newStatus ? 'Aktif' : 'Pasif'}
2025-09-15 09:31:47 +00:00
</span>
</div>
</div>
))}
</div>
</div>
</div>
{/* Footer */}
<div className="flex items-center justify-end space-x-2 p-3 border-t border-gray-200">
<button
onClick={onClose}
className="px-3 py-1.5 text-sm text-gray-600 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
>
İptal
</button>
<button
onClick={handleSave}
className={`px-3 py-1.5 text-sm text-white rounded-lg transition-colors flex items-center space-x-2 ${
2025-09-15 21:29:07 +00:00
newStatus ? 'bg-green-600 hover:bg-green-700' : 'bg-red-600 hover:bg-red-700'
2025-09-15 09:31:47 +00:00
}`}
>
<FaSave className="w-4 h-4" />
<span>Durumu Değiştir</span>
</button>
</div>
</div>
</div>
)
2025-09-15 21:29:07 +00:00
)
}
2025-09-15 09:31:47 +00:00
2025-09-15 21:29:07 +00:00
export default TeamStatusChangeModal