import React, { useState, useEffect, useMemo } from 'react' import { FaUser, FaUsers, FaBuilding, FaChevronDown, FaChevronRight, FaEye, FaTh, FaSitemap, FaTimes, FaCalendar, FaEnvelope, FaPhone, FaMapMarkerAlt, FaBriefcase, } from 'react-icons/fa' import { HrEmployee, HrOrganizationChart as OrgChart } from '../../../types/hr' import { mockEmployees } from '../../../mocks/mockEmployees' import { mockDepartments } from '../../../mocks/mockDepartments' import Widget from '../../../components/common/Widget' import { Container } from '@/components/shared' // Dinamik organizasyon verisi oluşturma fonksiyonu const generateOrganizationData = (): OrgChart[] => { const orgData: OrgChart[] = [] // Çalışanları işle mockEmployees.forEach((employee) => { const department = mockDepartments.find((d) => d.id === employee.departmantId) let level = 3 // Varsayılan seviye (normal çalışan) let parentId: string | undefined = undefined // Eğer bu çalışan bir departman yöneticisiyse if (department && department.managerId === employee.id) { if (!department.parentDepartmentId) { // Ana departman yöneticisi (CEO/Genel Müdür) level = 0 } else { // Alt departman yöneticisi level = 1 // Üst departmanın yöneticisini parent olarak bul const parentDept = mockDepartments.find((d) => d.id === department.parentDepartmentId) if (parentDept && parentDept.managerId) { parentId = parentDept.managerId } } } else { // Normal çalışan - departman yöneticisine bağlı if (department && department.managerId) { parentId = department.managerId // Departman yöneticisinin seviyesine göre belirleme const managerDept = mockDepartments.find((d) => d.managerId === department.managerId) if (managerDept && !managerDept.parentDepartmentId) { level = 2 // CEO'ya direkt bağlı } else { level = 3 // Orta kademe yöneticiye bağlı } } } orgData.push({ id: `org-${employee.id}`, employeeId: employee.id, employee: employee, parentId: parentId, level: level, position: employee.jobPosition?.name || 'Belirsiz', isActive: employee.isActive, }) }) return orgData.sort((a, b) => a.level - b.level) } interface TreeNode { employee: HrEmployee children: TreeNode[] level: number } const OrganizationChart: React.FC = () => { const [employees] = useState(mockEmployees) const [organizationData] = useState(generateOrganizationData()) const [expandedNodes, setExpandedNodes] = useState>(new Set()) const [orgTree, setOrgTree] = useState([]) const [viewMode, setViewMode] = useState<'tree' | 'cards'>('tree') const [selectedEmployee, setSelectedEmployee] = useState(null) const [showModal, setShowModal] = useState(false) const [selectedDepartment, setSelectedDepartment] = useState('all') const handleViewEmployee = (employee: HrEmployee) => { setSelectedEmployee(employee) setShowModal(true) } const handleCloseModal = () => { setShowModal(false) setSelectedEmployee(null) } useEffect(() => { // Build organization tree structure const buildTree = (): TreeNode[] => { const nodeMap = new Map() // First, create all nodes employees.forEach((employee) => { nodeMap.set(employee.id, { employee, children: [], level: 0, }) }) // Then, build the tree structure const rootNodes: TreeNode[] = [] organizationData.forEach((orgData) => { const node = nodeMap.get(orgData.employeeId) if (node) { node.level = orgData.level if (orgData.parentId) { const parentNode = nodeMap.get(orgData.parentId) if (parentNode) { parentNode.children.push(node) } } else { rootNodes.push(node) } } }) return rootNodes } setOrgTree(buildTree()) // Auto-expand first level const firstLevelIds = organizationData .filter((org) => org.level <= 1) .map((org) => org.employeeId) setExpandedNodes(new Set(firstLevelIds)) }, [employees, organizationData]) // Filtered data for views const filteredOrgTree = useMemo(() => { if (selectedDepartment === 'all') { return orgTree } const filterTree = (nodes: TreeNode[]): TreeNode[] => { const result: TreeNode[] = [] for (const node of nodes) { const filteredChildren = filterTree(node.children) if (node.employee.departmantId === selectedDepartment || filteredChildren.length > 0) { result.push({ ...node, children: filteredChildren }) } } return result } return filterTree(orgTree) }, [orgTree, selectedDepartment]) const filteredEmployees = useMemo(() => { if (selectedDepartment === 'all') { return employees } return employees.filter((emp) => emp.departmantId === selectedDepartment) }, [employees, selectedDepartment]) const toggleNode = (nodeId: string) => { const newExpanded = new Set(expandedNodes) if (newExpanded.has(nodeId)) { newExpanded.delete(nodeId) } else { newExpanded.add(nodeId) } setExpandedNodes(newExpanded) } const renderTreeNode = (node: TreeNode): React.ReactNode => { const isExpanded = expandedNodes.has(node.employee.id) const hasChildren = node.children.length > 0 return (
{/* Bağlantı çizgisi */} {node.level > 0 && ( )}
{/* Girinti ve bağlantı çizgisi */} {node.level > 0 && ( )} {/* Genişletme ikonu */}
{hasChildren && ( )}
{/* Grup Bilgisi */}

