267 lines
10 KiB
TypeScript
267 lines
10 KiB
TypeScript
import React, { useState, useEffect } from 'react'
|
||
import {
|
||
FaTimes,
|
||
FaSave,
|
||
FaExclamationTriangle,
|
||
FaCheckCircle,
|
||
FaTimesCircle,
|
||
} 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[]
|
||
}
|
||
|
||
const TeamStatusChangeModal: React.FC<TeamStatusChangeModalProps> = ({
|
||
isOpen,
|
||
onClose,
|
||
onSave,
|
||
selectedTeams,
|
||
}) => {
|
||
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)
|
||
|
||
useEffect(() => {
|
||
if (isOpen) {
|
||
// Reset form when modal opens
|
||
setNewStatus(true)
|
||
setReason('')
|
||
setErrors({})
|
||
}
|
||
}, [isOpen])
|
||
|
||
const validateForm = () => {
|
||
const newErrors: Record<string, string> = {}
|
||
|
||
if (!newStatus && !reason.trim()) {
|
||
newErrors.reason = 'Ekipleri pasif yaparken sebep belirtmeniz gerekli'
|
||
}
|
||
|
||
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 getImpactAnalysis = () => {
|
||
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,
|
||
),
|
||
activeMembers: activeTeams.reduce(
|
||
(total, team) => total + team.members.filter((m) => m.isActive).length,
|
||
0,
|
||
),
|
||
}
|
||
}
|
||
|
||
const impact = getImpactAnalysis()
|
||
|
||
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>
|
||
<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}
|
||
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>
|
||
<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
|
||
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 iş 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 iş 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) => {
|
||
setReason(e.target.value)
|
||
if (errors.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'
|
||
}`}
|
||
placeholder="Ekiplerin neden pasif yapıldığını açıklayın..."
|
||
/>
|
||
{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>
|
||
<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>
|
||
<div className="text-center">
|
||
<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>
|
||
|
||
{!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>
|
||
<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 iş emirleri alamayacak.
|
||
</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>
|
||
<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 iş emirleri alabilecek.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Selected Teams List */}
|
||
<div>
|
||
<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
|
||
key={team.id}
|
||
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>
|
||
<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'
|
||
}`}
|
||
>
|
||
{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 ? 'Aktif' : 'Pasif'}
|
||
</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 ${
|
||
newStatus ? 'bg-green-600 hover:bg-green-700' : 'bg-red-600 hover:bg-red-700'
|
||
}`}
|
||
>
|
||
<FaSave className="w-4 h-4" />
|
||
<span>Durumu Değiştir</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
)
|
||
}
|
||
|
||
export default TeamStatusChangeModal
|