erp-platform/ui/src/views/project/components/TaskViewModal.tsx
2025-09-16 00:02:48 +03:00

238 lines
7.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

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

import React from "react";
import {
FaTimes,
FaTasks,
FaCalendar,
FaUser,
FaChartLine,
} from "react-icons/fa";
import { mockProjectTasks } from "../../../mocks/mockProjectTasks";
import { PsProject, TaskStatusEnum } from "../../../types/ps";
import dayjs from "dayjs";
import { PriorityEnum } from "../../../types/common";
interface TaskViewModalProps {
project: PsProject;
isOpen: boolean;
onClose: () => void;
}
const statusConfig = {
[TaskStatusEnum.NotStarted]: {
name: "Başlamadı",
color: "bg-gray-100 text-gray-800",
},
[TaskStatusEnum.InProgress]: {
name: "Devam Ediyor",
color: "bg-yellow-100 text-yellow-800",
},
[TaskStatusEnum.Completed]: {
name: "Tamamlandı",
color: "bg-green-100 text-green-800",
},
[TaskStatusEnum.OnHold]: {
name: "Beklemede",
color: "bg-orange-100 text-orange-800",
},
[TaskStatusEnum.Cancelled]: {
name: "İptal Edildi",
color: "bg-red-100 text-red-800",
},
};
const priorityConfig = {
[PriorityEnum.Low]: { name: "Düşük", color: "bg-green-100 text-green-800" },
[PriorityEnum.Normal]: { name: "Normal", color: "bg-blue-100 text-blue-800" },
[PriorityEnum.High]: {
name: "Yüksek",
color: "bg-orange-100 text-orange-800",
},
[PriorityEnum.Urgent]: { name: "Acil", color: "bg-red-100 text-red-800" },
};
const Badge: React.FC<{ className?: string; children: React.ReactNode }> = ({
className,
children,
}) => (
<span
className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${className}`}
>
{children}
</span>
);
const TaskInfo: React.FC<{
icon: React.ElementType;
label: string;
value: string | number;
}> = ({ icon: Icon, label, value }) => (
<div className="flex items-center space-x-2">
<Icon className="h-4 w-4 text-gray-400" />
<div>
<p className="text-xs font-medium text-gray-700">{label}</p>
<p className="text-xs text-gray-600">{value}</p>
</div>
</div>
);
const ProgressBar: React.FC<{ progress: number }> = ({ progress }) => {
const getProgressColor = (p: number) => {
if (p >= 100) return "bg-green-500";
if (p >= 70) return "bg-blue-500";
if (p >= 50) return "bg-yellow-500";
return "bg-red-500";
};
return (
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span className="font-medium">İlerleme</span>
<span>%{progress}</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2">
<div
className={`h-2 rounded-full transition-all duration-300 ${getProgressColor(
progress
)}`}
style={{ width: `${progress}%` }}
/>
</div>
</div>
);
};
const TaskViewModal: React.FC<TaskViewModalProps> = ({
project,
isOpen,
onClose,
}) => {
if (!isOpen) return null;
const projectTasks = mockProjectTasks.filter(
(task) => task.projectId === project.id
);
return (
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div className="relative top-10 mx-auto p-2 border w-11/12 max-w-4xl shadow-lg rounded-md bg-white">
<div className="flex items-center justify-between p-2.5 border-b border-gray-200">
<div className="flex items-center">
<FaTasks className="h-6 w-6 text-blue-600 mr-3" />
<div>
<h3 className="text-lg font-semibold text-gray-900">
Proje Görevleri
</h3>
<p className="text-gray-600">
{project.name} - {project.code}
</p>
</div>
</div>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 focus:outline-none"
>
<FaTimes className="h-6 w-6" />
</button>
</div>
<div className="p-2.5 max-h-[75vh] overflow-y-auto">
{projectTasks.length > 0 ? (
<div className="space-y-3">
{projectTasks.map((task) => (
<div
key={task.id}
className="bg-white border border-gray-200 rounded-lg p-3 hover:shadow-md transition-shadow"
>
<div className="flex items-center flex-wrap gap-2 mb-2">
<h4 className="text-base font-medium text-gray-900 flex-shrink-0">
{task.name}
</h4>
<Badge className="bg-gray-200 text-gray-700">
{task.taskCode}
</Badge>
<Badge className={statusConfig[task.status]?.color}>
{statusConfig[task.status]?.name || "Bilinmiyor"}
</Badge>
<Badge
className={
priorityConfig[task.priority as PriorityEnum]?.color
}
>
{priorityConfig[task.priority as PriorityEnum]?.name ||
"Bilinmiyor"}
</Badge>
</div>
{task.description && (
<p className="text-sm text-gray-600 mb-3">
{task.description}
</p>
)}
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 mb-3 border-t border-b border-gray-100 py-2.5">
<TaskInfo
icon={FaCalendar}
label="Başlangıç"
value={dayjs(task.startDate).format("DD.MM.YYYY")}
/>
<TaskInfo
icon={FaCalendar}
label="Bitiş"
value={dayjs(task.endDate).format("DD.MM.YYYY")}
/>
<TaskInfo
icon={FaUser}
label="Atanan"
value={task.assignee?.fullName || "-"}
/>
<TaskInfo
icon={FaChartLine}
label="Tahmini Süre"
value={`${task.estimatedHours} saat`}
/>
</div>
<ProgressBar progress={task.progress} />
{task.actualHours > 0 && (
<div className="mt-2.5 pt-2.5 border-t border-gray-200">
<div className="flex justify-between text-sm">
<span className="text-gray-600">Gerçek Saat:</span>
<span className="font-medium">
{task.actualHours}h / {task.estimatedHours}h
</span>
</div>
</div>
)}
</div>
))}
</div>
) : (
<div className="text-center py-10">
<FaTasks className="mx-auto h-10 w-10 text-gray-400" />
<h3 className="mt-2 text-sm font-medium text-gray-900">
Görev bulunamadı
</h3>
<p className="mt-1 text-sm text-gray-500">
Bu proje için henüz görev tanımlanmamış.
</p>
</div>
)}
</div>
<div className="px-2.5 py-2 bg-gray-50 border-t border-gray-200 rounded-b-md">
<div className="flex justify-end">
<button
onClick={onClose}
className="px-3 py-1.5 bg-gray-600 text-white text-sm font-medium rounded-md hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-500"
>
Kapat
</button>
</div>
</div>
</div>
</div>
);
};
export default TaskViewModal;