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

2667 lines
119 KiB
TypeScript
Raw Normal View History

2025-09-15 19:46:52 +00:00
import React, { useState } from 'react'
2025-09-15 09:31:47 +00:00
import {
FaUsers,
FaEye,
FaEdit,
FaPlus,
FaChartBar,
FaTimes,
FaSave,
FaPlay,
FaPoll,
2025-09-15 19:46:52 +00:00
} from 'react-icons/fa'
2025-09-15 09:31:47 +00:00
import {
HrEvaluation360,
CampaignStatusEnum,
AssessorTypeEnum,
ParticipantStatusEnum,
QuestionTypeEnum,
ResultStatusEnum,
HrEvaluation360Result,
HrGroupScore,
HrAssessorTypeScore,
2025-09-15 19:46:52 +00:00
} 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'
2025-09-15 09:31:47 +00:00
import {
getAssessorTypeDescription,
getAssessorTypeText,
getParticipantStatusColor,
getParticipantStatusText,
getCampaignStatusColor,
getCampaignStatusText,
2025-09-15 19:46:52 +00:00
} from '../../../utils/erp'
import { Container } from '@/components/shared'
2025-09-15 09:31:47 +00:00
const Degree360Evaluation: React.FC = () => {
2025-09-15 19:46:52 +00:00
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')
2025-09-15 09:31:47 +00:00
// Results tab filters
2025-09-15 19:46:52 +00:00
const [selectedResultsStatus, setSelectedResultsStatus] = useState<string>('all')
const [selectedResultsEmployee, setSelectedResultsEmployee] = useState<string>('all')
const [selectedResultsDepartment, setSelectedResultsDepartment] = useState<string>('all')
const [selectedResultsCampaign, setSelectedResultsCampaign] = useState<string>('all')
2025-09-15 09:31:47 +00:00
// Modal states
2025-09-15 19:46:52 +00:00
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)
2025-09-15 09:31:47 +00:00
const [selectedResult, setSelectedResult] = useState<{
2025-09-15 19:46:52 +00:00
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)
2025-09-15 09:31:47 +00:00
// Evaluation states
2025-09-15 19:46:52 +00:00
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>('')
2025-09-15 09:31:47 +00:00
const [currentCampaignForEvaluation, setCurrentCampaignForEvaluation] =
2025-09-15 19:46:52 +00:00
useState<HrEvaluation360 | null>(null)
2025-09-15 09:31:47 +00:00
// Evaluation responses state
2025-09-15 19:46:52 +00:00
const [evaluationResponses, setEvaluationResponses] = useState<Record<string, string | number>>(
{},
)
2025-09-15 09:31:47 +00:00
// Edit modal states
2025-09-15 19:46:52 +00:00
const [editResponses, setEditResponses] = useState<Record<string, string | number>>({})
const [editManagerComments, setEditManagerComments] = useState<string>('')
const [editHrComments, setEditHrComments] = useState<string>('')
const [editResultStatus, setEditResultStatus] = useState<string>('PENDING')
2025-09-15 09:31:47 +00:00
// Form states
const [campaignFormData, setCampaignFormData] = useState({
2025-09-15 19:46:52 +00:00
name: '',
description: '',
templateId: '',
departmentId: '',
2025-09-15 09:31:47 +00:00
targetEmployees: [] as string[],
2025-09-15 19:46:52 +00:00
startDate: '',
endDate: '',
})
2025-09-15 09:31:47 +00:00
// Event handlers
const handleCloseModal = () => {
2025-09-15 19:46:52 +00:00
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')
2025-09-15 09:31:47 +00:00
setCampaignFormData({
2025-09-15 19:46:52 +00:00
name: '',
description: '',
templateId: '',
departmentId: '',
2025-09-15 09:31:47 +00:00
targetEmployees: [],
2025-09-15 19:46:52 +00:00
startDate: '',
endDate: '',
})
}
2025-09-15 09:31:47 +00:00
// Response handling functions
const handleResponseChange = (questionId: string, value: string | number) => {
setEvaluationResponses((prev) => ({
...prev,
[questionId]: value,
2025-09-15 19:46:52 +00:00
}))
}
2025-09-15 09:31:47 +00:00
// Edit response handling function
2025-09-15 19:46:52 +00:00
const handleEditResponseChange = (questionId: string, value: string | number) => {
2025-09-15 09:31:47 +00:00
setEditResponses((prev) => ({
...prev,
[questionId]: value,
2025-09-15 19:46:52 +00:00
}))
}
2025-09-15 09:31:47 +00:00
// Evaluation kaydetme fonksiyonu
const handleSaveEvaluation = () => {
2025-09-15 19:46:52 +00:00
if (!currentCampaignForEvaluation || !evaluationTarget || !evaluationEvaluator) {
alert('Tüm alanları doldurun!')
return
2025-09-15 09:31:47 +00:00
}
const template = mockEvaluation360Templates.find(
2025-09-15 19:46:52 +00:00
(t) => t.id === currentCampaignForEvaluation.templateId,
)
2025-09-15 09:31:47 +00:00
if (!template) {
2025-09-15 19:46:52 +00:00
alert('Template bulunamadı!')
return
2025-09-15 09:31:47 +00:00
}
// Responses oluştur
2025-09-15 19:46:52 +00:00
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
2025-09-15 09:31:47 +00:00
}
2025-09-15 19:46:52 +00:00
}
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
return {
id: `response-${Date.now()}-${Math.random()}`,
participantId: `participant-${Date.now()}`,
questionId,
question,
responseValue,
responseText: typeof responseValue === 'string' ? responseValue : undefined,
score,
submittedDate: new Date(),
2025-09-15 09:31:47 +00:00
}
2025-09-15 19:46:52 +00:00
})
2025-09-15 09:31:47 +00:00
// Puanları hesapla
2025-09-15 19:46:52 +00:00
const totalScore = responses.reduce((sum, response) => sum + response.score, 0)
2025-09-15 09:31:47 +00:00
const maxScore = template.questionGroups
.flatMap((g) => g.questions)
2025-09-15 19:46:52 +00:00
.reduce((sum, q) => sum + (q.maxRating || 5), 0)
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
const scorePercentage = maxScore > 0 ? (totalScore / maxScore) * 100 : 0
2025-09-15 09:31:47 +00:00
// Grup skorlarını hesapla
const groupScores: HrGroupScore[] = template.questionGroups.map((group) => {
const groupResponses = responses.filter((r) =>
2025-09-15 19:46:52 +00:00
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)
2025-09-15 09:31:47 +00:00
return {
groupId: group.id,
groupName: group.groupName,
score: groupScore,
maxScore: groupMaxScore,
percentage: groupMaxScore > 0 ? (groupScore / groupMaxScore) * 100 : 0,
responseCount: groupResponses.length,
2025-09-15 19:46:52 +00:00
}
})
2025-09-15 09:31:47 +00:00
// Assessor type skorlarını hesapla
const assessorTypeScores: HrAssessorTypeScore[] = [
{
assessorType: selectedAssessorType!,
assessorCount: 1,
averageScore: totalScore,
maxScore: maxScore,
percentage: scorePercentage,
},
2025-09-15 19:46:52 +00:00
]
2025-09-15 09:31:47 +00:00
// 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,
2025-09-15 19:46:52 +00:00
evaluatedEmployee: mockEmployees.find((e) => e.id === evaluationTarget),
2025-09-15 09:31:47 +00:00
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,
2025-09-15 19:46:52 +00:00
notes: '',
2025-09-15 09:31:47 +00:00
},
],
overallScore: totalScore,
maxPossibleScore: maxScore,
scorePercentage,
groupScores,
assessorTypeScores,
2025-09-15 19:46:52 +00:00
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: '',
2025-09-15 09:31:47 +00:00
status: ResultStatusEnum.Pending,
generatedDate: new Date(),
approvedBy: undefined,
approvedDate: undefined,
2025-09-15 19:46:52 +00:00
}
2025-09-15 09:31:47 +00:00
// Console'a yazdır
2025-09-15 19:46:52 +00:00
console.log('Evaluation360Result:', evaluationResult)
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
alert('Değerlendirme başarıyla kaydedildi! Sonuç konsola yazdırıldı.')
handleCloseModal()
}
2025-09-15 09:31:47 +00:00
const handleNewCampaign = () => {
2025-09-15 19:46:52 +00:00
setSelectedCampaign(null)
setShowCampaignModal(true)
}
2025-09-15 09:31:47 +00:00
const handleEditCampaign = (campaign: HrEvaluation360 | null) => {
if (campaign) {
2025-09-15 19:46:52 +00:00
setSelectedCampaign(campaign)
2025-09-15 09:31:47 +00:00
setCampaignFormData({
name: campaign.name,
description: campaign.description,
templateId: campaign.templateId,
2025-09-15 19:46:52 +00:00
departmentId: campaign.departmentId || '',
2025-09-15 09:31:47 +00:00
targetEmployees: campaign.targetEmployees,
2025-09-15 19:46:52 +00:00
startDate: campaign.startDate.toISOString().split('T')[0],
endDate: campaign.endDate.toISOString().split('T')[0],
})
setShowCampaignModal(true)
2025-09-15 09:31:47 +00:00
}
2025-09-15 19:46:52 +00:00
}
2025-09-15 09:31:47 +00:00
const handleViewCampaign = (campaign: HrEvaluation360) => {
2025-09-15 19:46:52 +00:00
setSelectedCampaign(campaign)
setShowViewModal(true)
}
2025-09-15 09:31:47 +00:00
const handleSaveCampaign = () => {
2025-09-15 19:46:52 +00:00
console.log('Değerlendirme kaydediliyor:', campaignFormData)
handleCloseModal()
}
2025-09-15 09:31:47 +00:00
const handleDepartmentChange = (departmentId: string) => {
2025-09-15 19:46:52 +00:00
setSelectedDepartment(departmentId)
2025-09-15 09:31:47 +00:00
setCampaignFormData({
...campaignFormData,
departmentId,
targetEmployees: [],
2025-09-15 19:46:52 +00:00
})
}
2025-09-15 09:31:47 +00:00
// Değerlendirme yapma handler'ı
const handleStartEvaluation = () => {
2025-09-15 19:46:52 +00:00
setCurrentCampaignForEvaluation(null)
setEvaluationTarget('')
setEvaluationEvaluator('')
setShowEvaluationModal(true)
}
2025-09-15 09:31:47 +00:00
// Otomatik değerlendirici belirleme fonksiyonu (360° metodolojisi)
2025-09-15 19:46:52 +00:00
const getEvaluatorsByType = (targetEmployeeId: string, assessorType: AssessorTypeEnum) => {
const targetEmployee = mockEmployees.find((emp) => emp.id === targetEmployeeId)
if (!targetEmployee) return []
2025-09-15 09:31:47 +00:00
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 || '',
2025-09-15 19:46:52 +00:00
type: 'employee',
2025-09-15 09:31:47 +00:00
},
2025-09-15 19:46:52 +00:00
]
2025-09-15 09:31:47 +00:00
}
case AssessorTypeEnum.Manager: {
const managers = mockEmployees.filter(
(emp) =>
emp.departmentId === targetEmployee.departmentId &&
2025-09-15 19:46:52 +00:00
(typeof emp.jobPosition?.level === 'number' &&
typeof targetEmployee.jobPosition?.level === 'number'
2025-09-15 09:31:47 +00:00
? emp.jobPosition?.level > targetEmployee.jobPosition?.level
2025-09-15 19:46:52 +00:00
: emp.jobPosition?.name.includes('Müdür') ||
emp.jobPosition?.name.includes('Manager')),
)
2025-09-15 09:31:47 +00:00
return managers.map((emp) => ({
id: emp.id,
name: emp.fullName,
title: emp.jobPosition?.name,
department: mockDepartments.find((d) => d.id === emp.departmentId)?.name || '',
2025-09-15 19:46:52 +00:00
type: 'employee',
}))
2025-09-15 09:31:47 +00:00
}
case AssessorTypeEnum.Peer: {
const peers = mockEmployees.filter(
(emp) =>
emp.id !== targetEmployeeId &&
emp.departmentId === targetEmployee.departmentId &&
2025-09-15 19:46:52 +00:00
emp.jobPosition?.level === targetEmployee.jobPosition?.level,
)
2025-09-15 09:31:47 +00:00
return peers.map((emp) => ({
id: emp.id,
name: emp.fullName,
title: emp.jobPosition?.name,
department: mockDepartments.find((d) => d.id === emp.departmentId)?.name || '',
2025-09-15 19:46:52 +00:00
type: 'employee',
}))
2025-09-15 09:31:47 +00:00
}
case AssessorTypeEnum.Subordinate: {
const subordinates = mockEmployees.filter(
(emp) =>
emp.departmentId === targetEmployee.departmentId &&
2025-09-15 19:46:52 +00:00
(typeof emp.jobPosition?.level === 'number' &&
typeof targetEmployee.jobPosition?.level === 'number'
2025-09-15 09:31:47 +00:00
? emp.jobPosition?.level < targetEmployee.jobPosition?.level
2025-09-15 19:46:52 +00:00
: !emp.jobPosition?.name.includes('Müdür') &&
!emp.jobPosition?.name.includes('Manager')),
)
2025-09-15 09:31:47 +00:00
return subordinates.map((emp) => ({
id: emp.id,
name: emp.fullName,
title: emp.jobPosition?.name,
department: mockDepartments.find((d) => d.id === emp.departmentId)?.name || '',
2025-09-15 19:46:52 +00:00
type: 'employee',
}))
2025-09-15 09:31:47 +00:00
}
case AssessorTypeEnum.Customer: {
return mockBusinessParties.map((customer) => ({
id: customer.id,
name: customer.name,
2025-09-15 19:46:52 +00:00
title: 'Müşteri Temsilcisi',
department: 'Müşteri',
type: 'customer',
}))
2025-09-15 09:31:47 +00:00
}
case AssessorTypeEnum.External: {
return [
{
2025-09-15 19:46:52 +00:00
id: 'external',
name: 'Dış Değerlendirici',
title: 'Harici',
department: 'Dış Paydaş',
type: 'external',
2025-09-15 09:31:47 +00:00
},
2025-09-15 19:46:52 +00:00
]
2025-09-15 09:31:47 +00:00
}
case AssessorTypeEnum.HRUpperManagement: {
const hrEmployees = mockEmployees.filter(
(emp) =>
emp.id !== targetEmployeeId && (emp.departmentId === 'hr' || emp.departmentId === '3'), // HR departmanı
2025-09-15 19:46:52 +00:00
)
2025-09-15 09:31:47 +00:00
return hrEmployees.map((emp) => ({
id: emp.id,
name: emp.fullName,
title: emp.jobPosition?.name,
department: mockDepartments.find((d) => d.id === emp.departmentId)?.name || '',
2025-09-15 19:46:52 +00:00
type: 'employee',
}))
2025-09-15 09:31:47 +00:00
}
case AssessorTypeEnum.OtherDepartment: {
const otherDepartmentEmployees = mockEmployees.filter(
(emp) => emp.id !== targetEmployeeId && emp.departmentId !== targetEmployee.departmentId,
2025-09-15 19:46:52 +00:00
)
2025-09-15 09:31:47 +00:00
return otherDepartmentEmployees.map((emp) => ({
id: emp.id,
name: emp.fullName,
title: emp.jobPosition?.name,
department: mockDepartments.find((d) => d.id === emp.departmentId)?.name || '',
2025-09-15 19:46:52 +00:00
type: 'employee',
}))
2025-09-15 09:31:47 +00:00
}
default:
2025-09-15 19:46:52 +00:00
return []
2025-09-15 09:31:47 +00:00
}
2025-09-15 19:46:52 +00:00
}
2025-09-15 09:31:47 +00:00
// Değerlendiren bilgisini getiren fonksiyon
const getEvaluatorInfo = () => {
2025-09-15 19:46:52 +00:00
if (evaluationEvaluator === 'external') {
return externalEvaluatorName
2025-09-15 09:31:47 +00:00
}
if (selectedAssessorType === AssessorTypeEnum.Customer) {
2025-09-15 19:46:52 +00:00
const customer = mockBusinessParties.find((c) => c.id === selectedCustomerId)
return customer ? customer.name : 'Müşteri Bulunamadı'
2025-09-15 09:31:47 +00:00
}
2025-09-15 19:46:52 +00:00
const employee = mockEmployees.find((e) => e.id === evaluationEvaluator)
return employee ? employee.fullName : 'Çalışan Bulunamadı'
}
2025-09-15 09:31:47 +00:00
// Template'deki izin verilen assessor tiplerini getir
const getAllowedAssessorTypes = () => {
2025-09-15 19:46:52 +00:00
if (!currentCampaignForEvaluation) return []
2025-09-15 09:31:47 +00:00
const template = mockEvaluation360Templates.find(
2025-09-15 19:46:52 +00:00
(t) => t.id === currentCampaignForEvaluation.templateId,
)
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
return template?.assessorTypes || []
}
2025-09-15 09:31:47 +00:00
// Helper function to get participants for a campaign from results
const getCampaignParticipants = (campaignId: string) => {
return mockEvaluation360Results
.filter((result) => result.campaignId === campaignId)
2025-09-15 19:46:52 +00:00
.flatMap((result) => result.participants)
}
2025-09-15 09:31:47 +00:00
// Filtered data
const filteredCampaigns = mockEvaluation360.filter((campaign) => {
2025-09-15 19:46:52 +00:00
if (selectedStatus !== 'all' && campaign.status !== selectedStatus) return false
if (selectedDepartment !== 'all' && campaign.departmentId !== selectedDepartment) return false
if (selectedEmployee !== 'all') {
const participants = getCampaignParticipants(campaign.id)
2025-09-15 09:31:47 +00:00
const hasEmployee = participants.some(
2025-09-15 19:46:52 +00:00
(p) => p.evaluatedEmployeeId === selectedEmployee || p.evaluatorId === selectedEmployee,
)
if (!hasEmployee) return false
2025-09-15 09:31:47 +00:00
}
2025-09-15 19:46:52 +00:00
return true
})
2025-09-15 09:31:47 +00:00
const filteredEmployeesByDepartment = mockEmployees.filter(
(emp) => selectedDepartment === 'all' || emp.departmentId === selectedDepartment,
2025-09-15 19:46:52 +00:00
)
2025-09-15 09:31:47 +00:00
// Statistics
const totalActiveCampaigns = mockEvaluation360.filter(
2025-09-15 19:46:52 +00:00
(c) => c.status === CampaignStatusEnum.Active,
).length
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
const allParticipants = mockEvaluation360Results.flatMap((result) => result.participants)
2025-09-15 09:31:47 +00:00
const totalCompletedEvaluations = allParticipants.filter(
2025-09-15 19:46:52 +00:00
(p) => p.status === ParticipantStatusEnum.Completed,
).length
2025-09-15 09:31:47 +00:00
const totalPendingEvaluations = allParticipants.filter(
2025-09-15 19:46:52 +00:00
(p) => p.status === ParticipantStatusEnum.Invited || p.status === ParticipantStatusEnum.Started,
).length
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
const totalParticipants = allParticipants.length
2025-09-15 09:31:47 +00:00
// Results helper functions
// Participant evaluation helper functions
const handleViewEvaluationDetail = (result: {
2025-09-15 19:46:52 +00:00
resultId: string
evaluatedEmployeeName: string
evaluatorName: string
campaignName: string
overallScore: number
scorePercentage: number
evaluatedEmployeeId: string
evaluatorId: string
campaignId: string
evaluatorType: AssessorTypeEnum
status: ParticipantStatusEnum
completedDate?: Date
2025-09-15 09:31:47 +00:00
}) => {
// Değerlendirme detaylarını görüntüle
2025-09-15 19:46:52 +00:00
console.log('Viewing evaluation detail:', result)
setSelectedResult(result)
setShowResultDetailModal(true)
}
2025-09-15 09:31:47 +00:00
const handleEditEvaluationDetail = (result: {
2025-09-15 19:46:52 +00:00
resultId: string
evaluatedEmployeeName: string
evaluatorName: string
campaignName: string
overallScore: number
scorePercentage: number
evaluatedEmployeeId: string
evaluatorId: string
campaignId: string
evaluatorType: AssessorTypeEnum
status: ParticipantStatusEnum
completedDate?: Date
2025-09-15 09:31:47 +00:00
}) => {
// Değerlendirme detaylarını düzenle
2025-09-15 19:46:52 +00:00
console.log('Editing evaluation detail:', result)
2025-09-15 09:31:47 +00:00
// Mevcut evaluation result'ını bul
2025-09-15 19:46:52 +00:00
const evaluationResult = mockEvaluation360Results.find((r) => r.id === result.resultId)
2025-09-15 09:31:47 +00:00
if (evaluationResult) {
// Mevcut cevapları yükle
2025-09-15 19:46:52 +00:00
const currentResponses: Record<string, string | number> = {}
2025-09-15 09:31:47 +00:00
evaluationResult.participants.forEach((participant) => {
participant.responses.forEach((response) => {
2025-09-15 19:46:52 +00:00
currentResponses[response.questionId] = response.responseValue
})
})
setEditResponses(currentResponses)
setEditManagerComments(evaluationResult.managerComments || '')
setEditHrComments(evaluationResult.hrComments || '')
setEditResultStatus(evaluationResult.status)
2025-09-15 09:31:47 +00:00
}
2025-09-15 19:46:52 +00:00
setSelectedResult(result)
setShowResultEditModal(true)
}
2025-09-15 09:31:47 +00:00
const getAssessorTypeLabel = (assessorType: AssessorTypeEnum): string => {
2025-09-15 19:46:52 +00:00
return getAssessorTypeText(assessorType)
}
2025-09-15 09:31:47 +00:00
const getAllEvaluationParticipants = () => {
// Tüm sonuçlardan participant verilerini al
const allParticipants = mockEvaluation360Results.flatMap((result) =>
result.participants.map((participant) => ({
...participant,
resultId: result.id,
evaluatedEmployeeName:
2025-09-15 19:46:52 +00:00
mockEmployees.find((e) => e.id === participant.evaluatedEmployeeId)?.fullName ||
'Bilinmiyor',
2025-09-15 09:31:47 +00:00
evaluatorName:
2025-09-15 19:46:52 +00:00
mockEmployees.find((e) => e.id === participant.evaluatorId)?.fullName || 'Bilinmiyor',
2025-09-15 09:31:47 +00:00
campaignName:
2025-09-15 19:46:52 +00:00
mockEvaluation360.find((c) => c.id === participant.campaignId)?.name || 'Bilinmiyor',
2025-09-15 09:31:47 +00:00
overallScore: result.overallScore,
scorePercentage: result.scorePercentage,
result: result,
2025-09-15 19:46:52 +00:00
})),
)
2025-09-15 09:31:47 +00:00
// Filtreleme işlemi
return allParticipants.filter((participant) => {
// Durum filtresi
2025-09-15 19:46:52 +00:00
if (selectedResultsStatus !== 'all' && participant.status !== selectedResultsStatus) {
return false
2025-09-15 09:31:47 +00:00
}
// Kampanya filtresi
2025-09-15 19:46:52 +00:00
if (selectedResultsCampaign !== 'all' && participant.campaignId !== selectedResultsCampaign) {
return false
2025-09-15 09:31:47 +00:00
}
// Değerlendirilecek kişi filtresi
if (
2025-09-15 19:46:52 +00:00
selectedResultsEmployee !== 'all' &&
2025-09-15 09:31:47 +00:00
participant.evaluatedEmployeeId !== selectedResultsEmployee
) {
2025-09-15 19:46:52 +00:00
return false
2025-09-15 09:31:47 +00:00
}
// Departman filtresi
2025-09-15 19:46:52 +00:00
if (selectedResultsDepartment !== 'all') {
2025-09-15 09:31:47 +00:00
const evaluatedEmployee = mockEmployees.find(
2025-09-15 19:46:52 +00:00
(e) => e.id === participant.evaluatedEmployeeId,
)
if (!evaluatedEmployee || evaluatedEmployee.departmentId !== selectedResultsDepartment) {
2025-09-15 19:46:52 +00:00
return false
2025-09-15 09:31:47 +00:00
}
}
2025-09-15 19:46:52 +00:00
return true
})
}
2025-09-15 09:31:47 +00:00
// Columns for campaigns table
const campaignColumns: Column<HrEvaluation360>[] = [
{
2025-09-15 19:46:52 +00:00
key: 'name',
header: 'Değerlendirme Adı',
2025-09-15 09:31:47 +00:00
sortable: true,
},
{
2025-09-15 19:46:52 +00:00
key: 'departmentId',
header: 'Departman',
2025-09-15 09:31:47 +00:00
render: (item: HrEvaluation360) => {
2025-09-15 19:46:52 +00:00
const department = mockDepartments.find((d) => d.id === item.departmentId)
return department?.name || 'Tüm Departmanlar'
2025-09-15 09:31:47 +00:00
},
},
{
2025-09-15 19:46:52 +00:00
key: 'templateId',
header: 'Şablon',
2025-09-15 09:31:47 +00:00
render: (item: HrEvaluation360) => {
2025-09-15 19:46:52 +00:00
const template = mockEvaluation360Templates.find((t) => t.id === item.templateId)
return template?.name || 'Bilinmiyor'
2025-09-15 09:31:47 +00:00
},
},
{
2025-09-15 19:46:52 +00:00
key: 'status',
header: 'Durum',
2025-09-15 09:31:47 +00:00
render: (item: HrEvaluation360) => (
<span
className={`px-2 py-1 text-xs font-medium rounded-full ${getCampaignStatusColor(
2025-09-15 19:46:52 +00:00
item.status,
2025-09-15 09:31:47 +00:00
)}`}
>
{getCampaignStatusText(item.status)}
</span>
),
},
{
2025-09-15 19:46:52 +00:00
key: 'startDate',
header: 'Başlangıç',
render: (item: HrEvaluation360) => item.startDate.toLocaleDateString('tr-TR'),
2025-09-15 09:31:47 +00:00
},
{
2025-09-15 19:46:52 +00:00
key: 'endDate',
header: 'Bitiş',
render: (item: HrEvaluation360) => item.endDate.toLocaleDateString('tr-TR'),
2025-09-15 09:31:47 +00:00
},
{
2025-09-15 19:46:52 +00:00
key: 'participants',
header: 'Katılımcı',
2025-09-15 09:31:47 +00:00
render: (item: HrEvaluation360) => {
2025-09-15 19:46:52 +00:00
const participants = getCampaignParticipants(item.id)
return `${participants.length} kişi`
2025-09-15 09:31:47 +00:00
},
},
{
2025-09-15 19:46:52 +00:00
key: 'id',
header: 'İşlemler',
2025-09-15 09:31:47 +00:00
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>
),
},
2025-09-15 19:46:52 +00:00
]
2025-09-15 09:31:47 +00:00
return (
2025-09-15 19:46:52 +00:00
<Container>
<div className="space-y-2">
{/* Header */}
<div className="flex justify-between items-center">
<div>
2025-09-15 21:02:48 +00:00
<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>
2025-09-15 19:46:52 +00:00
</div>
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 19:46:52 +00:00
{/* 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" />
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 19:46:52 +00:00
{/* 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>
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
<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>
2025-09-17 09:46:58 +00:00
{Object.values(CampaignStatusEnum).map((status) => (
<option key={status} value={status}>
{getCampaignStatusText(status)}
</option>
))}
2025-09-15 19:46:52 +00:00
</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>
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
<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}>
2025-09-17 09:46:58 +00:00
{employee.fullName}
2025-09-15 19:46:52 +00:00
</option>
))}
</select>
</div>
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
<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>
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 19:46:52 +00:00
{/* Campaigns Table */}
<DataTable data={filteredCampaigns} columns={campaignColumns} />
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 19:46:52 +00:00
)}
{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>
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
<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>
2025-09-17 09:46:58 +00:00
{Object.values(ParticipantStatusEnum).map((status) => (
<option key={status} value={status}>
{getParticipantStatusText(status)}
</option>
))}
2025-09-15 19:46:52 +00:00
</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>
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
<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>
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 19:46:52 +00:00
</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,
)}`}
2025-09-15 09:31:47 +00:00
>
2025-09-15 19:46:52 +00:00
{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>
2025-09-15 09:31:47 +00:00
</div>
</div>
2025-09-15 19:46:52 +00:00
)}
</div>
2025-09-15 09:31:47 +00:00
</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">
2025-09-15 19:46:52 +00:00
{selectedCampaign ? 'Değerlendirme Düzenle' : 'Yeni Değerlendirme'}
2025-09-15 09:31:47 +00:00
</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>
2025-09-15 19:46:52 +00:00
<label className="block text-sm font-medium text-gray-700 mb-1">ıklama</label>
2025-09-15 09:31:47 +00:00
<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>
2025-09-15 19:46:52 +00:00
<label className="block text-sm font-medium text-gray-700 mb-1">Departman</label>
2025-09-15 09:31:47 +00:00
<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) => (
2025-09-15 19:46:52 +00:00
<label key={employee.id} className="flex items-center mb-2">
2025-09-15 09:31:47 +00:00
<input
type="checkbox"
2025-09-15 19:46:52 +00:00
checked={campaignFormData.targetEmployees.includes(employee.id)}
2025-09-15 09:31:47 +00:00
onChange={(e) => {
if (e.target.checked) {
setCampaignFormData({
...campaignFormData,
2025-09-15 19:46:52 +00:00
targetEmployees: [...campaignFormData.targetEmployees, employee.id],
})
2025-09-15 09:31:47 +00:00
} else {
setCampaignFormData({
...campaignFormData,
2025-09-15 19:46:52 +00:00
targetEmployees: campaignFormData.targetEmployees.filter(
(id) => id !== employee.id,
),
})
2025-09-15 09:31:47 +00:00
}
}}
className="mr-2"
/>
2025-09-15 19:46:52 +00:00
{employee.firstName} {employee.lastName} -{' '}
{employee.jobPosition?.name || 'Pozisyon Belirtilmemiş'}
2025-09-15 09:31:47 +00:00
</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" />
2025-09-15 19:46:52 +00:00
{selectedCampaign ? 'Güncelle' : 'Kaydet'}
2025-09-15 09:31:47 +00:00
</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">
2025-09-15 19:46:52 +00:00
<h2 className="text-base font-semibold">{selectedCampaign.name}</h2>
2025-09-15 09:31:47 +00:00
<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>
2025-09-15 19:46:52 +00:00
<span className="text-sm font-medium text-gray-600">Adı:</span>
<p className="text-sm text-gray-900">{selectedCampaign.name}</p>
2025-09-15 09:31:47 +00:00
</div>
<div>
2025-09-15 19:46:52 +00:00
<span className="text-sm font-medium text-gray-600">ıklama:</span>
<p className="text-sm text-gray-900">{selectedCampaign.description}</p>
2025-09-15 09:31:47 +00:00
</div>
<div>
2025-09-15 19:46:52 +00:00
<span className="text-sm font-medium text-gray-600">Durum:</span>
2025-09-15 09:31:47 +00:00
<span
className={`ml-2 px-3 py-1 text-xs font-medium rounded-full ${getCampaignStatusColor(
2025-09-15 19:46:52 +00:00
selectedCampaign.status,
2025-09-15 09:31:47 +00:00
)}`}
>
{getCampaignStatusText(selectedCampaign.status)}
</span>
</div>
<div>
2025-09-15 19:46:52 +00:00
<span className="text-sm font-medium text-gray-600">Tarih Aralığı:</span>
2025-09-15 09:31:47 +00:00
<p className="text-sm text-gray-900">
2025-09-15 19:46:52 +00:00
{selectedCampaign.startDate.toLocaleDateString('tr-TR')} -{' '}
{selectedCampaign.endDate.toLocaleDateString('tr-TR')}
2025-09-15 09:31:47 +00:00
</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">
{(() => {
2025-09-15 19:46:52 +00:00
const participants = getCampaignParticipants(selectedCampaign.id)
2025-09-15 09:31:47 +00:00
const completed = participants.filter(
2025-09-15 19:46:52 +00:00
(p) => p.status === ParticipantStatusEnum.Completed,
)
2025-09-15 09:31:47 +00:00
const started = participants.filter(
2025-09-15 19:46:52 +00:00
(p) => p.status === ParticipantStatusEnum.Started,
)
2025-09-15 09:31:47 +00:00
const invited = participants.filter(
2025-09-15 19:46:52 +00:00
(p) => p.status === ParticipantStatusEnum.Invited,
)
2025-09-15 09:31:47 +00:00
return (
<>
<div className="flex justify-between">
2025-09-15 19:46:52 +00:00
<span className="text-sm text-gray-600">Toplam:</span>
2025-09-15 09:31:47 +00:00
<span className="text-sm font-medium text-gray-900">
{participants.length}
</span>
</div>
<div className="flex justify-between">
2025-09-15 19:46:52 +00:00
<span className="text-sm text-gray-600">Tamamlanan:</span>
2025-09-15 09:31:47 +00:00
<span className="text-sm font-medium text-green-600">
{completed.length}
</span>
</div>
<div className="flex justify-between">
2025-09-15 19:46:52 +00:00
<span className="text-sm text-gray-600">Devam Eden:</span>
2025-09-15 09:31:47 +00:00
<span className="text-sm font-medium text-blue-600">
{started.length}
</span>
</div>
<div className="flex justify-between">
2025-09-15 19:46:52 +00:00
<span className="text-sm text-gray-600">Bekleyen:</span>
2025-09-15 09:31:47 +00:00
<span className="text-sm font-medium text-yellow-600">
{invited.length}
</span>
</div>
</>
2025-09-15 19:46:52 +00:00
)
2025-09-15 09:31:47 +00:00
})()}
</div>
</div>
</div>
<div>
2025-09-15 19:46:52 +00:00
<h3 className="text-sm font-medium text-gray-900 mb-2">Katılımcı Detayları</h3>
2025-09-15 09:31:47 +00:00
<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">
2025-09-15 19:46:52 +00:00
{getCampaignParticipants(selectedCampaign.id).map((participant) => {
const targetEmployee = mockEmployees.find(
(emp) => emp.id === participant.evaluatedEmployeeId,
)
const assessorEmployee = mockEmployees.find(
(emp) => emp.id === participant.evaluatorId,
)
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
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
2025-09-15 09:31:47 +00:00
? `Başladı: ${participant.startedDate.toLocaleDateString(
2025-09-15 19:46:52 +00:00
'tr-TR',
2025-09-15 09:31:47 +00:00
)}`
2025-09-15 19:46:52 +00:00
: `Davet: ${participant.invitedDate.toLocaleDateString('tr-TR')}`}
</td>
</tr>
)
})}
2025-09-15 09:31:47 +00:00
</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={() => {
2025-09-15 19:46:52 +00:00
handleCloseModal()
handleEditCampaign(selectedCampaign)
2025-09-15 09:31:47 +00:00
}}
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
2025-09-15 19:46:52 +00:00
? 'Değerlendirme Yap'
2025-09-15 09:31:47 +00:00
: 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>
2025-09-15 19:46:52 +00:00
<h3 className="text-sm font-medium text-gray-900 mb-2">Değerlendirme Seçin</h3>
2025-09-15 09:31:47 +00:00
<div className="space-y-2">
{mockEvaluation360
2025-09-15 19:46:52 +00:00
.filter((campaign) => campaign.status === CampaignStatusEnum.Active)
2025-09-15 09:31:47 +00:00
.map((campaign) => (
<div
key={campaign.id}
className="border rounded-lg p-2.5 hover:bg-gray-50 cursor-pointer"
2025-09-15 19:46:52 +00:00
onClick={() => setCurrentCampaignForEvaluation(campaign)}
2025-09-15 09:31:47 +00:00
>
<div className="flex justify-between items-center">
<div>
2025-09-15 19:46:52 +00:00
<h4 className="font-medium text-gray-900">{campaign.name}</h4>
2025-09-15 21:02:48 +00:00
<p className="text-gray-600">{campaign.description}</p>
2025-09-15 09:31:47 +00:00
<div className="flex items-center gap-2 mt-2">
<span
className={`inline-block px-2 py-1 text-xs rounded-full ${getCampaignStatusColor(
2025-09-15 19:46:52 +00:00
campaign.status,
2025-09-15 09:31:47 +00:00
)}`}
>
{getCampaignStatusText(campaign.status)}
</span>
<span className="text-xs text-gray-500">
2025-09-15 19:46:52 +00:00
{campaign.startDate.toLocaleDateString()} -{' '}
2025-09-15 09:31:47 +00:00
{campaign.endDate.toLocaleDateString()}
</span>
</div>
</div>
<FaPlay className="w-4 h-4 text-gray-400" />
</div>
</div>
))}
</div>
{mockEvaluation360.filter(
2025-09-15 19:46:52 +00:00
(campaign) => campaign.status === CampaignStatusEnum.Active,
2025-09-15 09:31:47 +00:00
).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">
2025-09-15 19:46:52 +00:00
<strong>Seçili Değerlendirme:</strong> {currentCampaignForEvaluation.name}
2025-09-15 09:31:47 +00:00
</p>
</div>
<div className="space-y-3">
{mockEmployees
.filter((emp) =>
2025-09-15 19:46:52 +00:00
currentCampaignForEvaluation.targetEmployees.includes(emp.id),
2025-09-15 09:31:47 +00:00
)
.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>
2025-09-15 19:46:52 +00:00
<h4 className="font-medium text-gray-900">{employee.fullName}</h4>
2025-09-15 21:02:48 +00:00
<p className="text-gray-600">{employee.jobPosition?.name}</p>
<p className="text-gray-600">
{mockDepartments.find((d) => d.id === employee.departmentId)?.name}
2025-09-15 09:31:47 +00:00
</p>
</div>
<FaUsers className="w-4 h-4 text-gray-400" />
</div>
</div>
))}
</div>
{mockEmployees.filter((emp) =>
2025-09-15 19:46:52 +00:00
currentCampaignForEvaluation.targetEmployees.includes(emp.id),
2025-09-15 09:31:47 +00:00
).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
2025-09-15 19:46:52 +00:00
onClick={() => setEvaluationTarget('')}
2025-09-15 09:31:47 +00:00
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">
2025-09-15 19:46:52 +00:00
<strong>Değerlendirilecek:</strong>{' '}
{mockEmployees.find((e) => e.id === evaluationTarget)?.fullName}
2025-09-15 09:31:47 +00:00
</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={() => {
2025-09-15 19:46:52 +00:00
setSelectedAssessorType(assessorType)
setEvaluatorSearchTerm('')
2025-09-15 09:31:47 +00:00
}}
>
<div className="flex justify-between items-center">
<div>
<h4 className="font-medium text-gray-900">
{getAssessorTypeText(assessorType)}
</h4>
2025-09-15 21:02:48 +00:00
<p className="text-gray-600">
2025-09-15 09:31:47 +00:00
{getAssessorTypeDescription(assessorType)}
</p>
2025-09-15 19:46:52 +00:00
{getEvaluatorsByType(evaluationTarget, assessorType).length > 0 && (
2025-09-15 09:31:47 +00:00
<span className="inline-block mt-1 px-2 py-1 text-xs rounded-full bg-blue-100 text-blue-800">
2025-09-15 19:46:52 +00:00
{getEvaluatorsByType(evaluationTarget, assessorType).length} seçenek
mevcut
2025-09-15 09:31:47 +00:00
</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={() => {
2025-09-15 19:46:52 +00:00
setSelectedAssessorType(null)
setEvaluationEvaluator('')
setSelectedCustomerId('')
setExternalEvaluatorName('')
setExternalEvaluatorEmail('')
setEvaluatorSearchTerm('')
2025-09-15 09:31:47 +00:00
}}
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">
2025-09-15 19:46:52 +00:00
<strong>Değerlendirilecek:</strong>{' '}
{mockEmployees.find((e) => e.id === evaluationTarget)?.fullName}
2025-09-15 09:31:47 +00:00
<br />
2025-09-15 19:46:52 +00:00
<strong>Değerlendirici Tipi:</strong>{' '}
2025-09-15 09:31:47 +00:00
{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}
2025-09-15 19:46:52 +00:00
onChange={(e) => setExternalEvaluatorName(e.target.value)}
2025-09-15 09:31:47 +00:00
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}
2025-09-15 19:46:52 +00:00
onChange={(e) => setExternalEvaluatorEmail(e.target.value)}
2025-09-15 09:31:47 +00:00
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
2025-09-15 19:46:52 +00:00
onClick={() => setEvaluationEvaluator('external')}
2025-09-15 09:31:47 +00:00
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}
2025-09-15 19:46:52 +00:00
onChange={(e) => setEvaluatorSearchTerm(e.target.value)}
2025-09-15 09:31:47 +00:00
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm"
placeholder="Müşteri adında ara..."
/>
</div>
2025-09-15 19:46:52 +00:00
{getEvaluatorsByType(evaluationTarget, selectedAssessorType)
2025-09-15 09:31:47 +00:00
.filter((evaluator) =>
2025-09-15 19:46:52 +00:00
evaluator.name.toLowerCase().includes(evaluatorSearchTerm.toLowerCase()),
2025-09-15 09:31:47 +00:00
)
.map((evaluator) => (
<div
key={evaluator.id}
className="border rounded-lg p-2.5 hover:bg-gray-50 cursor-pointer"
onClick={() => {
2025-09-15 19:46:52 +00:00
setSelectedCustomerId(evaluator.id)
setEvaluationEvaluator(evaluator.id)
2025-09-15 09:31:47 +00:00
}}
>
<div className="flex justify-between items-center">
<div>
2025-09-15 19:46:52 +00:00
<h4 className="font-medium text-gray-900">{evaluator.name}</h4>
2025-09-15 21:02:48 +00:00
<p className="text-gray-600">{evaluator.title}</p>
2025-09-15 09:31:47 +00:00
<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}
2025-09-15 19:46:52 +00:00
onChange={(e) => setEvaluatorSearchTerm(e.target.value)}
2025-09-15 09:31:47 +00:00
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm"
placeholder="Çalışan adında ara..."
/>
</div>
2025-09-15 19:46:52 +00:00
{getEvaluatorsByType(evaluationTarget, selectedAssessorType)
2025-09-15 09:31:47 +00:00
.filter((evaluator) =>
2025-09-15 19:46:52 +00:00
evaluator.name.toLowerCase().includes(evaluatorSearchTerm.toLowerCase()),
2025-09-15 09:31:47 +00:00
)
.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>
2025-09-15 19:46:52 +00:00
<h4 className="font-medium text-gray-900">{evaluator.name}</h4>
2025-09-15 21:02:48 +00:00
<p className="text-gray-600">{evaluator.title}</p>
2025-09-15 09:31:47 +00:00
<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>
))}
2025-09-15 19:46:52 +00:00
{getEvaluatorsByType(evaluationTarget, selectedAssessorType).length === 0 && (
2025-09-15 09:31:47 +00:00
<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={() => {
2025-09-15 19:46:52 +00:00
setSelectedAssessorType(null)
setEvaluationEvaluator('')
setSelectedCustomerId('')
setExternalEvaluatorName('')
setExternalEvaluatorEmail('')
setEvaluatorSearchTerm('')
2025-09-15 09:31:47 +00:00
}}
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">
2025-09-15 19:46:52 +00:00
<strong>Değerlendirilen:</strong>{' '}
{mockEmployees.find((e) => e.id === evaluationTarget)?.fullName}
2025-09-15 09:31:47 +00:00
<br />
<strong>Değerlendiren:</strong> {getEvaluatorInfo()}
</p>
</div>
{/* Burada şablonun sorularını göstereceğiz */}
<div className="space-y-3">
{currentCampaignForEvaluation &&
mockEvaluation360Templates
2025-09-15 19:46:52 +00:00
.find((t) => t.id === currentCampaignForEvaluation.templateId)
2025-09-15 09:31:47 +00:00
?.questionGroups.map((group) => (
2025-09-15 19:46:52 +00:00
<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>
2025-09-15 09:31:47 +00:00
<div className="space-y-3">
{group.questions.map((question, qIndex) => (
2025-09-15 19:46:52 +00:00
<div key={question.id} className="bg-gray-50 p-2.5 rounded">
2025-09-15 09:31:47 +00:00
<p className="font-medium text-gray-800 mb-3">
{qIndex + 1}. {question.questionText}
{question.isRequired && (
2025-09-15 19:46:52 +00:00
<span className="text-red-500 ml-1">*</span>
2025-09-15 09:31:47 +00:00
)}
</p>
{/* Soru tipine göre input alanları */}
2025-09-15 19:46:52 +00:00
{question.questionType === QuestionTypeEnum.Rating && (
2025-09-15 09:31:47 +00:00
<div className="space-y-2">
<div className="flex justify-around items-center">
{Array.from(
{
length:
(question.maxRating || 5) -
(question.minRating || 1) +
1,
},
(_, i) => {
2025-09-15 19:46:52 +00:00
const value = (question.minRating || 1) + i
2025-09-15 09:31:47 +00:00
return (
<label
key={value}
className="flex flex-col items-center cursor-pointer"
>
<input
type="radio"
name={`question-${question.id}`}
value={value}
checked={
2025-09-15 19:46:52 +00:00
evaluationResponses[question.id] === value
2025-09-15 09:31:47 +00:00
}
onChange={(e) =>
handleResponseChange(
question.id,
2025-09-15 19:46:52 +00:00
Number(e.target.value),
2025-09-15 09:31:47 +00:00
)
}
className="mb-1"
/>
<span className="text-xs text-gray-600">
2025-09-15 19:46:52 +00:00
{question.ratingLabels?.[i] || value}
2025-09-15 09:31:47 +00:00
</span>
</label>
2025-09-15 19:46:52 +00:00
)
},
2025-09-15 09:31:47 +00:00
)}
</div>
</div>
)}
2025-09-15 19:46:52 +00:00
{question.questionType === QuestionTypeEnum.Text && (
2025-09-15 09:31:47 +00:00
<textarea
className="w-full border border-gray-300 rounded-md px-2.5 py-1.5 text-sm"
rows={3}
placeholder="Yorumunuzu yazın..."
2025-09-15 19:46:52 +00:00
value={evaluationResponses[question.id] || ''}
2025-09-15 09:31:47 +00:00
onChange={(e) =>
2025-09-15 19:46:52 +00:00
handleResponseChange(question.id, e.target.value)
2025-09-15 09:31:47 +00:00
}
/>
)}
2025-09-15 19:46:52 +00:00
{question.questionType === QuestionTypeEnum.YesNo && (
2025-09-15 09:31:47 +00:00
<div className="flex gap-4">
<label className="flex items-center cursor-pointer">
<input
type="radio"
name={`question-${question.id}`}
value="yes"
2025-09-15 19:46:52 +00:00
checked={evaluationResponses[question.id] === 'yes'}
2025-09-15 09:31:47 +00:00
onChange={(e) =>
2025-09-15 19:46:52 +00:00
handleResponseChange(question.id, e.target.value)
2025-09-15 09:31:47 +00:00
}
className="mr-2"
/>
Evet
</label>
<label className="flex items-center cursor-pointer">
<input
type="radio"
name={`question-${question.id}`}
value="no"
2025-09-15 19:46:52 +00:00
checked={evaluationResponses[question.id] === 'no'}
2025-09-15 09:31:47 +00:00
onChange={(e) =>
2025-09-15 19:46:52 +00:00
handleResponseChange(question.id, e.target.value)
2025-09-15 09:31:47 +00:00
}
className="mr-2"
/>
Hayır
</label>
</div>
)}
2025-09-15 19:46:52 +00:00
{question.questionType === QuestionTypeEnum.MultipleChoice && (
2025-09-15 09:31:47 +00:00
<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={
2025-09-15 19:46:52 +00:00
evaluationResponses[question.id] === option.value
2025-09-15 09:31:47 +00:00
}
onChange={(e) =>
handleResponseChange(
question.id,
2025-09-15 19:46:52 +00:00
Number(e.target.value),
2025-09-15 09:31:47 +00:00
)
}
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>
2025-09-15 19:46:52 +00:00
<span className="text-sm text-blue-700 font-medium">Kampanya: </span>
<span className="text-sm text-blue-800">{selectedResult.campaignName}</span>
2025-09-15 09:31:47 +00:00
</div>
<div>
2025-09-15 19:46:52 +00:00
<span className="text-sm text-blue-700 font-medium">Değerlendirilen: </span>
2025-09-15 09:31:47 +00:00
<span className="text-sm text-blue-800">
{selectedResult.evaluatedEmployeeName}
</span>
</div>
<div>
2025-09-15 19:46:52 +00:00
<span className="text-sm text-blue-700 font-medium">Değerlendiren: </span>
<span className="text-sm text-blue-800">{selectedResult.evaluatorName}</span>
2025-09-15 09:31:47 +00:00
</div>
<div>
<span className="text-sm text-blue-700 font-medium">
2025-09-15 19:46:52 +00:00
Değerlendiren Tipi:{' '}
2025-09-15 09:31:47 +00:00
</span>
<span className="text-sm text-blue-800">
{getAssessorTypeText(selectedResult.evaluatorType)}
</span>
</div>
</div>
</div>
<div className="bg-green-50 p-4 rounded-lg">
2025-09-15 19:46:52 +00:00
<h3 className="font-medium text-green-800 mb-2 text-sm">Sonuç Bilgileri</h3>
2025-09-15 09:31:47 +00:00
<div className="space-y-1.5">
<div>
2025-09-15 19:46:52 +00:00
<span className="text-sm text-green-700 font-medium">Durum: </span>
2025-09-15 09:31:47 +00:00
<span
className={`text-sm px-2 py-0.5 rounded-full ${getParticipantStatusColor(
2025-09-15 19:46:52 +00:00
selectedResult.status,
2025-09-15 09:31:47 +00:00
)}`}
>
{getParticipantStatusText(selectedResult.status)}
</span>
</div>
<div>
2025-09-15 19:46:52 +00:00
<span className="text-sm text-green-700 font-medium">Toplam Puan: </span>
2025-09-15 09:31:47 +00:00
<span className="text-sm text-green-800 font-bold">
{selectedResult.overallScore}/100
</span>
</div>
<div>
2025-09-15 19:46:52 +00:00
<span className="text-sm text-green-700 font-medium">Yüzde: </span>
2025-09-15 09:31:47 +00:00
<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">
2025-09-15 19:46:52 +00:00
Tamamlanma Tarihi:{' '}
2025-09-15 09:31:47 +00:00
</span>
<span className="text-sm text-green-800">
2025-09-15 19:46:52 +00:00
{new Date(selectedResult.completedDate).toLocaleDateString('tr-TR')}
2025-09-15 09:31:47 +00:00
</span>
</div>
)}
</div>
</div>
</div>
{/* Detaylı Sonuçlar */}
<div className="border rounded-lg p-3">
2025-09-15 19:46:52 +00:00
<h3 className="font-medium text-gray-900 mb-2 text-sm">Detaylı Sonuçlar</h3>
2025-09-15 09:31:47 +00:00
{(() => {
// Seçili sonucu mockEvaluation360Results'tan bul
const evaluationResult = mockEvaluation360Results.find(
2025-09-15 19:46:52 +00:00
(r) => r.id === selectedResult.resultId,
)
2025-09-15 09:31:47 +00:00
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>
2025-09-15 19:46:52 +00:00
)
2025-09-15 09:31:47 +00:00
}
return (
<div className="space-y-2.5">
{/* Soru Cevapları */}
{(() => {
const campaign = mockEvaluation360.find(
2025-09-15 19:46:52 +00:00
(c) => c.id === selectedResult.campaignId,
)
2025-09-15 09:31:47 +00:00
const template = campaign
2025-09-15 19:46:52 +00:00
? mockEvaluation360Templates.find((t) => t.id === campaign.templateId)
: null
2025-09-15 09:31:47 +00:00
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) => (
2025-09-15 19:46:52 +00:00
<div key={group.id} className="bg-gray-50 p-2.5 rounded-lg">
2025-09-15 09:31:47 +00:00
<div className="mb-3">
<h5 className="font-medium text-gray-800">
{group.groupName}
</h5>
2025-09-15 21:02:48 +00:00
<p className="text-gray-600">{group.description}</p>
2025-09-15 09:31:47 +00:00
</div>
<div className="space-y-2.5">
2025-09-15 19:46:52 +00:00
{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>
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
<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
}
})()}
2025-09-15 09:31:47 +00:00
</span>
</div>
2025-09-15 19:46:52 +00:00
<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>
2025-09-15 09:31:47 +00:00
</div>
</div>
2025-09-15 19:46:52 +00:00
{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>
)
})}
2025-09-15 09:31:47 +00:00
</div>
</div>
))}
</div>
</div>
2025-09-15 19:46:52 +00:00
)
2025-09-15 09:31:47 +00:00
}
2025-09-15 19:46:52 +00:00
return null
2025-09-15 09:31:47 +00:00
})()}
{/* 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) => (
2025-09-15 19:46:52 +00:00
<div key={groupScore.groupId} className="bg-gray-50 p-2.5 rounded-lg">
2025-09-15 09:31:47 +00:00
<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">
2025-09-15 19:46:52 +00:00
<span>%{Math.round(groupScore.percentage)}</span>
2025-09-15 09:31:47 +00:00
<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">
2025-09-15 19:46:52 +00:00
{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)}
2025-09-15 09:31:47 +00:00
</div>
2025-09-15 19:46:52 +00:00
<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>
))}
2025-09-15 09:31:47 +00:00
</div>
</div>
{/* Güçlü Yönler */}
<div>
2025-09-15 19:46:52 +00:00
<h4 className="font-medium text-gray-800 mb-2 text-sm">💪 Güçlü Yönler</h4>
2025-09-15 09:31:47 +00:00
<div className="bg-green-50 p-2.5 rounded-lg">
{evaluationResult.strengths.length > 0 ? (
<ul className="list-disc list-inside space-y-1">
2025-09-15 19:46:52 +00:00
{evaluationResult.strengths.map((strength, index) => (
<li key={index} className="text-green-800">
{strength}
</li>
))}
2025-09-15 09:31:47 +00:00
</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">
2025-09-15 19:46:52 +00:00
{evaluationResult.developmentAreas.map((area, index) => (
<li key={index} className="text-amber-800">
{area}
</li>
))}
2025-09-15 09:31:47 +00:00
</ul>
) : (
<p className="text-amber-700 italic">
Gelişim alanları henüz analiz edilmedi
</p>
)}
</div>
</div>
{/* Aksiyon Planı */}
<div>
2025-09-15 19:46:52 +00:00
<h4 className="font-medium text-gray-800 mb-2 text-sm">🎯 Aksiyon Planı</h4>
2025-09-15 09:31:47 +00:00
<div className="bg-purple-50 p-2.5 rounded-lg">
{evaluationResult.actionPlan.length > 0 ? (
<ul className="list-decimal list-inside space-y-1">
2025-09-15 19:46:52 +00:00
{evaluationResult.actionPlan.map((action, index) => (
<li key={index} className="text-purple-800">
{action}
</li>
))}
2025-09-15 09:31:47 +00:00
</ul>
) : (
<p className="text-purple-700 italic">
Aksiyon planı henüz oluşturulmadı
</p>
)}
</div>
</div>
{/* Yorumlar */}
2025-09-15 19:46:52 +00:00
{(evaluationResult.managerComments || evaluationResult.hrComments) && (
2025-09-15 09:31:47 +00:00
<div>
2025-09-15 19:46:52 +00:00
<h4 className="font-medium text-gray-800 mb-2 text-sm">💬 Yorumlar</h4>
2025-09-15 09:31:47 +00:00
<div className="space-y-2">
{evaluationResult.managerComments && (
<div className="bg-blue-50 p-2.5 rounded-lg">
2025-09-15 19:46:52 +00:00
<h5 className="font-medium text-blue-800 mb-2">Yönetici Yorumu</h5>
<p className="text-blue-700">{evaluationResult.managerComments}</p>
2025-09-15 09:31:47 +00:00
</div>
)}
{evaluationResult.hrComments && (
<div className="bg-indigo-50 p-2.5 rounded-lg">
2025-09-15 19:46:52 +00:00
<h5 className="font-medium text-indigo-800 mb-2">İK Yorumu</h5>
<p className="text-indigo-700">{evaluationResult.hrComments}</p>
2025-09-15 09:31:47 +00:00
</div>
)}
</div>
</div>
)}
</div>
2025-09-15 19:46:52 +00:00
)
2025-09-15 09:31:47 +00:00
})()}
</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={() => {
2025-09-15 19:46:52 +00:00
handleCloseModal()
handleEditEvaluationDetail(selectedResult)
2025-09-15 09:31:47 +00:00
}}
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">
2025-09-15 19:46:52 +00:00
<h3 className="font-medium text-amber-800 mb-2 text-sm">Değerlendirme Bilgileri</h3>
2025-09-15 09:31:47 +00:00
<div className="grid grid-cols-2 gap-4">
<div>
2025-09-15 19:46:52 +00:00
<span className="text-sm text-amber-700 font-medium">Kampanya: </span>
<span className="text-sm text-amber-800">{selectedResult.campaignName}</span>
2025-09-15 09:31:47 +00:00
</div>
<div>
2025-09-15 19:46:52 +00:00
<span className="text-sm text-amber-700 font-medium">Değerlendirilen: </span>
2025-09-15 09:31:47 +00:00
<span className="text-sm text-amber-800">
{selectedResult.evaluatedEmployeeName}
</span>
</div>
<div>
2025-09-15 19:46:52 +00:00
<span className="text-sm text-amber-700 font-medium">Değerlendiren: </span>
<span className="text-sm text-amber-800">{selectedResult.evaluatorName}</span>
2025-09-15 09:31:47 +00:00
</div>
<div>
2025-09-15 19:46:52 +00:00
<span className="text-sm text-amber-700 font-medium">Değerlendiren Tipi: </span>
2025-09-15 09:31:47 +00:00
<span className="text-sm text-amber-800">
{getAssessorTypeText(selectedResult.evaluatorType)}
</span>
</div>
</div>
</div>
{/* Soru Grupları ve Cevaplar */}
{(() => {
const evaluationResult = mockEvaluation360Results.find(
2025-09-15 19:46:52 +00:00
(r) => r.id === selectedResult.resultId,
)
const campaign = mockEvaluation360.find((c) => c.id === selectedResult.campaignId)
2025-09-15 09:31:47 +00:00
const template = campaign
2025-09-15 19:46:52 +00:00
? mockEvaluation360Templates.find((t) => t.id === campaign.templateId)
: null
2025-09-15 09:31:47 +00:00
if (!evaluationResult || !template) {
return (
<div className="text-center py-8 text-gray-500">
<p>Template verisi bulunamadı</p>
</div>
2025-09-15 19:46:52 +00:00
)
2025-09-15 09:31:47 +00:00
}
return (
<div className="space-y-3">
2025-09-15 19:46:52 +00:00
<h3 className="text-sm font-medium text-gray-900">Soru Grupları ve Cevaplar</h3>
2025-09-15 09:31:47 +00:00
{template.questionGroups.map((group) => (
<div key={group.id} className="border rounded-lg p-2">
<div className="mb-3">
2025-09-15 19:46:52 +00:00
<h4 className="font-medium text-gray-900 text-sm">{group.groupName}</h4>
2025-09-15 21:02:48 +00:00
<p className="text-gray-600">{group.description}</p>
2025-09-15 09:31:47 +00:00
<div className="flex items-center gap-2 mt-2">
2025-09-15 19:46:52 +00:00
<span className="text-xs text-gray-500">ırlık: %{group.weight}</span>
2025-09-15 09:31:47 +00:00
<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) => {
2025-09-15 19:46:52 +00:00
const currentResponse = evaluationResult.participants
.flatMap((p) => p.responses)
.find((r) => r.questionId === question.id)
2025-09-15 09:31:47 +00:00
const editValue =
editResponses[question.id] !== undefined
? editResponses[question.id]
2025-09-15 19:46:52 +00:00
: currentResponse?.responseValue
2025-09-15 09:31:47 +00:00
return (
2025-09-15 19:46:52 +00:00
<div key={question.id} className="bg-gray-50 p-2.5 rounded-lg">
2025-09-15 09:31:47 +00:00
<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">
2025-09-15 19:46:52 +00:00
Mevcut Cevap:{' '}
2025-09-15 09:31:47 +00:00
</span>
<span className="text-xs text-blue-800">
2025-09-15 19:46:52 +00:00
{typeof currentResponse.responseValue === 'string'
2025-09-15 09:31:47 +00:00
? 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ı */}
2025-09-15 19:46:52 +00:00
{question.questionType === QuestionTypeEnum.Rating && (
2025-09-15 09:31:47 +00:00
<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) => {
2025-09-15 19:46:52 +00:00
const value = (question.minRating || 1) + i
2025-09-15 09:31:47 +00:00
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,
2025-09-15 19:46:52 +00:00
Number(e.target.value),
2025-09-15 09:31:47 +00:00
)
}
className="mb-1"
/>
<span className="text-xs text-gray-600">
2025-09-15 19:46:52 +00:00
{question.ratingLabels?.[i] || value}
2025-09-15 09:31:47 +00:00
</span>
</label>
2025-09-15 19:46:52 +00:00
)
},
2025-09-15 09:31:47 +00:00
)}
</div>
</div>
)}
2025-09-15 19:46:52 +00:00
{question.questionType === QuestionTypeEnum.Text && (
2025-09-15 09:31:47 +00:00
<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..."
2025-09-15 19:46:52 +00:00
value={editValue || ''}
2025-09-15 09:31:47 +00:00
onChange={(e) =>
2025-09-15 19:46:52 +00:00
handleEditResponseChange(question.id, e.target.value)
2025-09-15 09:31:47 +00:00
}
/>
</div>
)}
2025-09-15 19:46:52 +00:00
{question.questionType === QuestionTypeEnum.YesNo && (
2025-09-15 09:31:47 +00:00
<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"
2025-09-15 19:46:52 +00:00
checked={editValue === 'yes'}
2025-09-15 09:31:47 +00:00
onChange={(e) =>
2025-09-15 19:46:52 +00:00
handleEditResponseChange(question.id, e.target.value)
2025-09-15 09:31:47 +00:00
}
className="mr-2"
/>
Evet
</label>
<label className="flex items-center cursor-pointer">
<input
type="radio"
name={`edit-question-${question.id}`}
value="no"
2025-09-15 19:46:52 +00:00
checked={editValue === 'no'}
2025-09-15 09:31:47 +00:00
onChange={(e) =>
2025-09-15 19:46:52 +00:00
handleEditResponseChange(question.id, e.target.value)
2025-09-15 09:31:47 +00:00
}
className="mr-2"
/>
Hayır
</label>
</div>
</div>
)}
2025-09-15 19:46:52 +00:00
{question.questionType === QuestionTypeEnum.MultipleChoice && (
2025-09-15 09:31:47 +00:00
<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,
2025-09-15 19:46:52 +00:00
Number(e.target.value),
2025-09-15 09:31:47 +00:00
)
}
className="mr-2"
/>
{option.optionText}
</label>
))}
</div>
</div>
)}
</div>
2025-09-15 19:46:52 +00:00
)
2025-09-15 09:31:47 +00:00
})}
</div>
</div>
))}
</div>
2025-09-15 19:46:52 +00:00
)
2025-09-15 09:31:47 +00:00
})()}
{/* 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>
2025-09-15 19:46:52 +00:00
<label className="block text-sm font-medium text-gray-700 mb-1">Sonuç Durumu</label>
2025-09-15 09:31:47 +00:00
<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">
2025-09-15 19:46:52 +00:00
<h4 className="font-medium text-gray-900 mb-2 text-sm">Mevcut Puan Bilgileri</h4>
2025-09-15 09:31:47 +00:00
<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={() => {
2025-09-15 19:46:52 +00:00
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()
2025-09-15 09:31:47 +00:00
}}
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>
)}
2025-09-15 19:46:52 +00:00
</Container>
)
}
2025-09-15 09:31:47 +00:00
2025-09-15 19:46:52 +00:00
export default Degree360Evaluation