erp-platform/ui/src/views/hr/components/BadgeAssignmentModal.tsx

337 lines
13 KiB
TypeScript
Raw Normal View History

2025-09-15 09:31:47 +00:00
import React, { useState, useEffect } from "react";
import {
FaUsers,
FaAward,
FaSave,
FaTimesCircle,
FaCalendarAlt,
} from "react-icons/fa";
import { mockEmployees } from "../../../mocks/mockEmployees";
import { mockBadges } from "../../../mocks/mockBadges";
export interface BadgeAssignmentFormData {
employeeId: string;
badgeId: string;
reason?: string;
earnedDate: string;
expiryDate?: string;
notes?: string;
}
interface BadgeAssignmentModalProps {
isOpen: boolean;
onClose: () => void;
onSubmit: (assignmentData: BadgeAssignmentFormData) => void;
preSelectedEmployeeId?: string;
preSelectedBadgeId?: string;
}
const BadgeAssignmentModal: React.FC<BadgeAssignmentModalProps> = ({
isOpen,
onClose,
onSubmit,
preSelectedEmployeeId,
preSelectedBadgeId,
}) => {
const [formData, setFormData] = useState<BadgeAssignmentFormData>({
employeeId: "",
badgeId: "",
reason: "",
earnedDate: new Date().toISOString().split("T")[0],
expiryDate: "",
notes: "",
});
const [searchEmployee, setSearchEmployee] = useState("");
const [searchBadge, setSearchBadge] = useState("");
useEffect(() => {
if (isOpen) {
setFormData({
employeeId: preSelectedEmployeeId || "",
badgeId: preSelectedBadgeId || "",
reason: "",
earnedDate: new Date().toISOString().split("T")[0],
expiryDate: "",
notes: "",
});
setSearchEmployee("");
setSearchBadge("");
}
}, [isOpen, preSelectedEmployeeId, preSelectedBadgeId]);
const handleInputChange = (
e: React.ChangeEvent<
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
>
) => {
const { name, value } = e.target;
setFormData((prev) => ({
...prev,
[name]: value,
}));
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
onSubmit(formData);
onClose();
};
const filteredEmployees = mockEmployees.filter(
(employee) =>
employee.fullName.toLowerCase().includes(searchEmployee.toLowerCase()) ||
employee.code.toLowerCase().includes(searchEmployee.toLowerCase())
);
const filteredBadges = mockBadges.filter(
(badge) =>
badge.isActive &&
(badge.name.toLowerCase().includes(searchBadge.toLowerCase()) ||
badge.description.toLowerCase().includes(searchBadge.toLowerCase()))
);
const selectedEmployee = mockEmployees.find(
(emp) => emp.id === formData.employeeId
);
const selectedBadge = mockBadges.find(
(badge) => badge.id === formData.badgeId
);
return (
isOpen && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-xl shadow-2xl w-full max-w-2xl mx-4 max-h-[90vh] overflow-y-auto">
{/* Header */}
<div className="flex items-center justify-between p-3 border-b border-gray-200 bg-gradient-to-r from-green-50 to-emerald-50 rounded-t-xl">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-green-600 rounded-lg flex items-center justify-center">
<FaAward className="w-5 h-5 text-white" />
</div>
<div>
<h3 className="text-xl font-bold text-gray-900">Rozet Ata</h3>
2025-09-15 21:02:48 +00:00
<p className="text-gray-600">
2025-09-15 09:31:47 +00:00
Personele başarı rozeti atayın
</p>
</div>
</div>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 p-1 hover:bg-gray-100 rounded-lg transition-colors"
>
<FaTimesCircle className="w-6 h-6" />
</button>
</div>
{/* Form */}
<form onSubmit={handleSubmit} className="p-3">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{/* Sol Kolon - Personel Seçimi */}
<div className="space-y-4">
<div className="bg-gray-50 p-2 rounded-lg">
<h4 className="text-sm font-semibold text-gray-800 mb-2 flex items-center gap-2">
<FaUsers className="w-5 h-5 text-blue-600" />
Personel Seçimi
</h4>
<div className="space-y-4">
<div>
<select
name="employeeId"
value={formData.employeeId}
onChange={handleInputChange}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"
required
>
<option value="">Personel seçin...</option>
{filteredEmployees.map((employee) => (
<option key={employee.id} value={employee.id}>
{employee.fullName} - {employee.code}
</option>
))}
</select>
</div>
{selectedEmployee && (
<div className="bg-blue-50 p-2 rounded-lg border border-blue-200 text-xs">
<div className="flex items-start justify-between">
<div className="flex-1">
<h4 className="font-medium text-blue-900 mb-1">
{selectedEmployee.fullName}
</h4>
<p className="text-xs text-blue-700 mb-1">
{selectedEmployee.code} {" "}
{selectedEmployee.department?.name}
</p>
<div className="text-xs text-blue-600">
<span className="font-medium">Email:</span>{" "}
{selectedEmployee.email}
</div>
</div>
</div>
</div>
)}
</div>
</div>
</div>
{/* Sağ Kolon - Rozet Seçimi */}
<div className="space-y-4">
<div className="bg-gray-50 p-2 rounded-lg">
<h4 className="text-sm font-semibold text-gray-800 mb-2 flex items-center gap-2">
<FaAward className="w-5 h-5 text-purple-600" />
Rozet Seçimi
</h4>
<div className="space-y-4">
<div>
<select
name="badgeId"
value={formData.badgeId}
onChange={handleInputChange}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"
required
>
<option value="">Rozet seçin...</option>
{filteredBadges.map((badge) => (
<option key={badge.id} value={badge.id}>
{badge.icon} {badge.name} ({badge.points} puan)
</option>
))}
</select>
</div>
{selectedBadge && (
<div className="bg-purple-50 p-2 rounded-lg border border-purple-200 text-xs">
<div className="flex items-start gap-3">
<div
className="w-10 h-10 rounded-full flex items-center justify-center text-lg flex-shrink-0"
style={{
backgroundColor: selectedBadge.backgroundColor,
border: `2px solid ${selectedBadge.color}`,
}}
>
{selectedBadge.icon}
</div>
<div className="flex-1">
<h4 className="font-medium text-purple-900 mb-1">
{selectedBadge.name}
</h4>
<p className="text-xs text-purple-700 mb-1">
{selectedBadge.description}
</p>
<div className="grid grid-cols-2 gap-2 text-xs text-purple-600">
<div>
<span className="font-medium">Puan:</span>{" "}
{selectedBadge.points}
</div>
<div>
<span className="font-medium">Kategori:</span>{" "}
{selectedBadge.category}
</div>
</div>
<div className="mt-2 text-xs text-purple-600">
<span className="font-medium">Kriter:</span>{" "}
{selectedBadge.criteria}
</div>
</div>
</div>
</div>
)}
</div>
</div>
</div>
</div>
{/* Atama Detayları */}
<div className="mt-3 bg-gray-50 p-2 rounded-lg">
<h4 className="text-sm font-semibold text-gray-800 mb-2 flex items-center gap-2">
<FaCalendarAlt className="w-5 h-5 text-green-600" />
Atama Detayları
</h4>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Kazanılma Tarihi <span className="text-red-500">*</span>
</label>
<input
type="date"
name="earnedDate"
value={formData.earnedDate}
onChange={handleInputChange}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"
required
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Geçerlilik Süresi (Opsiyonel)
</label>
<input
type="date"
name="expiryDate"
value={formData.expiryDate}
onChange={handleInputChange}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Kazanma Nedeni
</label>
<input
type="text"
name="reason"
value={formData.reason}
onChange={handleInputChange}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"
placeholder="Örn: Q3 hedeflerini %120 başarıyla tamamladı"
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Notlar
</label>
<textarea
name="notes"
value={formData.notes}
onChange={handleInputChange}
rows={2}
className="w-full px-2 py-1 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-colors"
placeholder="Ek notlar..."
/>
</div>
</div>
</div>
{/* Footer */}
<div className="flex items-center justify-end gap-2 mt-3 pt-3 border-t border-gray-200">
<button
type="button"
onClick={onClose}
className="px-3 py-1 text-sm text-gray-700 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors flex items-center gap-2"
>
<FaTimesCircle className="w-4 h-4" />
İptal
</button>
<button
type="submit"
className="px-3 py-1 text-sm bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors flex items-center gap-2 shadow-md hover:shadow-lg"
>
<FaSave className="w-4 h-4" />
Rozet Ata
</button>
</div>
</form>
</div>
</div>
)
);
};
export default BadgeAssignmentModal;