import React, { useState, useMemo } from 'react' import { FaUser, FaChevronDown, FaChevronRight, FaChevronLeft, FaChevronRight as FaArrowRight, } from 'react-icons/fa' import { PsGanttTask } from '../../../types/ps' import { mockEmployees } from '../../../mocks/mockEmployees' import { mockProductionOrders } from '../../../mocks/mockProductionOrders' import { mockWorkOrders } from '../../../mocks/mockWorkOrders' import { mockWorkCenters } from '../../../mocks/mockWorkCenters' import { PriorityEnum } from '../../../types/common' import { getPriorityColor, getProductionOrderStatus, getWorkOrderStatus } from '../../../utils/erp' import { Container } from '@/components/shared' interface PlanningGanttProps { workCenterId?: string } const PlanningGantt: React.FC = ({ workCenterId }) => { const getInitialExpandedItems = () => { const expandedItems = new Set() const firstTwoOrders = mockProductionOrders.slice(0, 2) firstTwoOrders.forEach((order) => { expandedItems.add(`prod-${order.id}`) const orderWorkOrders = mockWorkOrders.filter((wo) => wo.productionOrderId === order.id) orderWorkOrders.forEach((wo) => { expandedItems.add(`work-${wo.id}`) }) }) return expandedItems } const [expandedItems, setExpandedItems] = useState>(getInitialExpandedItems()) const [selectedWorkCenter, setSelectedWorkCenter] = useState(workCenterId || '') const [viewMode, setViewMode] = useState<'day' | 'week' | 'month' | 'year'>('week') const [currentDate, setCurrentDate] = useState(new Date()) const generateDateRange = () => { const startDate = new Date(currentDate) if (viewMode === 'day') { const hours = [] for (let i = 0; i < 24; i++) { const hour = new Date(startDate) hour.setHours(i, 0, 0, 0) hours.push(hour) } return hours } else if (viewMode === 'week') { const weekStart = new Date(startDate) const dayOfWeek = weekStart.getDay() const daysToSubtract = dayOfWeek === 0 ? 6 : dayOfWeek - 1 weekStart.setDate(weekStart.getDate() - daysToSubtract) weekStart.setHours(0, 0, 0, 0) const dates = [] for (let i = 0; i < 7; i++) { const date = new Date(weekStart) date.setDate(weekStart.getDate() + i) dates.push(date) } return dates } else if (viewMode === 'month') { const monthStart = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1) const daysInMonth = new Date( currentDate.getFullYear(), currentDate.getMonth() + 1, 0, ).getDate() const dates = [] for (let i = 0; i < daysInMonth; i++) { const date = new Date(monthStart) date.setDate(monthStart.getDate() + i) dates.push(date) } return dates } else { const yearStart = new Date(currentDate.getFullYear(), 0, 1) const months = [] for (let i = 0; i < 12; i++) { const month = new Date(yearStart) month.setMonth(i) months.push(month) } return months } } const dateRange = generateDateRange() const filteredData = useMemo(() => { const createGanttData = (): PsGanttTask[] => { return mockProductionOrders.map((order) => { const workOrders = mockWorkOrders .filter((wo) => wo.productionOrderId === order.id) .map((wo) => ({ id: `work-${wo.id}`, name: wo.operation?.name || wo.workOrderNumber, type: 'task' as const, startDate: wo.plannedStartDate, endDate: wo.plannedEndDate, progress: Math.round((wo.confirmedQuantity / wo.plannedQuantity) * 100) || 0, assignee: wo.assignedOperators[0] ? mockEmployees.find((e) => e.id === wo.assignedOperators[0]) : undefined, status: getWorkOrderStatus(wo.status), priority: order.priority, level: 1, children: [], estimatedHours: wo.processTime / 60, hoursWorked: wo.actualProcessTime ? wo.actualProcessTime / 60 : 0, })) return { id: `prod-${order.id}`, name: `${order.orderNumber} - ${order.materials.map((m) => m.material?.name).join(', ')}`, type: 'project' as const, startDate: order.plannedStartDate, endDate: order.plannedEndDate, progress: order.confirmedQuantity && order.plannedQuantity ? Math.round((order.confirmedQuantity / order.plannedQuantity) * 100) : 0, status: getProductionOrderStatus(order.status), priority: order.priority, level: 0, children: workOrders, } }) } const filterByWorkCenter = (tasks: PsGanttTask[]): PsGanttTask[] => { if (!selectedWorkCenter) return tasks return tasks .map((task) => { if (task.type === 'task' && task.assignee?.id !== selectedWorkCenter) { return null } if (task.children) { const filteredChildren = filterByWorkCenter(task.children).filter( Boolean, ) as PsGanttTask[] if (filteredChildren.length > 0) { return { ...task, children: filteredChildren } } else if (task.type === 'task' && task.assignee?.id === selectedWorkCenter) { return task } return null } return task }) .filter(Boolean) as PsGanttTask[] } const allGanttTasks = createGanttData() return filterByWorkCenter(allGanttTasks) }, [selectedWorkCenter]) const toggleExpand = (id: string) => { const newExpanded = new Set(expandedItems) if (newExpanded.has(id)) { newExpanded.delete(id) } else { newExpanded.add(id) } setExpandedItems(newExpanded) } const navigatePrevious = () => { const newDate = new Date(currentDate) if (viewMode === 'day') newDate.setDate(newDate.getDate() - 1) else if (viewMode === 'week') newDate.setDate(newDate.getDate() - 7) else if (viewMode === 'month') newDate.setMonth(newDate.getMonth() - 1) else newDate.setFullYear(newDate.getFullYear() - 1) setCurrentDate(newDate) } const navigateNext = () => { const newDate = new Date(currentDate) if (viewMode === 'day') newDate.setDate(newDate.getDate() + 1) else if (viewMode === 'week') newDate.setDate(newDate.getDate() + 7) else if (viewMode === 'month') newDate.setMonth(newDate.getMonth() + 1) else newDate.setFullYear(newDate.getFullYear() + 1) setCurrentDate(newDate) } const navigateToday = () => { setCurrentDate(new Date()) } const getCurrentDateInfo = () => { if (viewMode === 'day') { return currentDate.toLocaleDateString('tr-TR', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', }) } else if (viewMode === 'week') { const weekStart = new Date(currentDate) const dayOfWeek = weekStart.getDay() const daysToSubtract = dayOfWeek === 0 ? 6 : dayOfWeek - 1 weekStart.setDate(weekStart.getDate() - daysToSubtract) const weekEnd = new Date(weekStart) weekEnd.setDate(weekStart.getDate() + 6) return `${weekStart.toLocaleDateString('tr-TR', { day: 'numeric', month: 'short', })} - ${weekEnd.toLocaleDateString('tr-TR', { day: 'numeric', month: 'short', year: 'numeric', })}` } else if (viewMode === 'month') { return currentDate.toLocaleDateString('tr-TR', { year: 'numeric', month: 'long', }) } else { return currentDate.toLocaleDateString('tr-TR', { year: 'numeric' }) } } const calculateTaskPosition = (startDate: Date, endDate: Date) => { const chartStart = dateRange[0] const chartEnd = dateRange[dateRange.length - 1] const taskStart = new Date(startDate) const taskEnd = new Date(endDate) if (viewMode === 'day') { const dayStart = new Date(chartStart) dayStart.setHours(0, 0, 0, 0) const dayEnd = new Date(chartStart) dayEnd.setHours(23, 59, 59, 999) if (taskEnd < dayStart || taskStart > dayEnd) return { left: '100%', width: '0%', isVisible: false } const startHour = taskStart > dayStart ? taskStart.getHours() + taskStart.getMinutes() / 60 : 0 const endHour = taskEnd < dayEnd ? taskEnd.getHours() + taskEnd.getMinutes() / 60 : 24 const left = (startHour / 24) * 100 const width = Math.max(1, ((endHour - startHour) / 24) * 100) return { left: `${left}%`, width: `${width}%`, isVisible: true } } else if (viewMode === 'week') { const weekStart = new Date(chartStart) const weekEnd = new Date(chartEnd) weekEnd.setHours(23, 59, 59, 999) if (taskEnd < weekStart || taskStart > weekEnd) return { left: '100%', width: '0%', isVisible: false } const startDay = taskStart > weekStart ? Math.floor((taskStart.getTime() - weekStart.getTime()) / (1000 * 60 * 60 * 24)) : 0 const endDay = taskEnd < weekEnd ? Math.ceil((taskEnd.getTime() - weekStart.getTime()) / (1000 * 60 * 60 * 24)) : 7 const left = (startDay / 7) * 100 const width = Math.max(1, ((endDay - startDay) / 7) * 100) return { left: `${left}%`, width: `${width}%`, isVisible: true } } else if (viewMode === 'month') { const monthStart = new Date(chartStart) const monthEnd = new Date(chartEnd) monthEnd.setHours(23, 59, 59, 999) if (taskEnd < monthStart || taskStart > monthEnd) return { left: '100%', width: '0%', isVisible: false } const daysInMonth = dateRange.length const startDay = taskStart > monthStart ? Math.floor((taskStart.getTime() - monthStart.getTime()) / (1000 * 60 * 60 * 24)) : 0 const endDay = taskEnd < monthEnd ? Math.ceil((taskEnd.getTime() - monthStart.getTime()) / (1000 * 60 * 60 * 24)) : daysInMonth const left = (startDay / daysInMonth) * 100 const width = Math.max(1, ((endDay - startDay) / daysInMonth) * 100) return { left: `${left}%`, width: `${width}%`, isVisible: true } } else { const yearStart = new Date(chartStart) const yearEnd = new Date(chartEnd) yearEnd.setMonth(11, 31) yearEnd.setHours(23, 59, 59, 999) if (taskEnd < yearStart || taskStart > yearEnd) return { left: '100%', width: '0%', isVisible: false } const startMonth = taskStart > yearStart ? taskStart.getMonth() : 0 const endMonth = taskEnd < yearEnd ? taskEnd.getMonth() + 1 : 12 const left = (startMonth / 12) * 100 const width = Math.max(1, ((endMonth - startMonth) / 12) * 100) return { left: `${left}%`, width: `${width}%`, isVisible: true } } } const renderTask = (task: PsGanttTask): React.ReactNode => { const hasChildren = task.children && task.children.length > 0 const isExpanded = expandedItems.has(task.id) const indent = task.level * 20 return (
{/* Task Info */}
{hasChildren && ( )} {!hasChildren &&
}
{task.name}
{task.type === 'task' && task.assignee && (
{task.assignee.firstName} {task.assignee.lastName} {task.hoursWorked && task.estimatedHours && ( {task.hoursWorked}h / {task.estimatedHours}h )}
)}
{task.startDate.toLocaleDateString('tr-TR')} -{' '} {task.endDate.toLocaleDateString('tr-TR')}
{/* Gantt Chart */}
{(() => { const position = calculateTaskPosition(task.startDate, task.endDate) if (task.type === 'task' && position.isVisible) { return (
{task.progress}%
{task.name}
İlerleme: {task.progress}% tamamlandı
Planlanan Başlangıç: {task.startDate.toLocaleDateString('tr-TR')}
Planlanan Bitiş: {task.endDate.toLocaleDateString('tr-TR')}
) } if (task.type !== 'task' && position.isVisible) { return (
{task.name}
Planlanan Başlangıç: {task.startDate.toLocaleDateString('tr-TR')}
Planlanan Bitiş: {task.endDate.toLocaleDateString('tr-TR')}
) } return null })()}
{hasChildren && isExpanded && task.children?.map((child) => renderTask(child))}
) } return (

Planlama Gantt Şeması

Üretim ve iş emirlerinizi zaman çizelgesinde yönetin.

{getCurrentDateInfo()}
Üretim Emri / İş Emri
{dateRange.map((date) => (
{viewMode === 'day' ? date.toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit', }) : viewMode === 'week' ? date.toLocaleDateString('tr-TR', { day: '2-digit' }) : viewMode === 'year' ? date.toLocaleDateString('tr-TR', { month: 'short' }) : date.toLocaleDateString('tr-TR', { day: '2-digit' })}
{viewMode !== 'day' && viewMode !== 'year' && (
{date.toLocaleDateString('tr-TR', { weekday: 'short' })}
)} {viewMode === 'year' && (
{date.getFullYear()}
)}
))}
{filteredData.map((task) => renderTask(task))}
) } export default PlanningGantt