From 68482e0a8db6c7cba264c7f85bfdb6cdc0f9605c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Sat, 25 Oct 2025 22:32:31 +0300 Subject: [PATCH] Hr Visitors Dashboard --- ui/src/mocks/mockIntranet.ts | 137 ++++++------------ ui/src/mocks/mockProjectTasks.ts | 52 +++++++ ui/src/views/intranet/Dashboard.tsx | 2 + ui/src/views/intranet/modals/SurveyModal.tsx | 2 +- .../views/intranet/widgets/PriorityTasks.tsx | 40 ++--- ui/src/views/intranet/widgets/Visitors.tsx | 113 +++++++++++++++ 6 files changed, 234 insertions(+), 112 deletions(-) create mode 100644 ui/src/views/intranet/widgets/Visitors.tsx diff --git a/ui/src/mocks/mockIntranet.ts b/ui/src/mocks/mockIntranet.ts index a28c6581..a0e52b7e 100644 --- a/ui/src/mocks/mockIntranet.ts +++ b/ui/src/mocks/mockIntranet.ts @@ -6,7 +6,6 @@ import { Document, Certificate, ExpenseRequest, - Task, Training, Reservation, MealMenu, @@ -15,97 +14,6 @@ import { SocialPost, } from '@/types/intranet' - -export const mockExpenseRequests: ExpenseRequest[] = [ - { - id: 'exp1', - employee: mockEmployees[0], - category: 'travel', - amount: 850, - currency: 'TRY', - date: new Date('2024-10-15'), - description: 'Ankara ofis ziyareti - uçak bileti', - project: 'Intranet v2', - receipts: [{ name: 'ucak_bileti.pdf', url: '#', size: '234 KB' }], - status: 'approved', - approver: mockEmployees[4], - approvalDate: new Date('2024-10-16T10:00:00'), - creationTime: new Date('2024-10-15T18:00:00'), - }, - { - id: 'exp2', - employee: mockEmployees[2], - category: 'meal', - amount: 320, - currency: 'TRY', - date: new Date('2024-10-17'), - description: 'Müşteri toplantısı - öğle yemeği', - receipts: [{ name: 'restoran_fisi.jpg', url: '#', size: '156 KB' }], - status: 'pending', - creationTime: new Date('2024-10-17T20:00:00'), - }, - { - id: 'exp3', - employee: mockEmployees[1], - category: 'accommodation', - amount: 1200, - currency: 'TRY', - date: new Date('2024-10-14'), - description: 'İzmir workshop - otel konaklaması (2 gece)', - project: 'UX Workshop', - receipts: [{ name: 'otel_fatura.pdf', url: '#', size: '445 KB' }], - status: 'approved', - approver: mockEmployees[4], - approvalDate: new Date('2024-10-15T09:00:00'), - creationTime: new Date('2024-10-14T22:00:00'), - }, -] - -export const mockTasks: Task[] = [ - { - id: 'task1', - title: 'API Endpoint Geliştirme', - description: "Kullanıcı yönetimi için RESTful API endpoint'leri oluşturulacak", - project: 'Intranet v2', - assignedTo: [mockEmployees[0]], - assignedBy: mockEmployees[4], - priority: 'high', - status: 'in-progress', - dueDate: new Date('2024-10-25'), - creationTime: new Date('2024-10-14'), - labels: ['backend', 'api'], - comments: 3, - }, - { - id: 'task2', - title: 'Dashboard UI Tasarımı', - description: 'Yeni dashboard için UI/UX tasarımı yapılacak', - project: 'Intranet v2', - assignedTo: [mockEmployees[1]], - assignedBy: mockEmployees[4], - priority: 'medium', - status: 'review', - dueDate: new Date('2024-10-22'), - creationTime: new Date('2024-10-10'), - labels: ['design', 'ui/ux'], - comments: 5, - }, - { - id: 'task3', - title: 'Kubernetes Deployment', - description: 'Production ortamı için Kubernetes yapılandırması', - project: 'Infrastructure', - assignedTo: [mockEmployees[2]], - assignedBy: mockEmployees[4], - priority: 'urgent', - status: 'todo', - dueDate: new Date('2024-10-20'), - creationTime: new Date('2024-10-17'), - labels: ['devops', 'infrastructure'], - comments: 1, - }, -] -2 export const mockDocuments: Document[] = [ { id: 'doc1', @@ -979,4 +887,49 @@ export const mockVisitors: Visitor[] = [ badgeNumber: 'V-002', photo: 'https://i.pravatar.cc/150?img=68', }, +] + +export const mockExpenseRequests: ExpenseRequest[] = [ + { + id: 'exp1', + employee: mockEmployees[0], + category: 'travel', + amount: 850, + currency: 'TRY', + date: new Date('2024-10-15'), + description: 'Ankara ofis ziyareti - uçak bileti', + project: 'Intranet v2', + receipts: [{ name: 'ucak_bileti.pdf', url: '#', size: '234 KB' }], + status: 'approved', + approver: mockEmployees[4], + approvalDate: new Date('2024-10-16T10:00:00'), + creationTime: new Date('2024-10-15T18:00:00'), + }, + { + id: 'exp2', + employee: mockEmployees[2], + category: 'meal', + amount: 320, + currency: 'TRY', + date: new Date('2024-10-17'), + description: 'Müşteri toplantısı - öğle yemeği', + receipts: [{ name: 'restoran_fisi.jpg', url: '#', size: '156 KB' }], + status: 'pending', + creationTime: new Date('2024-10-17T20:00:00'), + }, + { + id: 'exp3', + employee: mockEmployees[1], + category: 'accommodation', + amount: 1200, + currency: 'TRY', + date: new Date('2024-10-14'), + description: 'İzmir workshop - otel konaklaması (2 gece)', + project: 'UX Workshop', + receipts: [{ name: 'otel_fatura.pdf', url: '#', size: '445 KB' }], + status: 'approved', + approver: mockEmployees[4], + approvalDate: new Date('2024-10-15T09:00:00'), + creationTime: new Date('2024-10-14T22:00:00'), + }, ] \ No newline at end of file diff --git a/ui/src/mocks/mockProjectTasks.ts b/ui/src/mocks/mockProjectTasks.ts index 5084bbfc..6e6ac06e 100644 --- a/ui/src/mocks/mockProjectTasks.ts +++ b/ui/src/mocks/mockProjectTasks.ts @@ -82,4 +82,56 @@ export const mockProjectTasks: PsProjectTask[] = [ creationTime: new Date("2024-01-15"), lastModificationTime: new Date("2024-02-08"), }, + { + id: "4", + projectId: "1", + phaseId: "1", + phase: mockProjectPhases.find((phase) => phase.id === "1"), + taskCode: "TSK-004", + name: "Güvenlik Açığı Düzeltme", + description: "Kritik güvenlik açığının acil olarak düzeltilmesi gerekiyor", + taskType: TaskTypeEnum.Development, + status: TaskStatusEnum.InProgress, + priority: PriorityEnum.Urgent, + assignedTo: "1", + assignee: mockEmployees.find((emp) => emp.id === "1"), + startDate: new Date("2024-10-20"), + endDate: new Date("2024-10-25"), + actualStartDate: new Date("2024-10-20"), + actualEndDate: undefined, + estimatedHours: 20, + actualHours: 8, + progress: 40, + activities: [], + comments: [], + isActive: true, + creationTime: new Date("2024-10-20"), + lastModificationTime: new Date("2024-10-20"), + }, + { + id: "5", + projectId: "2", + phaseId: "2", + phase: mockProjectPhases.find((phase) => phase.id === "2"), + taskCode: "TSK-005", + name: "Performans Optimizasyonu", + description: "Uygulama performansının iyileştirilmesi", + taskType: TaskTypeEnum.Development, + status: TaskStatusEnum.NotStarted, + priority: PriorityEnum.High, + assignedTo: "2", + assignee: mockEmployees.find((emp) => emp.id === "2"), + startDate: new Date("2024-10-28"), + endDate: new Date("2024-11-15"), + actualStartDate: undefined, + actualEndDate: undefined, + estimatedHours: 100, + actualHours: 0, + progress: 0, + activities: [], + comments: [], + isActive: true, + creationTime: new Date("2024-10-15"), + lastModificationTime: new Date("2024-10-15"), + }, ]; diff --git a/ui/src/views/intranet/Dashboard.tsx b/ui/src/views/intranet/Dashboard.tsx index f735bf36..7e015e05 100644 --- a/ui/src/views/intranet/Dashboard.tsx +++ b/ui/src/views/intranet/Dashboard.tsx @@ -19,6 +19,7 @@ import ExpenseManagement from './widgets/ExpenseManagement' import UpcomingTrainings from './widgets/UpcomingTrainings' import ActiveReservations from './widgets/ActiveReservations' import ActiveSurveys from './widgets/ActiveSurveys' +import Visitors from './widgets/Visitors' // Modals import SurveyModal from './modals/SurveyModal' @@ -92,6 +93,7 @@ const IntranetDashboard: React.FC = () => { setShowReservationModal(true)} /> +
diff --git a/ui/src/views/intranet/modals/SurveyModal.tsx b/ui/src/views/intranet/modals/SurveyModal.tsx index bf588667..ffc1d692 100644 --- a/ui/src/views/intranet/modals/SurveyModal.tsx +++ b/ui/src/views/intranet/modals/SurveyModal.tsx @@ -1,7 +1,7 @@ import React from 'react' import { motion } from 'framer-motion' import { FaTimes } from 'react-icons/fa' -import { Survey } from '../../../mocks/mockIntranet' +import { Survey } from '@/types/intranet' interface SurveyModalProps { survey: Survey diff --git a/ui/src/views/intranet/widgets/PriorityTasks.tsx b/ui/src/views/intranet/widgets/PriorityTasks.tsx index c112705f..4b120f21 100644 --- a/ui/src/views/intranet/widgets/PriorityTasks.tsx +++ b/ui/src/views/intranet/widgets/PriorityTasks.tsx @@ -1,19 +1,21 @@ import React from 'react' -import { FaChartBar, FaClock, FaUsers } from 'react-icons/fa' +import { FaChartBar, FaClock, FaUser } from 'react-icons/fa' import dayjs from 'dayjs' -import { mockTasks } from '../../../mocks/mockIntranet' +import { mockProjectTasks } from '../../../mocks/mockProjectTasks' +import { PriorityEnum } from '../../../types/common' +import { TaskStatusEnum } from '../../../types/ps' const PriorityTasks: React.FC = () => { - const priorityTasks = mockTasks - .filter((t) => t.priority === 'high' || t.priority === 'urgent') + const priorityTasks = mockProjectTasks + .filter((t) => t.priority === PriorityEnum.High || t.priority === PriorityEnum.Urgent) .slice(0, 3) - const getPriorityColor = (priority: string) => { - const colors: Record = { - low: 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-300', - medium: 'bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-300', - high: 'bg-orange-100 dark:bg-orange-900/30 text-orange-600 dark:text-orange-300', - urgent: 'bg-red-100 dark:bg-red-900/30 text-red-600 dark:text-red-300', + const getPriorityColor = (priority: PriorityEnum) => { + const colors: Record = { + [PriorityEnum.Low]: 'bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-300', + [PriorityEnum.Normal]: 'bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-300', + [PriorityEnum.High]: 'bg-orange-100 dark:bg-orange-900/30 text-orange-600 dark:text-orange-300', + [PriorityEnum.Urgent]: 'bg-red-100 dark:bg-red-900/30 text-red-600 dark:text-red-300', } return colors[priority] } @@ -33,21 +35,21 @@ const PriorityTasks: React.FC = () => {

- {task.title} + {task.name}

- {task.priority === 'urgent' && '🔥 Acil'} - {task.priority === 'high' && 'Yüksek'} - {task.priority === 'medium' && 'Orta'} - {task.priority === 'low' && 'Düşük'} + {task.priority === PriorityEnum.Urgent && '🔥 Acil'} + {task.priority === PriorityEnum.High && 'Yüksek'} + {task.priority === PriorityEnum.Normal && 'Orta'} + {task.priority === PriorityEnum.Low && 'Düşük'}

@@ -56,11 +58,11 @@ const PriorityTasks: React.FC = () => {

- {dayjs(task.dueDate).format('DD MMM')} + {dayjs(task.endDate).format('DD MMM')} - - {task.assignedTo.length} kişi + + {task.assignee?.firstName || 'Atanmadı'}
diff --git a/ui/src/views/intranet/widgets/Visitors.tsx b/ui/src/views/intranet/widgets/Visitors.tsx new file mode 100644 index 00000000..c51d2188 --- /dev/null +++ b/ui/src/views/intranet/widgets/Visitors.tsx @@ -0,0 +1,113 @@ +import React from 'react' +import { FaUser, FaUserCheck, FaUserClock } from 'react-icons/fa' +import dayjs from 'dayjs' +import { mockVisitors } from '../../../mocks/mockIntranet' + +const Visitors: React.FC = () => { + const todayVisitors = mockVisitors.filter((visitor) => + dayjs(visitor.visitDate).isSame(dayjs(), 'day') + ) + + const getStatusIcon = (status: string) => { + switch (status) { + case 'checked-in': + return + case 'checked-out': + return + case 'scheduled': + return + default: + return + } + } + + const getStatusText = (status: string) => { + switch (status) { + case 'checked-in': + return 'Giriş Yaptı' + case 'checked-out': + return 'Çıkış Yaptı' + case 'scheduled': + return 'Planlandı' + default: + return 'Bilinmiyor' + } + } + + const getStatusColor = (status: string) => { + switch (status) { + case 'checked-in': + return 'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800' + case 'checked-out': + return 'bg-gray-50 dark:bg-gray-900/20 border-gray-200 dark:border-gray-700' + case 'scheduled': + return 'bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800' + default: + return 'bg-gray-50 dark:bg-gray-900/20 border-gray-200 dark:border-gray-700' + } + } + + return ( +
+
+

+ + Bugünkü Ziyaretçiler +

+
+
+ {todayVisitors.length > 0 ? ( + todayVisitors.map((visitor) => ( +
+
+ {visitor.fullName} +
+
+

+ {visitor.fullName} +

+
+ {getStatusIcon(visitor.status)} +
+
+

+ {visitor.company} +

+

+ {visitor.purpose} +

+
+ + {dayjs(visitor.visitDate).format('HH:mm')} + + + {getStatusText(visitor.status)} + +
+ {visitor.host && ( +

+ Karşılayan: {visitor.host.fullName} +

+ )} +
+
+
+ )) + ) : ( +

+ Bugün ziyaretçi yok +

+ )} +
+
+ ) +} + +export default Visitors \ No newline at end of file