{node.employee.fullName}

{node.employee.jobPosition?.name}

{node.employee.department?.name}

{hasChildren && ( {node.children.length} )}
{hasChildren && isExpanded && (
{node.children.map((child) => renderTreeNode(child))}
)}
) } const renderCardView = () => { const groupedByLevel = filteredEmployees.reduce( (acc, employee) => { const orgData = organizationData.find((org) => org.employeeId === employee.id) const level = orgData?.level || 0 if (!acc[level]) { acc[level] = [] } acc[level].push(employee) return acc }, {} as Record, ) return (
{Object.entries(groupedByLevel) .sort(([a], [b]) => parseInt(a) - parseInt(b)) .map(([level, levelEmployees]) => (

{level === '0' ? 'Üst Yönetim' : level === '1' ? 'Orta Kademe Yönetim' : level === '2' ? 'Alt Kademe Yönetim' : `${parseInt(level) + 1}. Seviye`} {levelEmployees.length} kişi

{levelEmployees.map((employee) => (

handleViewEmployee(employee)} className="font-medium text-sm text-blue-600 hover:underline cursor-pointer truncate" > {employee.fullName}

{employee.code}

{employee.jobPosition?.name}

{employee.department?.name}

))}
))}
) } return (
{/* Header */}

Organizasyon Şeması

Kurumsal hiyerarşi ve raporlama yapısı

{/* Stats */}
e.department?.id).filter(Boolean)).size} color="purple" icon="FaBuilding" /> 0 ? Math.max(...organizationData.map((org) => org.level)) + 1 : 0 } color="orange" icon="FaUser" />
{/* Content */}
{viewMode === 'tree' ? (
{filteredOrgTree.map((node) => renderTreeNode(node))}
) : ( renderCardView() )} {(viewMode === 'tree' ? filteredOrgTree.length === 0 : filteredEmployees.length === 0) && (

Organizasyon verisi bulunamadı

Henüz organizasyon şeması oluşturulmamış.

)}
{/* Employee Detail Modal */} {showModal && selectedEmployee && (
{/* Modal Header */}

Personel Detayları

{/* Employee Info */}
{/* Basic Info */}

{selectedEmployee.fullName}

{selectedEmployee.code}

{selectedEmployee.jobPosition?.name}

{/* Contact Information */}
İletişim Bilgileri
E-posta: {selectedEmployee.email}
{selectedEmployee.phone && (
İş Telefonu: {selectedEmployee.phone}
)} {selectedEmployee.personalPhone && (
Kişisel Telefon: {selectedEmployee.personalPhone}
)}
{/* Employment Information */}
İş Bilgileri
Departman:

{selectedEmployee.department?.name}

Pozisyon:

{selectedEmployee.jobPosition?.name}

İşe Başlama Tarihi:

{new Date(selectedEmployee.hireDate).toLocaleDateString('tr-TR')}

İstihdam Türü:

{selectedEmployee.employmentType}

Çalışma Lokasyonu:

{selectedEmployee.workLocation}

Durum: {selectedEmployee.isActive ? 'Aktif' : 'Pasif'}
{/* Personal Information */}
Kişisel Bilgiler
Doğum Tarihi:

{new Date(selectedEmployee.birthDate).toLocaleDateString('tr-TR')}

Cinsiyet:

{selectedEmployee.gender}

Medeni Durum:

{selectedEmployee.maritalStatus}

TC Kimlik No:

{selectedEmployee.nationalId}

{selectedEmployee.address && (
Adres:

{selectedEmployee.address.street}, {selectedEmployee.address.city},{' '} {selectedEmployee.address.country}

)}
{/* Emergency Contact */} {selectedEmployee.emergencyContact && (
Acil Durum İletişim
İsim:

{selectedEmployee.emergencyContact.name}

Yakınlık:

{selectedEmployee.emergencyContact.relationship}

Telefon:

{selectedEmployee.emergencyContact.phone}

)}
{/* Modal Footer */}
)}
) } export default OrganizationChart