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

3071 lines
130 KiB
TypeScript
Raw Normal View History

2025-09-15 09:31:47 +00:00
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";
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.departmantId)
?.name || "",
type: "employee",
},
];
}
case AssessorTypeEnum.Manager: {
const managers = mockEmployees.filter(
(emp) =>
emp.departmantId === targetEmployee.departmantId &&
(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.departmantId)?.name || "",
type: "employee",
}));
}
case AssessorTypeEnum.Peer: {
const peers = mockEmployees.filter(
(emp) =>
emp.id !== targetEmployeeId &&
emp.departmantId === targetEmployee.departmantId &&
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.departmantId)?.name || "",
type: "employee",
}));
}
case AssessorTypeEnum.Subordinate: {
const subordinates = mockEmployees.filter(
(emp) =>
emp.departmantId === targetEmployee.departmantId &&
(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.departmantId)?.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.departmantId === "hr" || emp.departmantId === "3") // HR departmanı
);
return hrEmployees.map((emp) => ({
id: emp.id,
name: emp.fullName,
title: emp.jobPosition?.name,
department:
mockDepartments.find((d) => d.id === emp.departmantId)?.name || "",
type: "employee",
}));
}
case AssessorTypeEnum.OtherDepartment: {
const otherDepartmentEmployees = mockEmployees.filter(
(emp) =>
emp.id !== targetEmployeeId &&
emp.departmantId !== targetEmployee.departmantId
);
return otherDepartmentEmployees.map((emp) => ({
id: emp.id,
name: emp.fullName,
title: emp.jobPosition?.name,
department:
mockDepartments.find((d) => d.id === emp.departmantId)?.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.departmantId === 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.departmantId !== 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 (
<div className="mt-2 space-y-3">
{/* Header */}
<div className="flex justify-between items-center">
<div>
<h1 className="text-xl font-bold text-gray-900">
360° Değerlendirme Sistemi
</h1>
<p className="text-gray-600 mt-1">
Ç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>
<option value={CampaignStatusEnum.Draft}>Taslak</option>
<option value={CampaignStatusEnum.Active}>Aktif</option>
<option value={CampaignStatusEnum.Completed}>
Tamamlandı
</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.firstName} {employee.lastName}
</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>
<option value={ParticipantStatusEnum.Invited}>
Davet Edildi
</option>
<option value={ParticipantStatusEnum.Started}>
Başladı
</option>
<option value={ParticipantStatusEnum.Completed}>
Tamamlandı
</option>
<option value={ParticipantStatusEnum.Expired}>
Süresi Dolmuş
</option>
<option value={ParticipantStatusEnum.Declined}>
Reddedildi
</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>
{/* 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-sm 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-sm text-gray-600">
{employee.jobPosition?.name}
</p>
<p className="text-sm text-gray-600">
{
mockDepartments.find(
(d) => d.id === employee.departmantId
)?.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-sm 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-sm 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-sm 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-sm 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-sm 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>
)}
</div>
);
};
export default Degree360Evaluation;