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

2666 lines
119 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 } from 'react'
import {
FaUsers,
FaEye,
FaEdit,
FaPlus,
FaChartBar,
FaTimes,
FaSave,
FaPlay,
FaPoll,
} from 'react-icons/fa'
import {
HrEvaluation360,
CampaignStatusEnum,
AssessorTypeEnum,
ParticipantStatusEnum,
QuestionTypeEnum,
ResultStatusEnum,
HrEvaluation360Result,
HrGroupScore,
HrAssessorTypeScore,
} from '../../../types/hr'
import DataTable, { Column } from '../../../components/common/DataTable'
import { mockEvaluation360 } from '../../../mocks/mockEvaluation360'
import { mockEvaluation360Results } from '../../../mocks/mockEvaluation360Results'
import { mockEmployees } from '../../../mocks/mockEmployees'
import { mockDepartments } from '../../../mocks/mockDepartments'
import { mockEvaluation360Templates } from '../../../mocks/mockEvaluation360Templates'
import { mockBusinessParties } from '../../../mocks/mockBusinessParties'
import Widget from '../../../components/common/Widget'
import {
getAssessorTypeDescription,
getAssessorTypeText,
getParticipantStatusColor,
getParticipantStatusText,
getCampaignStatusColor,
getCampaignStatusText,
} from '../../../utils/erp'
import { Container } from '@/components/shared'
const Degree360Evaluation: React.FC = () => {
const [activeTab, setActiveTab] = useState<'campaigns' | 'results'>('campaigns')
const [selectedStatus, setSelectedStatus] = useState<string>('all')
const [selectedEmployee, setSelectedEmployee] = useState<string>('all')
const [selectedDepartment, setSelectedDepartment] = useState<string>('all')
// Results tab filters
const [selectedResultsStatus, setSelectedResultsStatus] = useState<string>('all')
const [selectedResultsEmployee, setSelectedResultsEmployee] = useState<string>('all')
const [selectedResultsDepartment, setSelectedResultsDepartment] = useState<string>('all')
const [selectedResultsCampaign, setSelectedResultsCampaign] = useState<string>('all')
// Modal states
const [showCampaignModal, setShowCampaignModal] = useState(false)
const [showViewModal, setShowViewModal] = useState(false)
const [showEvaluationModal, setShowEvaluationModal] = useState(false)
const [showResultDetailModal, setShowResultDetailModal] = useState(false)
const [showResultEditModal, setShowResultEditModal] = useState(false)
const [selectedCampaign, setSelectedCampaign] = useState<HrEvaluation360 | null>(null)
const [selectedResult, setSelectedResult] = useState<{
resultId: string
evaluatedEmployeeName: string
evaluatorName: string
campaignName: string
overallScore: number
scorePercentage: number
evaluatedEmployeeId: string
evaluatorId: string
campaignId: string
evaluatorType: AssessorTypeEnum
status: ParticipantStatusEnum
completedDate?: Date
} | null>(null)
// Evaluation states
const [evaluationTarget, setEvaluationTarget] = useState<string>('')
const [evaluationEvaluator, setEvaluationEvaluator] = useState<string>('')
const [selectedAssessorType, setSelectedAssessorType] = useState<AssessorTypeEnum | null>(null)
const [externalEvaluatorName, setExternalEvaluatorName] = useState<string>('')
const [externalEvaluatorEmail, setExternalEvaluatorEmail] = useState<string>('')
const [selectedCustomerId, setSelectedCustomerId] = useState<string>('')
const [evaluatorSearchTerm, setEvaluatorSearchTerm] = useState<string>('')
const [currentCampaignForEvaluation, setCurrentCampaignForEvaluation] =
useState<HrEvaluation360 | null>(null)
// Evaluation responses state
const [evaluationResponses, setEvaluationResponses] = useState<Record<string, string | number>>(
{},
)
// Edit modal states
const [editResponses, setEditResponses] = useState<Record<string, string | number>>({})
const [editManagerComments, setEditManagerComments] = useState<string>('')
const [editHrComments, setEditHrComments] = useState<string>('')
const [editResultStatus, setEditResultStatus] = useState<string>('PENDING')
// Form states
const [campaignFormData, setCampaignFormData] = useState({
name: '',
description: '',
templateId: '',
departmentId: '',
targetEmployees: [] as string[],
startDate: '',
endDate: '',
})
// Event handlers
const handleCloseModal = () => {
setShowCampaignModal(false)
setShowViewModal(false)
setShowEvaluationModal(false)
setShowResultDetailModal(false)
setShowResultEditModal(false)
setSelectedCampaign(null)
setSelectedResult(null)
setEvaluationTarget('')
setEvaluationEvaluator('')
setSelectedAssessorType(null)
setExternalEvaluatorName('')
setExternalEvaluatorEmail('')
setSelectedCustomerId('')
setEvaluatorSearchTerm('')
setCurrentCampaignForEvaluation(null)
setEvaluationResponses({})
setEditResponses({})
setEditManagerComments('')
setEditHrComments('')
setEditResultStatus('PENDING')
setCampaignFormData({
name: '',
description: '',
templateId: '',
departmentId: '',
targetEmployees: [],
startDate: '',
endDate: '',
})
}
// Response handling functions
const handleResponseChange = (questionId: string, value: string | number) => {
setEvaluationResponses((prev) => ({
...prev,
[questionId]: value,
}))
}
// Edit response handling function
const handleEditResponseChange = (questionId: string, value: string | number) => {
setEditResponses((prev) => ({
...prev,
[questionId]: value,
}))
}
// Evaluation kaydetme fonksiyonu
const handleSaveEvaluation = () => {
if (!currentCampaignForEvaluation || !evaluationTarget || !evaluationEvaluator) {
alert('Tüm alanları doldurun!')
return
}
const template = mockEvaluation360Templates.find(
(t) => t.id === currentCampaignForEvaluation.templateId,
)
if (!template) {
alert('Template bulunamadı!')
return
}
// Responses oluştur
const responses = Object.entries(evaluationResponses).map(([questionId, responseValue]) => {
const question = template.questionGroups
.flatMap((g) => g.questions)
.find((q) => q.id === questionId)
let score = 0
if (question) {
if (question.questionType === QuestionTypeEnum.Rating) {
score = Number(responseValue)
} else if (question.questionType === QuestionTypeEnum.YesNo) {
score = responseValue === 'yes' ? question.maxRating || 5 : question.minRating || 1
} else if (question.questionType === QuestionTypeEnum.MultipleChoice) {
const option = question.options?.find((o) => o.value === Number(responseValue))
score = option?.value || 0
}
}
return {
id: `response-${Date.now()}-${Math.random()}`,
participantId: `participant-${Date.now()}`,
questionId,
question,
responseValue,
responseText: typeof responseValue === 'string' ? responseValue : undefined,
score,
submittedDate: new Date(),
}
})
// Puanları hesapla
const totalScore = responses.reduce((sum, response) => sum + response.score, 0)
const maxScore = template.questionGroups
.flatMap((g) => g.questions)
.reduce((sum, q) => sum + (q.maxRating || 5), 0)
const scorePercentage = maxScore > 0 ? (totalScore / maxScore) * 100 : 0
// Grup skorlarını hesapla
const groupScores: HrGroupScore[] = template.questionGroups.map((group) => {
const groupResponses = responses.filter((r) =>
group.questions.some((q) => q.id === r.questionId),
)
const groupScore = groupResponses.reduce((sum, r) => sum + r.score, 0)
const groupMaxScore = group.questions.reduce((sum, q) => sum + (q.maxRating || 5), 0)
return {
groupId: group.id,
groupName: group.groupName,
score: groupScore,
maxScore: groupMaxScore,
percentage: groupMaxScore > 0 ? (groupScore / groupMaxScore) * 100 : 0,
responseCount: groupResponses.length,
}
})
// Assessor type skorlarını hesapla
const assessorTypeScores: HrAssessorTypeScore[] = [
{
assessorType: selectedAssessorType!,
assessorCount: 1,
averageScore: totalScore,
maxScore: maxScore,
percentage: scorePercentage,
},
]
// Evaluation360Result oluştur
const evaluationResult: HrEvaluation360Result = {
id: `result-${Date.now()}`,
campaignId: currentCampaignForEvaluation.id,
employeeId: evaluationTarget,
employee: mockEmployees.find((e) => e.id === evaluationTarget),
participants: [
{
id: `participant-${Date.now()}`,
campaignId: currentCampaignForEvaluation.id,
evaluatedEmployeeId: evaluationTarget,
evaluatedEmployee: mockEmployees.find((e) => e.id === evaluationTarget),
evaluatorId: evaluationEvaluator,
evaluator:
selectedAssessorType === AssessorTypeEnum.External ||
selectedAssessorType === AssessorTypeEnum.Customer
? undefined // External ve Customer için Employee bilgisi yok
: mockEmployees.find((e) => e.id === evaluationEvaluator),
evaluatorType: selectedAssessorType!,
status: ParticipantStatusEnum.Completed,
invitedDate: new Date(),
startedDate: new Date(),
completedDate: new Date(),
responses,
overallScore: totalScore,
notes: '',
},
],
overallScore: totalScore,
maxPossibleScore: maxScore,
scorePercentage,
groupScores,
assessorTypeScores,
strengths: ['Güçlü iletişim', 'Takım çalışması'], // Örnek veriler
developmentAreas: ['Zaman yönetimi', 'Teknik beceriler'], // Örnek veriler
actionPlan: ['Zaman yönetimi kursu alma', 'Teknik eğitimlere katılma'], // Örnek veriler
managerComments: '',
hrComments: '',
status: ResultStatusEnum.Pending,
generatedDate: new Date(),
approvedBy: undefined,
approvedDate: undefined,
}
// Console'a yazdır
console.log('Evaluation360Result:', evaluationResult)
alert('Değerlendirme başarıyla kaydedildi! Sonuç konsola yazdırıldı.')
handleCloseModal()
}
const handleNewCampaign = () => {
setSelectedCampaign(null)
setShowCampaignModal(true)
}
const handleEditCampaign = (campaign: HrEvaluation360 | null) => {
if (campaign) {
setSelectedCampaign(campaign)
setCampaignFormData({
name: campaign.name,
description: campaign.description,
templateId: campaign.templateId,
departmentId: campaign.departmentId || '',
targetEmployees: campaign.targetEmployees,
startDate: campaign.startDate.toISOString().split('T')[0],
endDate: campaign.endDate.toISOString().split('T')[0],
})
setShowCampaignModal(true)
}
}
const handleViewCampaign = (campaign: HrEvaluation360) => {
setSelectedCampaign(campaign)
setShowViewModal(true)
}
const handleSaveCampaign = () => {
console.log('Değerlendirme kaydediliyor:', campaignFormData)
handleCloseModal()
}
const handleDepartmentChange = (departmentId: string) => {
setSelectedDepartment(departmentId)
setCampaignFormData({
...campaignFormData,
departmentId,
targetEmployees: [],
})
}
// Değerlendirme yapma handler'ı
const handleStartEvaluation = () => {
setCurrentCampaignForEvaluation(null)
setEvaluationTarget('')
setEvaluationEvaluator('')
setShowEvaluationModal(true)
}
// Otomatik değerlendirici belirleme fonksiyonu (360° metodolojisi)
const getEvaluatorsByType = (targetEmployeeId: string, assessorType: AssessorTypeEnum) => {
const targetEmployee = mockEmployees.find((emp) => emp.id === targetEmployeeId)
if (!targetEmployee) return []
switch (assessorType) {
case AssessorTypeEnum.Self: {
return [
{
id: targetEmployee.id,
name: targetEmployee.fullName,
title: targetEmployee.jobPosition?.name,
department:
mockDepartments.find((d) => d.id === targetEmployee.departmentId)?.name || '',
type: 'employee',
},
]
}
case AssessorTypeEnum.Manager: {
const managers = mockEmployees.filter(
(emp) =>
emp.departmentId === targetEmployee.departmentId &&
(typeof emp.jobPosition?.level === 'number' &&
typeof targetEmployee.jobPosition?.level === 'number'
? emp.jobPosition?.level > targetEmployee.jobPosition?.level
: emp.jobPosition?.name.includes('Müdür') ||
emp.jobPosition?.name.includes('Manager')),
)
return managers.map((emp) => ({
id: emp.id,
name: emp.fullName,
title: emp.jobPosition?.name,
department: mockDepartments.find((d) => d.id === emp.departmentId)?.name || '',
type: 'employee',
}))
}
case AssessorTypeEnum.Peer: {
const peers = mockEmployees.filter(
(emp) =>
emp.id !== targetEmployeeId &&
emp.departmentId === targetEmployee.departmentId &&
emp.jobPosition?.level === targetEmployee.jobPosition?.level,
)
return peers.map((emp) => ({
id: emp.id,
name: emp.fullName,
title: emp.jobPosition?.name,
department: mockDepartments.find((d) => d.id === emp.departmentId)?.name || '',
type: 'employee',
}))
}
case AssessorTypeEnum.Subordinate: {
const subordinates = mockEmployees.filter(
(emp) =>
emp.departmentId === targetEmployee.departmentId &&
(typeof emp.jobPosition?.level === 'number' &&
typeof targetEmployee.jobPosition?.level === 'number'
? emp.jobPosition?.level < targetEmployee.jobPosition?.level
: !emp.jobPosition?.name.includes('Müdür') &&
!emp.jobPosition?.name.includes('Manager')),
)
return subordinates.map((emp) => ({
id: emp.id,
name: emp.fullName,
title: emp.jobPosition?.name,
department: mockDepartments.find((d) => d.id === emp.departmentId)?.name || '',
type: 'employee',
}))
}
case AssessorTypeEnum.Customer: {
return mockBusinessParties.map((customer) => ({
id: customer.id,
name: customer.name,
title: 'Müşteri Temsilcisi',
department: 'Müşteri',
type: 'customer',
}))
}
case AssessorTypeEnum.External: {
return [
{
id: 'external',
name: 'Dış Değerlendirici',
title: 'Harici',
department: 'Dış Paydaş',
type: 'external',
},
]
}
case AssessorTypeEnum.HRUpperManagement: {
const hrEmployees = mockEmployees.filter(
(emp) =>
emp.id !== targetEmployeeId && (emp.departmentId === 'hr' || emp.departmentId === '3'), // HR departmanı
)
return hrEmployees.map((emp) => ({
id: emp.id,
name: emp.fullName,
title: emp.jobPosition?.name,
department: mockDepartments.find((d) => d.id === emp.departmentId)?.name || '',
type: 'employee',
}))
}
case AssessorTypeEnum.OtherDepartment: {
const otherDepartmentEmployees = mockEmployees.filter(
(emp) => emp.id !== targetEmployeeId && emp.departmentId !== targetEmployee.departmentId,
)
return otherDepartmentEmployees.map((emp) => ({
id: emp.id,
name: emp.fullName,
title: emp.jobPosition?.name,
department: mockDepartments.find((d) => d.id === emp.departmentId)?.name || '',
type: 'employee',
}))
}
default:
return []
}
}
// Değerlendiren bilgisini getiren fonksiyon
const getEvaluatorInfo = () => {
if (evaluationEvaluator === 'external') {
return externalEvaluatorName
}
if (selectedAssessorType === AssessorTypeEnum.Customer) {
const customer = mockBusinessParties.find((c) => c.id === selectedCustomerId)
return customer ? customer.name : 'Müşteri Bulunamadı'
}
const employee = mockEmployees.find((e) => e.id === evaluationEvaluator)
return employee ? employee.fullName : 'Çalışan Bulunamadı'
}
// Template'deki izin verilen assessor tiplerini getir
const getAllowedAssessorTypes = () => {
if (!currentCampaignForEvaluation) return []
const template = mockEvaluation360Templates.find(
(t) => t.id === currentCampaignForEvaluation.templateId,
)
return template?.assessorTypes || []
}
// Helper function to get participants for a campaign from results
const getCampaignParticipants = (campaignId: string) => {
return mockEvaluation360Results
.filter((result) => result.campaignId === campaignId)
.flatMap((result) => result.participants)
}
// Filtered data
const filteredCampaigns = mockEvaluation360.filter((campaign) => {
if (selectedStatus !== 'all' && campaign.status !== selectedStatus) return false
if (selectedDepartment !== 'all' && campaign.departmentId !== selectedDepartment) return false
if (selectedEmployee !== 'all') {
const participants = getCampaignParticipants(campaign.id)
const hasEmployee = participants.some(
(p) => p.evaluatedEmployeeId === selectedEmployee || p.evaluatorId === selectedEmployee,
)
if (!hasEmployee) return false
}
return true
})
const filteredEmployeesByDepartment = mockEmployees.filter(
(emp) => selectedDepartment === 'all' || emp.departmentId === selectedDepartment,
)
// Statistics
const totalActiveCampaigns = mockEvaluation360.filter(
(c) => c.status === CampaignStatusEnum.Active,
).length
const allParticipants = mockEvaluation360Results.flatMap((result) => result.participants)
const totalCompletedEvaluations = allParticipants.filter(
(p) => p.status === ParticipantStatusEnum.Completed,
).length
const totalPendingEvaluations = allParticipants.filter(
(p) => p.status === ParticipantStatusEnum.Invited || p.status === ParticipantStatusEnum.Started,
).length
const totalParticipants = allParticipants.length
// Results helper functions
// Participant evaluation helper functions
const handleViewEvaluationDetail = (result: {
resultId: string
evaluatedEmployeeName: string
evaluatorName: string
campaignName: string
overallScore: number
scorePercentage: number
evaluatedEmployeeId: string
evaluatorId: string
campaignId: string
evaluatorType: AssessorTypeEnum
status: ParticipantStatusEnum
completedDate?: Date
}) => {
// Değerlendirme detaylarını görüntüle
console.log('Viewing evaluation detail:', result)
setSelectedResult(result)
setShowResultDetailModal(true)
}
const handleEditEvaluationDetail = (result: {
resultId: string
evaluatedEmployeeName: string
evaluatorName: string
campaignName: string
overallScore: number
scorePercentage: number
evaluatedEmployeeId: string
evaluatorId: string
campaignId: string
evaluatorType: AssessorTypeEnum
status: ParticipantStatusEnum
completedDate?: Date
}) => {
// Değerlendirme detaylarını düzenle
console.log('Editing evaluation detail:', result)
// Mevcut evaluation result'ını bul
const evaluationResult = mockEvaluation360Results.find((r) => r.id === result.resultId)
if (evaluationResult) {
// Mevcut cevapları yükle
const currentResponses: Record<string, string | number> = {}
evaluationResult.participants.forEach((participant) => {
participant.responses.forEach((response) => {
currentResponses[response.questionId] = response.responseValue
})
})
setEditResponses(currentResponses)
setEditManagerComments(evaluationResult.managerComments || '')
setEditHrComments(evaluationResult.hrComments || '')
setEditResultStatus(evaluationResult.status)
}
setSelectedResult(result)
setShowResultEditModal(true)
}
const getAssessorTypeLabel = (assessorType: AssessorTypeEnum): string => {
return getAssessorTypeText(assessorType)
}
const getAllEvaluationParticipants = () => {
// Tüm sonuçlardan participant verilerini al
const allParticipants = mockEvaluation360Results.flatMap((result) =>
result.participants.map((participant) => ({
...participant,
resultId: result.id,
evaluatedEmployeeName:
mockEmployees.find((e) => e.id === participant.evaluatedEmployeeId)?.fullName ||
'Bilinmiyor',
evaluatorName:
mockEmployees.find((e) => e.id === participant.evaluatorId)?.fullName || 'Bilinmiyor',
campaignName:
mockEvaluation360.find((c) => c.id === participant.campaignId)?.name || 'Bilinmiyor',
overallScore: result.overallScore,
scorePercentage: result.scorePercentage,
result: result,
})),
)
// Filtreleme işlemi
return allParticipants.filter((participant) => {
// Durum filtresi
if (selectedResultsStatus !== 'all' && participant.status !== selectedResultsStatus) {
return false
}
// Kampanya filtresi
if (selectedResultsCampaign !== 'all' && participant.campaignId !== selectedResultsCampaign) {
return false
}
// Değerlendirilecek kişi filtresi
if (
selectedResultsEmployee !== 'all' &&
participant.evaluatedEmployeeId !== selectedResultsEmployee
) {
return false
}
// Departman filtresi
if (selectedResultsDepartment !== 'all') {
const evaluatedEmployee = mockEmployees.find(
(e) => e.id === participant.evaluatedEmployeeId,
)
if (!evaluatedEmployee || evaluatedEmployee.departmentId !== selectedResultsDepartment) {
return false
}
}
return true
})
}
// Columns for campaigns table
const campaignColumns: Column<HrEvaluation360>[] = [
{
key: 'name',
header: 'Değerlendirme Adı',
sortable: true,
},
{
key: 'departmentId',
header: 'Departman',
render: (item: HrEvaluation360) => {
const department = mockDepartments.find((d) => d.id === item.departmentId)
return department?.name || 'Tüm Departmanlar'
},
},
{
key: 'templateId',
header: 'Şablon',
render: (item: HrEvaluation360) => {
const template = mockEvaluation360Templates.find((t) => t.id === item.templateId)
return template?.name || 'Bilinmiyor'
},
},
{
key: 'status',
header: 'Durum',
render: (item: HrEvaluation360) => (
<span
className={`px-2 py-1 text-xs font-medium rounded-full ${getCampaignStatusColor(
item.status,
)}`}
>
{getCampaignStatusText(item.status)}
</span>
),
},
{
key: 'startDate',
header: 'Başlangıç',
render: (item: HrEvaluation360) => item.startDate.toLocaleDateString('tr-TR'),
},
{
key: 'endDate',
header: 'Bitiş',
render: (item: HrEvaluation360) => item.endDate.toLocaleDateString('tr-TR'),
},
{
key: 'participants',
header: 'Katılımcı',
render: (item: HrEvaluation360) => {
const participants = getCampaignParticipants(item.id)
return `${participants.length} kişi`
},
},
{
key: 'id',
header: 'İşlemler',
render: (item: HrEvaluation360) => (
<div className="flex gap-2">
<button
onClick={() => handleViewCampaign(item)}
className="p-1 text-blue-600 hover:text-blue-800"
title="Görüntüle"
>
<FaEye className="w-4 h-4" />
</button>
<button
onClick={() => handleEditCampaign(item)}
className="p-1 text-green-600 hover:text-green-800"
title="Düzenle"
>
<FaEdit className="w-4 h-4" />
</button>
</div>
),
},
]
return (
<Container>
<div className="space-y-2">
{/* Header */}
<div className="flex justify-between items-center">
<div>
<h2 className="text-2xl font-bold text-gray-900">360° Değerlendirme Sistemi</h2>
<p className="text-gray-600">Çok yönlü performans değerlendirme sistemi</p>
</div>
</div>
{/* Statistics Cards */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-2">
<Widget
title="Aktif Değerlendirmeler"
value={totalActiveCampaigns}
color="blue"
icon="FaPlay"
/>
<Widget
title="Tamamlanan Değerlendirmeler"
value={totalCompletedEvaluations}
color="green"
icon="FaCheckCircle"
/>
<Widget
title="Bekleyen Değerlendirmeler"
value={totalPendingEvaluations}
color="yellow"
icon="FaPoll"
/>
<Widget title="Katılımcılar" value={totalParticipants} color="purple" icon="FaUsers" />
</div>
{/* Tabs */}
<div className="bg-white rounded-lg shadow-sm border">
<div className="border-b border-gray-200">
<nav className="-mb-px flex space-x-2 px-2">
{[
{
key: 'campaigns',
label: 'Değerlendirme Kampanyaları',
icon: FaUsers,
},
{
key: 'results',
label: 'Değerlendirme Sonuçları',
icon: FaChartBar,
},
].map(({ key, label, icon: Icon }) => (
<button
key={key}
onClick={() => setActiveTab(key as 'campaigns' | 'results')}
className={`flex items-center gap-2 py-1.5 px-2.5 border-b-2 font-medium text-sm ${
activeTab === key
? 'border-blue-500 text-blue-600'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
}`}
>
<Icon className="w-4 h-4" />
{label}
</button>
))}
</nav>
</div>
<div className="p-3">
{activeTab === 'campaigns' && (
<div className="space-y-3">
{/* Filters and Actions */}
<div className="flex flex-col sm:flex-row gap-3 justify-between">
<div className="flex flex-col sm:flex-row gap-3">
<select
value={selectedStatus}
onChange={(e) => setSelectedStatus(e.target.value)}
className="border border-gray-300 rounded-md px-2.5 py-1 text-sm"
>
<option value="all">Tüm Durumlar</option>
{Object.values(CampaignStatusEnum).map((status) => (
<option key={status} value={status}>
{getCampaignStatusText(status)}
</option>
))}
</select>
<select
value={selectedDepartment}
onChange={(e) => setSelectedDepartment(e.target.value)}
className="border border-gray-300 rounded-md px-2.5 py-1 text-sm"
>
<option value="all">Tüm Departmanlar</option>
{mockDepartments.map((department) => (
<option key={department.id} value={department.id}>
{department.name}
</option>
))}
</select>
<select
value={selectedEmployee}
onChange={(e) => setSelectedEmployee(e.target.value)}
className="border border-gray-300 rounded-md px-2.5 py-1 text-sm"
>
<option value="all">Tüm Personel</option>
{mockEmployees.map((employee) => (
<option key={employee.id} value={employee.id}>
{employee.fullName}
</option>
))}
</select>
</div>
<div className="flex gap-2">
<button
onClick={handleNewCampaign}
className="flex items-center gap-2 px-3 py-1.5 bg-blue-600 text-white rounded-md hover:bg-blue-700 text-sm"
>
<FaPlus className="w-4 h-4" />
Yeni Değerlendirme
</button>
<button
onClick={handleStartEvaluation}
className="flex items-center gap-2 px-3 py-1.5 bg-green-600 text-white rounded-md hover:bg-green-700 text-sm"
>
<FaPoll className="w-4 h-4" />
Değerlendirme Yap
</button>
</div>
</div>
{/* Campaigns Table */}
<DataTable data={filteredCampaigns} columns={campaignColumns} />
</div>
)}
{activeTab === 'results' && (
<div className="space-y-3">
{/* Results Filters */}
<div className="flex flex-col sm:flex-row gap-3 justify-between">
<div className="flex flex-col sm:flex-row gap-3">
<select
value={selectedResultsCampaign}
onChange={(e) => setSelectedResultsCampaign(e.target.value)}
className="border border-gray-300 rounded-md px-2.5 py-1 text-sm"
>
<option value="all">Tüm Değerlendirmeler</option>
{mockEvaluation360.map((campaign) => (
<option key={campaign.id} value={campaign.id}>
{campaign.name}
</option>
))}
</select>
<select
value={selectedResultsStatus}
onChange={(e) => setSelectedResultsStatus(e.target.value)}
className="border border-gray-300 rounded-md px-2.5 py-1 text-sm"
>
<option value="all">Tüm Durumlar</option>
{Object.values(ParticipantStatusEnum).map((status) => (
<option key={status} value={status}>
{getParticipantStatusText(status)}
</option>
))}
</select>
<select
value={selectedResultsDepartment}
onChange={(e) => setSelectedResultsDepartment(e.target.value)}
className="border border-gray-300 rounded-md px-2.5 py-1 text-sm"
>
<option value="all">Tüm Departmanlar</option>
{mockDepartments.map((department) => (
<option key={department.id} value={department.id}>
{department.name}
</option>
))}
</select>
<select
value={selectedResultsEmployee}
onChange={(e) => setSelectedResultsEmployee(e.target.value)}
className="border border-gray-300 rounded-md px-2.5 py-1 text-sm"
>
<option value="all">Tüm Personel</option>
{mockEmployees.map((employee) => (
<option key={employee.id} value={employee.id}>
{employee.firstName} {employee.lastName}
</option>
))}
</select>
</div>
</div>
{/* Results Summary */}
<div className="bg-white rounded-lg border 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-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Değerlendirme Adı
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Değerlendirilecek Kişi
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Değerlendiren
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Toplam İlerleme
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Değerlendirme Durumu
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Toplam Puan
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Puan Yüzdesi
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
İşlemler
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{getAllEvaluationParticipants().map((result) => (
<tr
key={`${result.resultId}-${result.evaluatedEmployeeId}-${result.evaluatorId}`}
className="hover:bg-gray-50 text-xs"
>
<td className="px-3 py-2 whitespace-nowrap text-gray-500">
<div className="flex flex-col">
<span className="font-medium text-gray-900">
{result.campaignName}
</span>
<span className="text-xs text-gray-500">
{result.completedDate
? new Date(result.completedDate).toLocaleDateString('tr-TR')
: '-'}
</span>
</div>
</td>
<td className="px-3 py-2 whitespace-nowrap text-gray-500">
{result.evaluatedEmployeeName}
</td>
<td className="px-3 py-2 whitespace-nowrap text-gray-500">
<div className="flex flex-col">
<span className="font-medium text-gray-900">
{result.evaluatorName}
</span>
<span className="text-xs text-gray-500">
{getAssessorTypeLabel(result.evaluatorType)}
</span>
</div>
</td>
<td className="px-3 py-2 whitespace-nowrap text-sm">
<div className="flex items-center">
<div className="w-16 bg-gray-200 rounded-full h-2 mr-2">
<div
className="bg-blue-600 h-2 rounded-full"
style={{
width: `${
result.status === ParticipantStatusEnum.Completed ? 100 : 50
}%`,
}}
></div>
</div>
<span className="text-sm text-gray-600">
{result.status === ParticipantStatusEnum.Completed ? 100 : 50}%
</span>
</div>
</td>
<td className="px-3 py-2 whitespace-nowrap text-sm text-gray-900">
<span
className={`inline-block px-2 py-1 text-xs rounded-full ${getParticipantStatusColor(
result.status,
)}`}
>
{getParticipantStatusText(result.status)}
</span>
</td>
<td className="px-3 py-2 whitespace-nowrap text-sm text-gray-900">
{result.overallScore}/100
</td>
<td className="px-3 py-2 whitespace-nowrap text-sm text-gray-900">
%{result.scorePercentage}
</td>
<td className="px-3 py-2 whitespace-nowrap text-sm font-medium">
<div className="flex gap-2">
<button
onClick={() => handleViewEvaluationDetail(result)}
className="text-blue-600 hover:text-blue-900"
title="Değerlendirme Detayını Görüntüle"
>
<FaEye className="w-4 h-4" />
</button>
<button
onClick={() => handleEditEvaluationDetail(result)}
className="text-green-600 hover:text-green-900"
title="Değerlendirme Detayını Düzenle"
>
<FaEdit className="w-4 h-4" />
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
)}
</div>
</div>
</div>
{/* Campaign Modal */}
{showCampaignModal && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-2">
<div className="bg-white rounded-lg w-full max-w-lg max-h-[90vh] overflow-y-auto">
<div className="flex justify-between items-center p-2.5 border-b">
<h2 className="text-base font-semibold">
{selectedCampaign ? 'Değerlendirme Düzenle' : 'Yeni Değerlendirme'}
</h2>
<button
onClick={handleCloseModal}
className="p-1.5 text-gray-400 hover:text-gray-600"
>
<FaTimes className="w-4 h-4" />
</button>
</div>
<div className="p-3 space-y-2.5">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Değerlendirme Adı
</label>
<input
type="text"
value={campaignFormData.name}
onChange={(e) =>
setCampaignFormData({
...campaignFormData,
name: e.target.value,
})
}
className="w-full border border-gray-300 rounded-md px-2 py-1 text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">ıklama</label>
<textarea
value={campaignFormData.description}
onChange={(e) =>
setCampaignFormData({
...campaignFormData,
description: e.target.value,
})
}
rows={1}
className="w-full border border-gray-300 rounded-md px-2 py-1 text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Değerlendirme Şablonu
</label>
<select
value={campaignFormData.templateId}
onChange={(e) =>
setCampaignFormData({
...campaignFormData,
templateId: e.target.value,
})
}
className="w-full border border-gray-300 rounded-md px-2 py-1 text-sm"
>
<option value="">Şablon Seçin</option>
{mockEvaluation360Templates.map((template) => (
<option key={template.id} value={template.id}>
{template.name}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Departman</label>
<select
value={campaignFormData.departmentId}
onChange={(e) => handleDepartmentChange(e.target.value)}
className="w-full border border-gray-300 rounded-md px-2 py-1 text-sm"
>
<option value="">Departman Seçin</option>
{mockDepartments.map((department) => (
<option key={department.id} value={department.id}>
{department.name}
</option>
))}
</select>
</div>
{campaignFormData.departmentId && (
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Hedef Personel
</label>
<div className="border border-gray-300 rounded-md p-1.5 max-h-28 overflow-y-auto">
{filteredEmployeesByDepartment.map((employee) => (
<label key={employee.id} className="flex items-center mb-2">
<input
type="checkbox"
checked={campaignFormData.targetEmployees.includes(employee.id)}
onChange={(e) => {
if (e.target.checked) {
setCampaignFormData({
...campaignFormData,
targetEmployees: [...campaignFormData.targetEmployees, employee.id],
})
} else {
setCampaignFormData({
...campaignFormData,
targetEmployees: campaignFormData.targetEmployees.filter(
(id) => id !== employee.id,
),
})
}
}}
className="mr-2"
/>
{employee.firstName} {employee.lastName} -{' '}
{employee.jobPosition?.name || 'Pozisyon Belirtilmemiş'}
</label>
))}
</div>
</div>
)}
<div className="grid grid-cols-2 gap-2.5">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Başlangıç Tarihi
</label>
<input
type="date"
value={campaignFormData.startDate}
onChange={(e) =>
setCampaignFormData({
...campaignFormData,
startDate: e.target.value,
})
}
className="w-full border border-gray-300 rounded-md px-2 py-1 text-sm"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Bitiş Tarihi
</label>
<input
type="date"
value={campaignFormData.endDate}
onChange={(e) =>
setCampaignFormData({
...campaignFormData,
endDate: e.target.value,
})
}
className="w-full border border-gray-300 rounded-md px-2 py-1 text-sm"
/>
</div>
</div>
</div>
<div className="flex justify-end gap-2 p-2.5 border-t">
<button
onClick={handleCloseModal}
className="px-2.5 py-1 text-sm text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200"
>
İptal
</button>
<button
onClick={handleSaveCampaign}
className="flex items-center gap-2 px-2.5 py-1 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700"
>
<FaSave className="w-4 h-4" />
{selectedCampaign ? 'Güncelle' : 'Kaydet'}
</button>
</div>
</div>
</div>
)}
{/* View Modal */}
{showViewModal && selectedCampaign && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-2">
<div className="bg-white rounded-lg w-full max-w-2xl max-h-[90vh] overflow-y-auto">
<div className="flex justify-between items-center p-2.5 border-b">
<h2 className="text-base font-semibold">{selectedCampaign.name}</h2>
<button
onClick={handleCloseModal}
className="p-1.5 text-gray-400 hover:text-gray-600"
>
<FaTimes className="w-4 h-4" />
</button>
</div>
<div className="p-3 space-y-3">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h3 className="text-sm font-medium text-gray-900 mb-2">
Değerlendirme Bilgileri
</h3>
<div className="space-y-2">
<div>
<span className="text-sm font-medium text-gray-600">Adı:</span>
<p className="text-sm text-gray-900">{selectedCampaign.name}</p>
</div>
<div>
<span className="text-sm font-medium text-gray-600">ıklama:</span>
<p className="text-sm text-gray-900">{selectedCampaign.description}</p>
</div>
<div>
<span className="text-sm font-medium text-gray-600">Durum:</span>
<span
className={`ml-2 px-3 py-1 text-xs font-medium rounded-full ${getCampaignStatusColor(
selectedCampaign.status,
)}`}
>
{getCampaignStatusText(selectedCampaign.status)}
</span>
</div>
<div>
<span className="text-sm font-medium text-gray-600">Tarih Aralığı:</span>
<p className="text-sm text-gray-900">
{selectedCampaign.startDate.toLocaleDateString('tr-TR')} -{' '}
{selectedCampaign.endDate.toLocaleDateString('tr-TR')}
</p>
</div>
</div>
</div>
<div>
<h3 className="text-sm font-medium text-gray-900 mb-2">
Katılımcı İstatistikleri
</h3>
<div className="space-y-2">
{(() => {
const participants = getCampaignParticipants(selectedCampaign.id)
const completed = participants.filter(
(p) => p.status === ParticipantStatusEnum.Completed,
)
const started = participants.filter(
(p) => p.status === ParticipantStatusEnum.Started,
)
const invited = participants.filter(
(p) => p.status === ParticipantStatusEnum.Invited,
)
return (
<>
<div className="flex justify-between">
<span className="text-sm text-gray-600">Toplam:</span>
<span className="text-sm font-medium text-gray-900">
{participants.length}
</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-600">Tamamlanan:</span>
<span className="text-sm font-medium text-green-600">
{completed.length}
</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-600">Devam Eden:</span>
<span className="text-sm font-medium text-blue-600">
{started.length}
</span>
</div>
<div className="flex justify-between">
<span className="text-sm text-gray-600">Bekleyen:</span>
<span className="text-sm font-medium text-yellow-600">
{invited.length}
</span>
</div>
</>
)
})()}
</div>
</div>
</div>
<div>
<h3 className="text-sm font-medium text-gray-900 mb-2">Katılımcı Detayları</h3>
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Hedef Çalışan
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Değerlendiren
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Tip
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Durum
</th>
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Tarih
</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{getCampaignParticipants(selectedCampaign.id).map((participant) => {
const targetEmployee = mockEmployees.find(
(emp) => emp.id === participant.evaluatedEmployeeId,
)
const assessorEmployee = mockEmployees.find(
(emp) => emp.id === participant.evaluatorId,
)
return (
<tr key={participant.id}>
<td className="px-3 py-2 whitespace-nowrap text-sm text-gray-900">
{targetEmployee
? `${targetEmployee.firstName} ${targetEmployee.lastName}`
: 'Bilinmiyor'}
</td>
<td className="px-3 py-2 whitespace-nowrap text-sm text-gray-900">
{assessorEmployee
? `${assessorEmployee.firstName} ${assessorEmployee.lastName}`
: 'Bilinmiyor'}
</td>
<td className="px-3 py-2 whitespace-nowrap text-sm text-gray-500">
{getAssessorTypeText(participant.evaluatorType)}
</td>
<td className="px-3 py-2 whitespace-nowrap">
<span
className={`px-2 py-1 text-xs font-medium rounded-full ${getParticipantStatusColor(
participant.status,
)}`}
>
{getParticipantStatusText(participant.status)}
</span>
</td>
<td className="px-3 py-2 whitespace-nowrap text-sm text-gray-500">
{participant.completedDate
? participant.completedDate.toLocaleDateString('tr-TR')
: participant.startedDate
? `Başladı: ${participant.startedDate.toLocaleDateString(
'tr-TR',
)}`
: `Davet: ${participant.invitedDate.toLocaleDateString('tr-TR')}`}
</td>
</tr>
)
})}
</tbody>
</table>
</div>
</div>
</div>
<div className="flex justify-end gap-2 p-2.5 border-t">
<button
onClick={handleCloseModal}
className="px-2.5 py-1 text-sm text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200"
>
Kapat
</button>
<button
onClick={() => {
handleCloseModal()
handleEditCampaign(selectedCampaign)
}}
className="flex items-center gap-2 px-2.5 py-1 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700"
>
<FaEdit className="w-4 h-4" />
Düzenle
</button>
</div>
</div>
</div>
)}
{/* Evaluation Modal */}
{showEvaluationModal && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-2">
<div className="bg-white rounded-lg w-full max-w-lg max-h-[90vh] overflow-y-auto">
<div className="flex justify-between items-center p-2.5 border-b">
<h2 className="text-base font-semibold">
{!currentCampaignForEvaluation
? 'Değerlendirme Yap'
: currentCampaignForEvaluation.name}
</h2>
<button
onClick={handleCloseModal}
className="p-1.5 text-gray-400 hover:text-gray-600"
>
<FaTimes className="w-4 h-4" />
</button>
</div>
<div className="p-3 space-y-2.5">
{!currentCampaignForEvaluation ? (
/* Adım 0: Değerlendirme seçimi */
<div>
<h3 className="text-sm font-medium text-gray-900 mb-2">Değerlendirme Seçin</h3>
<div className="space-y-2">
{mockEvaluation360
.filter((campaign) => campaign.status === CampaignStatusEnum.Active)
.map((campaign) => (
<div
key={campaign.id}
className="border rounded-lg p-2.5 hover:bg-gray-50 cursor-pointer"
onClick={() => setCurrentCampaignForEvaluation(campaign)}
>
<div className="flex justify-between items-center">
<div>
<h4 className="font-medium text-gray-900">{campaign.name}</h4>
<p className="text-gray-600">{campaign.description}</p>
<div className="flex items-center gap-2 mt-2">
<span
className={`inline-block px-2 py-1 text-xs rounded-full ${getCampaignStatusColor(
campaign.status,
)}`}
>
{getCampaignStatusText(campaign.status)}
</span>
<span className="text-xs text-gray-500">
{campaign.startDate.toLocaleDateString()} -{' '}
{campaign.endDate.toLocaleDateString()}
</span>
</div>
</div>
<FaPlay className="w-4 h-4 text-gray-400" />
</div>
</div>
))}
</div>
{mockEvaluation360.filter(
(campaign) => campaign.status === CampaignStatusEnum.Active,
).length === 0 && (
<div className="text-center py-8 text-gray-500">
<FaPoll className="w-12 h-12 mx-auto mb-3 text-gray-300" />
<p>Aktif değerlendirme bulunmuyor</p>
</div>
)}
</div>
) : !evaluationTarget ? (
/* Adım 1: Değerlendirilecek kişi seçimi */
<div>
<div className="mb-4">
<button
onClick={() => setCurrentCampaignForEvaluation(null)}
className="text-blue-600 hover:text-blue-800 text-sm"
>
Değerlendirme Seçimine Dön
</button>
</div>
<h3 className="text-sm font-medium text-gray-900 mb-2">
1. Adım: Değerlendirilecek Kişiyi Seçin
</h3>
<div className="bg-blue-50 p-2.5 rounded-lg mb-3">
<p className="text-sm text-blue-800">
<strong>Seçili Değerlendirme:</strong> {currentCampaignForEvaluation.name}
</p>
</div>
<div className="space-y-3">
{mockEmployees
.filter((emp) =>
currentCampaignForEvaluation.targetEmployees.includes(emp.id),
)
.map((employee) => (
<div
key={employee.id}
className="border rounded-lg p-2.5 hover:bg-gray-50 cursor-pointer"
onClick={() => setEvaluationTarget(employee.id)}
>
<div className="flex justify-between items-center">
<div>
<h4 className="font-medium text-gray-900">{employee.fullName}</h4>
<p className="text-gray-600">{employee.jobPosition?.name}</p>
<p className="text-gray-600">
{mockDepartments.find((d) => d.id === employee.departmentId)?.name}
</p>
</div>
<FaUsers className="w-4 h-4 text-gray-400" />
</div>
</div>
))}
</div>
{mockEmployees.filter((emp) =>
currentCampaignForEvaluation.targetEmployees.includes(emp.id),
).length === 0 && (
<div className="text-center py-8 text-gray-500">
<FaUsers className="w-12 h-12 mx-auto mb-3 text-gray-300" />
<p>Bu değerlendirmede hedef çalışan bulunmuyor</p>
</div>
)}
</div>
) : !selectedAssessorType ? (
/* Adım 2a: Değerlendirici Tipi Seçimi */
<div>
<div className="mb-4">
<button
onClick={() => setEvaluationTarget('')}
className="text-blue-600 hover:text-blue-800 text-sm"
>
Geri Dön
</button>
</div>
<h3 className="text-sm font-medium text-gray-900 mb-2">
2. Adım: Değerlendirici Tipi Seçin
</h3>
<div className="bg-blue-50 p-2.5 rounded-lg mb-3">
<p className="text-sm text-blue-800">
<strong>Değerlendirilecek:</strong>{' '}
{mockEmployees.find((e) => e.id === evaluationTarget)?.fullName}
</p>
</div>
{/* Değerlendirici tipi seçimi */}
<div className="space-y-2">
{getAllowedAssessorTypes().map((assessorType) => (
<div
key={assessorType}
className="border rounded-lg p-2.5 hover:bg-gray-50 cursor-pointer"
onClick={() => {
setSelectedAssessorType(assessorType)
setEvaluatorSearchTerm('')
}}
>
<div className="flex justify-between items-center">
<div>
<h4 className="font-medium text-gray-900">
{getAssessorTypeText(assessorType)}
</h4>
<p className="text-gray-600">
{getAssessorTypeDescription(assessorType)}
</p>
{getEvaluatorsByType(evaluationTarget, assessorType).length > 0 && (
<span className="inline-block mt-1 px-2 py-1 text-xs rounded-full bg-blue-100 text-blue-800">
{getEvaluatorsByType(evaluationTarget, assessorType).length} seçenek
mevcut
</span>
)}
</div>
<FaUsers className="w-4 h-4 text-gray-400" />
</div>
</div>
))}
</div>
</div>
) : !evaluationEvaluator ? (
/* Adım 2b: Belirli tip değerlendirici seçimi */
<div>
<div className="mb-4">
<button
onClick={() => {
setSelectedAssessorType(null)
setEvaluationEvaluator('')
setSelectedCustomerId('')
setExternalEvaluatorName('')
setExternalEvaluatorEmail('')
setEvaluatorSearchTerm('')
}}
className="text-blue-600 hover:text-blue-800 text-sm"
>
Geri Dön
</button>
</div>
<h3 className="text-sm font-medium text-gray-900 mb-2">
2. Adım: {getAssessorTypeText(selectedAssessorType)} Seçin
</h3>
<div className="bg-blue-50 p-2.5 rounded-lg mb-3">
<p className="text-sm text-blue-800">
<strong>Değerlendirilecek:</strong>{' '}
{mockEmployees.find((e) => e.id === evaluationTarget)?.fullName}
<br />
<strong>Değerlendirici Tipi:</strong>{' '}
{getAssessorTypeText(selectedAssessorType)}
</p>
</div>
{selectedAssessorType === AssessorTypeEnum.External ? (
/* Dış değerlendirici için form */
<div className="space-y-3">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Değerlendirici Adı *
</label>
<input
type="text"
value={externalEvaluatorName}
onChange={(e) => setExternalEvaluatorName(e.target.value)}
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm"
placeholder="Değerlendirici adını girin"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
E-posta Adresi *
</label>
<input
type="email"
value={externalEvaluatorEmail}
onChange={(e) => setExternalEvaluatorEmail(e.target.value)}
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm"
placeholder="E-posta adresini girin"
/>
</div>
{externalEvaluatorName && externalEvaluatorEmail && (
<button
onClick={() => setEvaluationEvaluator('external')}
className="w-full bg-green-600 text-white py-2 px-4 rounded-md hover:bg-green-700 text-sm"
>
Dış Değerlendiriciyi Seç
</button>
)}
</div>
) : selectedAssessorType === AssessorTypeEnum.Customer ? (
/* Müşteri seçimi */
<div className="space-y-2">
{/* Arama kutusu */}
<div>
<input
type="text"
value={evaluatorSearchTerm}
onChange={(e) => setEvaluatorSearchTerm(e.target.value)}
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm"
placeholder="Müşteri adında ara..."
/>
</div>
{getEvaluatorsByType(evaluationTarget, selectedAssessorType)
.filter((evaluator) =>
evaluator.name.toLowerCase().includes(evaluatorSearchTerm.toLowerCase()),
)
.map((evaluator) => (
<div
key={evaluator.id}
className="border rounded-lg p-2.5 hover:bg-gray-50 cursor-pointer"
onClick={() => {
setSelectedCustomerId(evaluator.id)
setEvaluationEvaluator(evaluator.id)
}}
>
<div className="flex justify-between items-center">
<div>
<h4 className="font-medium text-gray-900">{evaluator.name}</h4>
<p className="text-gray-600">{evaluator.title}</p>
<span className="inline-block mt-1 px-2 py-1 text-xs rounded-full bg-purple-100 text-purple-800">
{evaluator.department}
</span>
</div>
<FaUsers className="w-4 h-4 text-gray-400" />
</div>
</div>
))}
</div>
) : (
/* Diğer tipler için çalışan seçimi */
<div className="space-y-2">
{/* Arama kutusu */}
<div>
<input
type="text"
value={evaluatorSearchTerm}
onChange={(e) => setEvaluatorSearchTerm(e.target.value)}
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm"
placeholder="Çalışan adında ara..."
/>
</div>
{getEvaluatorsByType(evaluationTarget, selectedAssessorType)
.filter((evaluator) =>
evaluator.name.toLowerCase().includes(evaluatorSearchTerm.toLowerCase()),
)
.map((evaluator) => (
<div
key={evaluator.id}
className="border rounded-lg p-2.5 hover:bg-gray-50 cursor-pointer"
onClick={() => setEvaluationEvaluator(evaluator.id)}
>
<div className="flex justify-between items-center">
<div>
<h4 className="font-medium text-gray-900">{evaluator.name}</h4>
<p className="text-gray-600">{evaluator.title}</p>
<span className="inline-block mt-1 px-2 py-1 text-xs rounded-full bg-purple-100 text-purple-800">
{evaluator.department}
</span>
</div>
<FaUsers className="w-4 h-4 text-gray-400" />
</div>
</div>
))}
{getEvaluatorsByType(evaluationTarget, selectedAssessorType).length === 0 && (
<div className="text-center py-8 text-gray-500">
<FaUsers className="w-12 h-12 mx-auto mb-3 text-gray-300" />
<p>Bu kategoride değerlendirici bulunmuyor</p>
</div>
)}
</div>
)}
</div>
) : (
/* Adım 3: Değerlendirme formu */
<div>
<div className="mb-4">
<button
onClick={() => {
setSelectedAssessorType(null)
setEvaluationEvaluator('')
setSelectedCustomerId('')
setExternalEvaluatorName('')
setExternalEvaluatorEmail('')
setEvaluatorSearchTerm('')
}}
className="text-blue-600 hover:text-blue-800 text-sm"
>
Geri Dön
</button>
</div>
<h3 className="text-sm font-medium text-gray-900 mb-2">
3. Adım: Değerlendirme Formu
</h3>
<div className="bg-green-50 p-2.5 rounded-lg mb-3">
<p className="text-sm text-green-800">
<strong>Değerlendirilen:</strong>{' '}
{mockEmployees.find((e) => e.id === evaluationTarget)?.fullName}
<br />
<strong>Değerlendiren:</strong> {getEvaluatorInfo()}
</p>
</div>
{/* Burada şablonun sorularını göstereceğiz */}
<div className="space-y-3">
{currentCampaignForEvaluation &&
mockEvaluation360Templates
.find((t) => t.id === currentCampaignForEvaluation.templateId)
?.questionGroups.map((group) => (
<div key={group.id} className="border rounded-lg p-2.5">
<h4 className="font-medium text-gray-900 mb-2">{group.groupName}</h4>
<p className="text-sm text-gray-600 mb-3">{group.description}</p>
<div className="space-y-3">
{group.questions.map((question, qIndex) => (
<div key={question.id} className="bg-gray-50 p-2.5 rounded">
<p className="font-medium text-gray-800 mb-3">
{qIndex + 1}. {question.questionText}
{question.isRequired && (
<span className="text-red-500 ml-1">*</span>
)}
</p>
{/* Soru tipine göre input alanları */}
{question.questionType === QuestionTypeEnum.Rating && (
<div className="space-y-2">
<div className="flex justify-around items-center">
{Array.from(
{
length:
(question.maxRating || 5) -
(question.minRating || 1) +
1,
},
(_, i) => {
const value = (question.minRating || 1) + i
return (
<label
key={value}
className="flex flex-col items-center cursor-pointer"
>
<input
type="radio"
name={`question-${question.id}`}
value={value}
checked={
evaluationResponses[question.id] === value
}
onChange={(e) =>
handleResponseChange(
question.id,
Number(e.target.value),
)
}
className="mb-1"
/>
<span className="text-xs text-gray-600">
{question.ratingLabels?.[i] || value}
</span>
</label>
)
},
)}
</div>
</div>
)}
{question.questionType === QuestionTypeEnum.Text && (
<textarea
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm"
rows={3}
placeholder="Yorumunuzu yazın..."
value={evaluationResponses[question.id] || ''}
onChange={(e) =>
handleResponseChange(question.id, e.target.value)
}
/>
)}
{question.questionType === QuestionTypeEnum.YesNo && (
<div className="flex gap-4">
<label className="flex items-center cursor-pointer">
<input
type="radio"
name={`question-${question.id}`}
value="yes"
checked={evaluationResponses[question.id] === 'yes'}
onChange={(e) =>
handleResponseChange(question.id, e.target.value)
}
className="mr-2"
/>
Evet
</label>
<label className="flex items-center cursor-pointer">
<input
type="radio"
name={`question-${question.id}`}
value="no"
checked={evaluationResponses[question.id] === 'no'}
onChange={(e) =>
handleResponseChange(question.id, e.target.value)
}
className="mr-2"
/>
Hayır
</label>
</div>
)}
{question.questionType === QuestionTypeEnum.MultipleChoice && (
<div className="space-y-2">
{question.options?.map((option) => (
<label
key={option.id}
className="flex items-center cursor-pointer"
>
<input
type="radio"
name={`question-${question.id}`}
value={option.value}
checked={
evaluationResponses[question.id] === option.value
}
onChange={(e) =>
handleResponseChange(
question.id,
Number(e.target.value),
)
}
className="mr-2"
/>
{option.optionText}
</label>
))}
</div>
)}
</div>
))}
</div>
</div>
))}
</div>
</div>
)}
</div>
<div className="flex justify-end gap-2 p-2.5 border-t">
<button
onClick={handleCloseModal}
className="px-2.5 py-1 text-sm text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200"
>
İptal
</button>
{evaluationTarget && evaluationEvaluator && (
<button
onClick={handleSaveEvaluation}
className="flex items-center gap-2 px-2.5 py-1 text-sm bg-green-600 text-white rounded-md hover:bg-green-700"
>
<FaSave className="w-4 h-4" />
Değerlendirmeyi Kaydet
</button>
)}
</div>
</div>
</div>
)}
{/* Result Detail Modal */}
{showResultDetailModal && selectedResult && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-2">
<div className="bg-white rounded-lg w-full max-w-2xl max-h-[90vh] overflow-y-auto">
<div className="flex justify-between items-center p-2.5 border-b">
<h2 className="text-base font-semibold">Değerlendirme Detayı</h2>
<button
onClick={handleCloseModal}
className="p-1.5 text-gray-400 hover:text-gray-600"
>
<FaTimes className="w-4 h-4" />
</button>
</div>
<div className="p-3 space-y-2.5">
{/* Genel Bilgiler */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<div className="bg-blue-50 p-4 rounded-lg">
<h3 className="font-medium text-blue-800 mb-2 text-sm">
Değerlendirme Bilgileri
</h3>
<div className="space-y-1.5">
<div>
<span className="text-sm text-blue-700 font-medium">Kampanya: </span>
<span className="text-sm text-blue-800">{selectedResult.campaignName}</span>
</div>
<div>
<span className="text-sm text-blue-700 font-medium">Değerlendirilen: </span>
<span className="text-sm text-blue-800">
{selectedResult.evaluatedEmployeeName}
</span>
</div>
<div>
<span className="text-sm text-blue-700 font-medium">Değerlendiren: </span>
<span className="text-sm text-blue-800">{selectedResult.evaluatorName}</span>
</div>
<div>
<span className="text-sm text-blue-700 font-medium">
Değerlendiren Tipi:{' '}
</span>
<span className="text-sm text-blue-800">
{getAssessorTypeText(selectedResult.evaluatorType)}
</span>
</div>
</div>
</div>
<div className="bg-green-50 p-4 rounded-lg">
<h3 className="font-medium text-green-800 mb-2 text-sm">Sonuç Bilgileri</h3>
<div className="space-y-1.5">
<div>
<span className="text-sm text-green-700 font-medium">Durum: </span>
<span
className={`text-sm px-2 py-0.5 rounded-full ${getParticipantStatusColor(
selectedResult.status,
)}`}
>
{getParticipantStatusText(selectedResult.status)}
</span>
</div>
<div>
<span className="text-sm text-green-700 font-medium">Toplam Puan: </span>
<span className="text-sm text-green-800 font-bold">
{selectedResult.overallScore}/100
</span>
</div>
<div>
<span className="text-sm text-green-700 font-medium">Yüzde: </span>
<span className="text-sm text-green-800 font-bold">
%{selectedResult.scorePercentage}
</span>
</div>
{selectedResult.completedDate && (
<div>
<span className="text-sm text-green-700 font-medium">
Tamamlanma Tarihi:{' '}
</span>
<span className="text-sm text-green-800">
{new Date(selectedResult.completedDate).toLocaleDateString('tr-TR')}
</span>
</div>
)}
</div>
</div>
</div>
{/* Detaylı Sonuçlar */}
<div className="border rounded-lg p-3">
<h3 className="font-medium text-gray-900 mb-2 text-sm">Detaylı Sonuçlar</h3>
{(() => {
// Seçili sonucu mockEvaluation360Results'tan bul
const evaluationResult = mockEvaluation360Results.find(
(r) => r.id === selectedResult.resultId,
)
if (!evaluationResult) {
return (
<div className="text-center py-8 text-gray-500">
<FaChartBar className="w-12 h-12 mx-auto mb-3 text-gray-300" />
<p>Sonuç verisi bulunamadı</p>
</div>
)
}
return (
<div className="space-y-2.5">
{/* Soru Cevapları */}
{(() => {
const campaign = mockEvaluation360.find(
(c) => c.id === selectedResult.campaignId,
)
const template = campaign
? mockEvaluation360Templates.find((t) => t.id === campaign.templateId)
: null
if (template) {
return (
<div>
<h4 className="font-medium text-gray-800 mb-2 text-sm">
📝 Soru Cevapları
</h4>
<div className="space-y-3">
{template.questionGroups.map((group) => (
<div key={group.id} className="bg-gray-50 p-2.5 rounded-lg">
<div className="mb-3">
<h5 className="font-medium text-gray-800">
{group.groupName}
</h5>
<p className="text-gray-600">{group.description}</p>
</div>
<div className="space-y-2.5">
{group.questions.map((question, qIndex) => {
const response = evaluationResult.participants
.flatMap((p) => p.responses)
.find((r) => r.questionId === question.id)
if (!response) return null
return (
<div
key={question.id}
className="bg-white p-1.5 rounded border-l-4 border-blue-200"
>
<div className="mb-2">
<span className="text-sm font-medium text-gray-800">
S{qIndex + 1}: {question.questionText}
</span>
</div>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<span className="text-sm text-gray-600">
Cevap:
</span>
<span className="px-2 py-1 bg-blue-100 text-blue-800 rounded text-sm font-medium">
{(() => {
if (
question.questionType ===
QuestionTypeEnum.Rating
) {
const ratingIndex =
Number(response.responseValue) -
(question.minRating || 1)
const label =
question.ratingLabels?.[ratingIndex]
return label
? `${response.responseValue} - ${label}`
: response.responseValue
} else if (
question.questionType ===
QuestionTypeEnum.YesNo
) {
return response.responseValue === 'yes'
? 'Evet'
: 'Hayır'
} else if (
question.questionType ===
QuestionTypeEnum.MultipleChoice
) {
const option = question.options?.find(
(o) =>
o.value ===
Number(response.responseValue),
)
return option
? option.optionText
: response.responseValue
} else {
return response.responseValue
}
})()}
</span>
</div>
<div className="flex items-center gap-2">
<span className="text-xs text-gray-500">Puan:</span>
<span className="px-2 py-1 bg-green-100 text-green-800 rounded text-sm font-bold">
{response.score}
</span>
</div>
</div>
{response.responseText && (
<div className="mt-2 p-2 bg-gray-100 rounded">
<span className="text-xs text-gray-600">
Detay:{' '}
</span>
<span className="text-sm text-gray-700">
{response.responseText}
</span>
</div>
)}
</div>
)
})}
</div>
</div>
))}
</div>
</div>
)
}
return null
})()}
{/* Grup Bazlı Puanlar */}
<div>
<h4 className="font-medium text-gray-800 mb-2 text-sm">
📊 Grup Bazlı Puanlar
</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{evaluationResult.groupScores.map((groupScore) => (
<div key={groupScore.groupId} className="bg-gray-50 p-2.5 rounded-lg">
<div className="flex justify-between items-center mb-2">
<h5 className="font-medium text-gray-700">
{groupScore.groupName}
</h5>
<span className="text-lg font-bold text-blue-600">
{groupScore.score}/{groupScore.maxScore}
</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2 mb-2">
<div
className="bg-blue-600 h-2 rounded-full"
style={{ width: `${groupScore.percentage}%` }}
></div>
</div>
<div className="flex justify-between text-sm text-gray-600">
<span>%{Math.round(groupScore.percentage)}</span>
<span>{groupScore.responseCount} cevap</span>
</div>
</div>
))}
</div>
</div>
{/* Değerlendirici Tipi Bazlı Puanlar */}
<div>
<h4 className="font-medium text-gray-800 mb-2 text-sm">
👥 Değerlendirici Tipi Bazlı Puanlar
</h4>
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
{evaluationResult.assessorTypeScores.map((assessorScore, index) => (
<div key={index} className="bg-blue-50 p-2.5 rounded-lg text-center">
<div className="text-sm text-blue-700 font-medium mb-1">
{getAssessorTypeText(assessorScore.assessorType)}
</div>
<div className="text-2xl font-bold text-blue-800 mb-1">
%{Math.round(assessorScore.percentage)}
</div>
<div className="text-xs text-blue-600">
{assessorScore.averageScore}/{assessorScore.maxScore} puan
</div>
<div className="text-xs text-blue-500">
{assessorScore.assessorCount} değerlendirici
</div>
</div>
))}
</div>
</div>
{/* Güçlü Yönler */}
<div>
<h4 className="font-medium text-gray-800 mb-2 text-sm">💪 Güçlü Yönler</h4>
<div className="bg-green-50 p-2.5 rounded-lg">
{evaluationResult.strengths.length > 0 ? (
<ul className="list-disc list-inside space-y-1">
{evaluationResult.strengths.map((strength, index) => (
<li key={index} className="text-green-800">
{strength}
</li>
))}
</ul>
) : (
<p className="text-green-700 italic">
Güçlü yönler henüz analiz edilmedi
</p>
)}
</div>
</div>
{/* Gelişim Alanları */}
<div>
<h4 className="font-medium text-gray-800 mb-2 text-sm">
📈 Gelişim Alanları
</h4>
<div className="bg-amber-50 p-2.5 rounded-lg">
{evaluationResult.developmentAreas.length > 0 ? (
<ul className="list-disc list-inside space-y-1">
{evaluationResult.developmentAreas.map((area, index) => (
<li key={index} className="text-amber-800">
{area}
</li>
))}
</ul>
) : (
<p className="text-amber-700 italic">
Gelişim alanları henüz analiz edilmedi
</p>
)}
</div>
</div>
{/* Aksiyon Planı */}
<div>
<h4 className="font-medium text-gray-800 mb-2 text-sm">🎯 Aksiyon Planı</h4>
<div className="bg-purple-50 p-2.5 rounded-lg">
{evaluationResult.actionPlan.length > 0 ? (
<ul className="list-decimal list-inside space-y-1">
{evaluationResult.actionPlan.map((action, index) => (
<li key={index} className="text-purple-800">
{action}
</li>
))}
</ul>
) : (
<p className="text-purple-700 italic">
Aksiyon planı henüz oluşturulmadı
</p>
)}
</div>
</div>
{/* Yorumlar */}
{(evaluationResult.managerComments || evaluationResult.hrComments) && (
<div>
<h4 className="font-medium text-gray-800 mb-2 text-sm">💬 Yorumlar</h4>
<div className="space-y-2">
{evaluationResult.managerComments && (
<div className="bg-blue-50 p-2.5 rounded-lg">
<h5 className="font-medium text-blue-800 mb-2">Yönetici Yorumu</h5>
<p className="text-blue-700">{evaluationResult.managerComments}</p>
</div>
)}
{evaluationResult.hrComments && (
<div className="bg-indigo-50 p-2.5 rounded-lg">
<h5 className="font-medium text-indigo-800 mb-2">İK Yorumu</h5>
<p className="text-indigo-700">{evaluationResult.hrComments}</p>
</div>
)}
</div>
</div>
)}
</div>
)
})()}
</div>
</div>
<div className="flex justify-end gap-2 p-2.5 border-t">
<button
onClick={handleCloseModal}
className="px-2.5 py-1 text-sm text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200"
>
Kapat
</button>
<button
onClick={() => {
handleCloseModal()
handleEditEvaluationDetail(selectedResult)
}}
className="flex items-center gap-2 px-2.5 py-1 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-700"
>
<FaEdit className="w-4 h-4" />
Düzenle
</button>
</div>
</div>
</div>
)}
{/* Result Edit Modal */}
{showResultEditModal && selectedResult && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-2">
<div className="bg-white rounded-lg w-full max-w-4xl max-h-[90vh] overflow-y-auto">
<div className="flex justify-between items-center p-2.5 border-b">
<h2 className="text-base font-semibold">Değerlendirme Düzenle</h2>
<button
onClick={handleCloseModal}
className="p-1.5 text-gray-400 hover:text-gray-600"
>
<FaTimes className="w-4 h-4" />
</button>
</div>
<div className="p-3 space-y-2.5">
<div className="bg-amber-50 p-2.5 rounded-lg">
<h3 className="font-medium text-amber-800 mb-2 text-sm">Değerlendirme Bilgileri</h3>
<div className="grid grid-cols-2 gap-4">
<div>
<span className="text-sm text-amber-700 font-medium">Kampanya: </span>
<span className="text-sm text-amber-800">{selectedResult.campaignName}</span>
</div>
<div>
<span className="text-sm text-amber-700 font-medium">Değerlendirilen: </span>
<span className="text-sm text-amber-800">
{selectedResult.evaluatedEmployeeName}
</span>
</div>
<div>
<span className="text-sm text-amber-700 font-medium">Değerlendiren: </span>
<span className="text-sm text-amber-800">{selectedResult.evaluatorName}</span>
</div>
<div>
<span className="text-sm text-amber-700 font-medium">Değerlendiren Tipi: </span>
<span className="text-sm text-amber-800">
{getAssessorTypeText(selectedResult.evaluatorType)}
</span>
</div>
</div>
</div>
{/* Soru Grupları ve Cevaplar */}
{(() => {
const evaluationResult = mockEvaluation360Results.find(
(r) => r.id === selectedResult.resultId,
)
const campaign = mockEvaluation360.find((c) => c.id === selectedResult.campaignId)
const template = campaign
? mockEvaluation360Templates.find((t) => t.id === campaign.templateId)
: null
if (!evaluationResult || !template) {
return (
<div className="text-center py-8 text-gray-500">
<p>Template verisi bulunamadı</p>
</div>
)
}
return (
<div className="space-y-3">
<h3 className="text-sm font-medium text-gray-900">Soru Grupları ve Cevaplar</h3>
{template.questionGroups.map((group) => (
<div key={group.id} className="border rounded-lg p-2">
<div className="mb-3">
<h4 className="font-medium text-gray-900 text-sm">{group.groupName}</h4>
<p className="text-gray-600">{group.description}</p>
<div className="flex items-center gap-2 mt-2">
<span className="text-xs text-gray-500">ırlık: %{group.weight}</span>
<span className="text-xs text-gray-500"></span>
<span className="text-xs text-gray-500">
{group.questions.length} soru
</span>
</div>
</div>
<div className="space-y-2.5">
{group.questions.map((question, qIndex) => {
const currentResponse = evaluationResult.participants
.flatMap((p) => p.responses)
.find((r) => r.questionId === question.id)
const editValue =
editResponses[question.id] !== undefined
? editResponses[question.id]
: currentResponse?.responseValue
return (
<div key={question.id} className="bg-gray-50 p-2.5 rounded-lg">
<p className="font-medium text-gray-800 mb-3">
{qIndex + 1}. {question.questionText}
{question.isRequired && (
<span className="text-red-500 ml-1">*</span>
)}
</p>
{currentResponse && (
<div className="mb-2 p-1.5 bg-blue-50 rounded">
<span className="text-xs text-blue-700 font-medium">
Mevcut Cevap:{' '}
</span>
<span className="text-xs text-blue-800">
{typeof currentResponse.responseValue === 'string'
? currentResponse.responseValue
: `${currentResponse.responseValue} puan`}
</span>
<span className="text-xs text-blue-600 ml-2">
(Puan: {currentResponse.score})
</span>
</div>
)}
{/* Soru tipine göre düzenleme alanları */}
{question.questionType === QuestionTypeEnum.Rating && (
<div className="space-y-2">
<label className="text-sm text-gray-700 font-medium">
Yeni Puan:
</label>
<div className="flex gap-2.5">
{Array.from(
{
length:
(question.maxRating || 5) -
(question.minRating || 1) +
1,
},
(_, i) => {
const value = (question.minRating || 1) + i
return (
<label
key={value}
className="flex flex-col items-center cursor-pointer"
>
<input
type="radio"
name={`edit-question-${question.id}`}
value={value}
checked={editValue === value}
onChange={(e) =>
handleEditResponseChange(
question.id,
Number(e.target.value),
)
}
className="mb-1"
/>
<span className="text-xs text-gray-600">
{question.ratingLabels?.[i] || value}
</span>
</label>
)
},
)}
</div>
</div>
)}
{question.questionType === QuestionTypeEnum.Text && (
<div>
<label className="block text-sm text-gray-700 font-medium mb-2">
Yeni Cevap:
</label>
<textarea
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm"
rows={3}
placeholder="Yeni cevabı yazın..."
value={editValue || ''}
onChange={(e) =>
handleEditResponseChange(question.id, e.target.value)
}
/>
</div>
)}
{question.questionType === QuestionTypeEnum.YesNo && (
<div>
<label className="block text-sm text-gray-700 font-medium mb-2">
Yeni Cevap:
</label>
<div className="flex gap-4">
<label className="flex items-center cursor-pointer">
<input
type="radio"
name={`edit-question-${question.id}`}
value="yes"
checked={editValue === 'yes'}
onChange={(e) =>
handleEditResponseChange(question.id, e.target.value)
}
className="mr-2"
/>
Evet
</label>
<label className="flex items-center cursor-pointer">
<input
type="radio"
name={`edit-question-${question.id}`}
value="no"
checked={editValue === 'no'}
onChange={(e) =>
handleEditResponseChange(question.id, e.target.value)
}
className="mr-2"
/>
Hayır
</label>
</div>
</div>
)}
{question.questionType === QuestionTypeEnum.MultipleChoice && (
<div>
<label className="block text-sm text-gray-700 font-medium mb-2">
Yeni Seçim:
</label>
<div className="space-y-2">
{question.options?.map((option) => (
<label
key={option.id}
className="flex items-center cursor-pointer"
>
<input
type="radio"
name={`edit-question-${question.id}`}
value={option.value}
checked={editValue === option.value}
onChange={(e) =>
handleEditResponseChange(
question.id,
Number(e.target.value),
)
}
className="mr-2"
/>
{option.optionText}
</label>
))}
</div>
</div>
)}
</div>
)
})}
</div>
</div>
))}
</div>
)
})()}
{/* Yorumlar ve Durum */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Yönetici Yorumları
</label>
<textarea
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm"
rows={4}
placeholder="Yönetici yorumlarını buraya yazın..."
value={editManagerComments}
onChange={(e) => setEditManagerComments(e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
İK Yorumları
</label>
<textarea
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm"
rows={4}
placeholder="İK yorumlarını buraya yazın..."
value={editHrComments}
onChange={(e) => setEditHrComments(e.target.value)}
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Sonuç Durumu</label>
<select
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm"
value={editResultStatus}
onChange={(e) => setEditResultStatus(e.target.value)}
>
<option value="PENDING">Beklemede</option>
<option value="IN_REVIEW">İncelemede</option>
<option value="APPROVED">Onaylandı</option>
<option value="PUBLISHED">Yayınlandı</option>
</select>
</div>
{/* Mevcut Puan Bilgileri */}
<div className="border rounded-lg p-3">
<h4 className="font-medium text-gray-900 mb-2 text-sm">Mevcut Puan Bilgileri</h4>
<div className="grid grid-cols-2 gap-3">
<div className="text-center p-4 bg-blue-50 rounded-lg">
<div className="text-2xl font-bold text-blue-600">
{selectedResult.overallScore}
</div>
<div className="text-sm text-blue-700">Toplam Puan</div>
</div>
<div className="text-center p-4 bg-green-50 rounded-lg">
<div className="text-2xl font-bold text-green-600">
%{selectedResult.scorePercentage}
</div>
<div className="text-sm text-green-700">Başarı Yüzdesi</div>
</div>
</div>
</div>
</div>
<div className="flex justify-end gap-2 p-2.5 border-t">
<button
onClick={handleCloseModal}
className="px-2.5 py-1 text-sm text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200"
>
İptal
</button>
<button
onClick={() => {
console.log('Güncellenen cevaplar:', editResponses)
console.log('Yönetici yorumları:', editManagerComments)
console.log('İK yorumları:', editHrComments)
console.log('Durum:', editResultStatus)
alert('Değerlendirme güncellendi!')
handleCloseModal()
}}
className="flex items-center gap-2 px-2.5 py-1 text-sm bg-green-600 text-white rounded-md hover:bg-green-700"
>
<FaSave className="w-4 h-4" />
Kaydet
</button>
</div>
</div>
</div>
)}
</Container>
)
}
export default Degree360Evaluation