erp-platform/ui/src/views/maintenance/components/TeamStatusChangeModal.tsx
2025-09-16 00:29:07 +03:00

267 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 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) => {
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ıı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 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 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