diff --git a/ui/src/views/Dashboard.tsx b/ui/src/views/Dashboard.tsx index 3e14eb8a..95a0d659 100644 --- a/ui/src/views/Dashboard.tsx +++ b/ui/src/views/Dashboard.tsx @@ -1,64 +1,9 @@ import { useLocalization } from '@/utils/hooks/useLocalization' import { Helmet } from 'react-helmet' -import { useState } from 'react' -import IntranetSidebar from './intranet/Sidebar' -import LeaveManagement from './intranet/HR/LeaveManagement' -import OvertimeManagement from './intranet/HR/OvertimeManagement' -import ExpenseManagement from './intranet/HR/ExpenseManagement' -import EventsModule from './intranet/Event' -import DocumentsModule from './intranet/Document' -import TasksModule from './intranet/Task' -import SocialWall from './intranet/SocialWall' -import BirthdaysModule from './intranet/Birthday' -import TrainingModule from './intranet/Training' -import ReservationsModule from './intranet/Reservation' -import CafeteriaModule from './intranet/Cafeteria' -import SurveysModule from './intranet/Survey' -import VisitorsModule from './intranet/Visitor' -import AnnouncementsModule from './intranet/Announcement' import IntranetDashboard from './intranet/Dashboard' const Dashboard = () => { const { translate } = useLocalization() - const [currentPath, setCurrentPath] = useState('/intranet/dashboard') - - const renderContent = () => { - switch (currentPath) { - case '/intranet/dashboard': - return - case '/intranet/social': - return - case '/intranet/hr/leave': - return - case '/intranet/hr/overtime': - return - case '/intranet/hr/expense': - return - case '/intranet/announcements': - return - case '/intranet/events': - return - case '/intranet/documents': - return - case '/intranet/tasks': - return - case '/intranet/birthdays': - return - case '/intranet/training': - return - case '/intranet/reservations': - return - case '/intranet/cafeteria/menu': - case '/intranet/cafeteria/shuttle': - return - case '/intranet/surveys': - return - case '/intranet/visitors': - return - default: - return - } - } return ( <> @@ -68,9 +13,8 @@ const Dashboard = () => { defaultTitle="Sözsoft Kurs Platform" />
-
- {renderContent()} +
diff --git a/ui/src/views/intranet/Dashboard.tsx b/ui/src/views/intranet/Dashboard.tsx index 548460b6..26e03864 100644 --- a/ui/src/views/intranet/Dashboard.tsx +++ b/ui/src/views/intranet/Dashboard.tsx @@ -7,13 +7,18 @@ import { HiChartBar as ChartBarIcon, HiUserGroup as UserGroupIcon, HiClock as ClockIcon, - HiSparkles as SparklesIcon, - HiArrowTrendingUp as ArrowTrendingUpIcon, - HiArrowTrendingDown as ArrowTrendingDownIcon, HiXMark, HiEye, HiPaperClip, + HiTruck as TruckIcon, + HiAcademicCap as AcademicCapIcon, + HiKey as KeyIcon, + HiClipboardDocumentCheck as ClipboardIcon, + HiPlus, + HiCurrencyDollar, + HiArrowDownTray, } from 'react-icons/hi2' +import { IoRestaurant as RestaurantIcon } from 'react-icons/io5' import dayjs from 'dayjs' import 'dayjs/locale/tr' import relativeTime from 'dayjs/plugin/relativeTime' @@ -23,19 +28,34 @@ import { mockEvents, mockBirthdays, mockAnniversaries, - mockQuickLinks, mockTasks, mockDocuments, + mockMealMenus, + mockShuttleRoutes, + mockTrainings, + mockReservations, + mockSurveys, + mockLeaveRequests, + mockOvertimeRequests, + mockExpenseRequests, Announcement, + Survey, } from '../../mocks/mockIntranetData' +import { LeaveStatusEnum, LeaveTypeEnum } from '../../types/hr' +import SocialWall from './SocialWall' dayjs.locale('tr') dayjs.extend(relativeTime) dayjs.extend(isBetween) const IntranetDashboard: React.FC = () => { - const [selectedDate] = useState(new Date()) const [selectedAnnouncement, setSelectedAnnouncement] = useState(null) + const [showSurveyModal, setShowSurveyModal] = useState(false) + const [selectedSurvey, setSelectedSurvey] = useState(null) + const [showLeaveModal, setShowLeaveModal] = useState(false) + const [showOvertimeModal, setShowOvertimeModal] = useState(false) + const [showExpenseModal, setShowExpenseModal] = useState(false) + const [showReservationModal, setShowReservationModal] = useState(false) // Bugünün etkinlikleri const todayEvents = mockEvents.filter( @@ -82,6 +102,36 @@ const IntranetDashboard: React.FC = () => { // Sabitlenmiş duyurular const pinnedAnnouncements = mockAnnouncements.filter((a) => a.isPinned).slice(0, 3) + // Handler fonksiyonları + const handleTakeSurvey = (survey: Survey) => { + setSelectedSurvey(survey) + setShowSurveyModal(true) + } + + const handleSubmitSurvey = () => { + setShowSurveyModal(false) + setSelectedSurvey(null) + // TODO: Başarı bildirimi göster + } + + // Bu haftanın menüleri + const weekMenus = mockMealMenus.filter((menu) => { + const menuDate = dayjs(menu.date) + const today = dayjs() + const weekStart = today.startOf('week') + const weekEnd = today.endOf('week') + return menuDate.isBetween(weekStart, weekEnd, null, '[]') + }) + + // Bugünün menüsü + const todayMenu = mockMealMenus.find((menu) => dayjs(menu.date).isSame(dayjs(), 'day')) + + // Sabah servisleri + const morningShuttles = mockShuttleRoutes.filter((s) => s.type === 'morning') + + // Akşam servisleri + const eveningShuttles = mockShuttleRoutes.filter((s) => s.type === 'evening') + const getCategoryColor = (category: string) => { const colors: Record = { general: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300', @@ -104,164 +154,21 @@ const IntranetDashboard: React.FC = () => { } return ( -
-
+
+
{/* Header */} -
+

- Hoş geldiniz, {dayjs().format('DD MMMM YYYY dddd')} + Hoş geldiniz, {dayjs().format('DD MMMM YYYY dddd')}

-
- -
- {/* Main Grid */} -
- {/* Sol Kolon - Duyurular */} + {/* Main Grid - 3 Kolon: Sol (2/6), Orta (5/6), Sağ (3/6) */} +
+ {/* Sol Kolon (1/6) */}
- {/* Duyurular */} -
-
-
-

- - Önemli Duyurular -

- -
-
-
- {pinnedAnnouncements.map((announcement) => ( -
setSelectedAnnouncement(announcement)} - className="p-6 hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer transition-colors" - > -
- {announcement.author.fullName} -
-
-

- {announcement.title} -

- - {announcement.category === 'general' && 'Genel'} - {announcement.category === 'hr' && 'İK'} - {announcement.category === 'it' && 'IT'} - {announcement.category === 'event' && 'Etkinlik'} - {announcement.category === 'urgent' && 'Acil'} - -
-

- {announcement.excerpt} -

-
- {announcement.author.fullName} - - {dayjs(announcement.publishDate).fromNow()} - - {announcement.viewCount} görüntülenme -
-
-
-
- ))} -
-
- - {/* Hızlı Erişim */} -
-

- - Hızlı Erişim -

-
- {mockQuickLinks.map((link) => ( - - {link.icon} - - {link.name} - - - ))} -
-
- - {/* Öncelikli Görevler */} -
-
-

- - Öncelikli Görevler -

-
-
- {priorityTasks.map((task) => ( -
-
- -
-
-

- {task.title} -

- - {task.priority === 'urgent' && '🔥 Acil'} - {task.priority === 'high' && 'Yüksek'} - {task.priority === 'medium' && 'Orta'} - {task.priority === 'low' && 'Düşük'} - -
-

- {task.description} -

-
- - - {dayjs(task.dueDate).format('DD MMM')} - - - - {task.assignedTo.length} kişi - -
-
-
-
- ))} -
-
-
- - {/* Sağ Kolon - Etkinlikler & Kutlamalar */} -
{/* Bugünün Etkinlikleri */}
@@ -367,7 +274,7 @@ const IntranetDashboard: React.FC = () => {
- {/* Dokümanlar */} + {/* Son Dokümanlar */}
@@ -375,20 +282,17 @@ const IntranetDashboard: React.FC = () => { Son Dokümanlar -
- {mockDocuments.slice(0, 5).map((doc) => ( + {mockDocuments.slice(0, 3).map((doc) => (
- +

@@ -398,23 +302,36 @@ const IntranetDashboard: React.FC = () => { {doc.category === 'policy' && '📋 Politika'} {doc.category === 'procedure' && '📝 Prosedür'} {doc.category === 'form' && '📄 Form'} - {doc.category === 'template' && '� Şablon'} + {doc.category === 'template' && '📋 Şablon'} {doc.category === 'report' && '📊 Rapor'} {doc.category === 'other' && '📄 Diğer'} + + {doc.size}

-
+
{dayjs(doc.uploadDate).fromNow()} - {doc.size} + {doc.downloadCount} indirme
+

))}
- {/* Doğum Günleri */} + {/* Bu Hafta Doğanlar */} {weekBirthdays.length > 0 && (
@@ -423,7 +340,7 @@ const IntranetDashboard: React.FC = () => {
- {weekBirthdays.map((birthday, index) => ( + {weekBirthdays.slice(0, 3).map((birthday, index) => (
{ {birthday.employee.fullName}

- {dayjs(birthday.date).format('DD MMMM')} • {birthday.age} yaşında + {dayjs(birthday.date).format('DD MMM')}

@@ -453,7 +370,7 @@ const IntranetDashboard: React.FC = () => {
- {monthAnniversaries.map((anniversary, index) => ( + {monthAnniversaries.slice(0, 3).map((anniversary, index) => (
{ {anniversary.employee.fullName}

- {anniversary.years} yıldır bizimle! 🎊 + {anniversary.years} yıl 🎊

@@ -473,10 +390,1224 @@ const IntranetDashboard: React.FC = () => {
)} + + {/* Yaklaşan Eğitimler */} +
+
+

+ + Yaklaşan Eğitimler +

+
+
+ {mockTrainings + .filter((t) => t.status === 'upcoming') + .slice(0, 3) + .map((training) => ( +
+

+ {training.title} +

+

+ {training.instructor} • {training.duration} +

+
+ + {dayjs(training.startDate).format('DD MMM')} - {dayjs(training.endDate).format('DD MMM')} + + + {training.enrolled}/{training.maxParticipants} + +
+
+ ))} + {mockTrainings.filter((t) => t.status === 'upcoming').length === 0 && ( +

+ Yaklaşan eğitim yok +

+ )} +
+
+ + {/* Aktif Rezervasyonlar */} +
+
+

+ + Aktif Rezervasyonlar +

+
+
+ {mockReservations + .filter((r) => r.status === 'approved') + .slice(0, 3) + .map((reservation) => ( +
+
+

+ {reservation.resourceName} +

+ + {reservation.type === 'room' ? '🏢' : reservation.type === 'vehicle' ? '🚗' : '⚙️'} + +
+

+ {dayjs(reservation.startDate).format('DD MMM HH:mm')} - {dayjs(reservation.endDate).format('HH:mm')} +

+
+ ))} + {mockReservations.filter((r) => r.status === 'approved').length === 0 && ( +

+ Aktif rezervasyon yok +

+ )} + + +
+
+ + {/* Aktif Anketler */} +
+
+

+ + Aktif Anketler +

+
+
+ {mockSurveys + .filter((s) => s.status === 'active') + .slice(0, 3) + .map((survey) => ( +
handleTakeSurvey(survey)} + className="p-3 rounded-lg bg-purple-50 dark:bg-purple-900/20 border border-purple-200 dark:border-purple-800 hover:bg-purple-100 dark:hover:bg-purple-900/30 cursor-pointer transition-colors" + > +

+ {survey.title} +

+
+ + {survey.totalQuestions} soru + + + {survey.responses} yanıt + +
+

+ Son tarih: {dayjs(survey.deadline).format('DD MMM')} +

+ +
+ ))} + {mockSurveys.filter((s) => s.status === 'active').length === 0 && ( +

+ Aktif anket yok +

+ )} +
+
+
+ + {/* Orta Kolon (4/6) - Sadece Sosyal Duvar */} +
+ {/* Sosyal Duvar */} + +
+ + {/* Sağ Kolon (1/6) */} +
+ {/* Önemli Duyurular */} +
+
+
+

+ + Önemli Duyurular +

+
+
+
+ {pinnedAnnouncements.map((announcement) => ( +
setSelectedAnnouncement(announcement)} + className="p-6 hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer transition-colors" + > +
+ {announcement.author.fullName} +
+
+

+ {announcement.title} +

+ + {announcement.category === 'general' && 'Genel'} + {announcement.category === 'hr' && 'İK'} + {announcement.category === 'it' && 'IT'} + {announcement.category === 'event' && 'Etkinlik'} + {announcement.category === 'urgent' && 'Acil'} + +
+

+ {announcement.excerpt} +

+
+ {announcement.author.fullName} + + {dayjs(announcement.publishDate).fromNow()} + + {announcement.viewCount} görüntülenme +
+
+
+
+ ))} +
+
+ {/* Öncelikli Görevler */} +
+
+

+ + Öncelikli Görevler +

+
+
+ {priorityTasks.map((task) => ( +
+
+ +
+
+

+ {task.title} +

+ + {task.priority === 'urgent' && '🔥 Acil'} + {task.priority === 'high' && 'Yüksek'} + {task.priority === 'medium' && 'Orta'} + {task.priority === 'low' && 'Düşük'} + +
+

+ {task.description} +

+
+ + + {dayjs(task.dueDate).format('DD MMM')} + + + + {task.assignedTo.length} kişi + +
+
+
+
+ ))} +
+
+ + {/* Haftalık Menü */} +
+
+
+

+ + Haftalık Menü +

+ +
+
+
+ {weekMenus.map((menu) => { + const isToday = dayjs(menu.date).isSame(dayjs(), 'day') + return ( +
+
+
+

+ {menu.dayOfWeek} + {isToday && ( + + Bugün + + )} +

+

+ {dayjs(menu.date).format('DD MMMM')} +

+
+
+
+ {menu.meals[0]?.items.slice(0, 3).map((item, idx) => ( +

+ • {item} +

+ ))} + {menu.meals[0]?.items.length > 3 && ( +

+ +{menu.meals[0].items.length - 3} daha... +

+ )} +
+
+ ) + })} +
+
+ + {/* Servis Saatleri */} +
+
+

+ + Servis Saatleri +

+
+
+ {/* Sabah Servisleri */} +
+

+ 🌅 Sabah Servisleri +

+
+ {morningShuttles.slice(0, 2).map((shuttle) => ( +
+
+
+

+ {shuttle.name} +

+

+ {shuttle.route[0]} → {shuttle.route[shuttle.route.length - 1]} +

+
+
+

+ {shuttle.departureTime} +

+
+
+
+ + {shuttle.arrivalTime} + + 5 + ? 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300' + : shuttle.available > 0 + ? 'bg-orange-100 dark:bg-orange-900/30 text-orange-700 dark:text-orange-300' + : 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300' + }`} + > + {shuttle.available} yer + +
+
+ ))} +
+
+ + {/* Akşam Servisleri */} +
+

+ 🌆 Akşam Servisleri +

+
+ {eveningShuttles.slice(0, 2).map((shuttle) => ( +
+
+
+

+ {shuttle.name} +

+

+ {shuttle.route[0]} → {shuttle.route[shuttle.route.length - 1]} +

+
+
+

+ {shuttle.departureTime} +

+
+
+
+ + {shuttle.arrivalTime} + + 5 + ? 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300' + : shuttle.available > 0 + ? 'bg-orange-100 dark:bg-orange-900/30 text-orange-700 dark:text-orange-300' + : 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300' + }`} + > + {shuttle.available} yer + +
+
+ ))} +
+
+
+
+ + {/* İzin Yönetimi */} +
+
+

+ + İzin Yönetimi +

+
+
+ {/* İzin bakiye özeti */} +
+
+

Yıllık İzin

+

12 gün

+
+
+

Hastalık İzni

+

8 gün

+
+
+ + {/* Son izin talepleri */} +
+ {mockLeaveRequests.slice(0, 3).map((leave) => ( +
+
+

+ {leave.leaveType === LeaveTypeEnum.Annual ? '🏖️ Yıllık' : + leave.leaveType === LeaveTypeEnum.Sick ? '🏥 Hastalık' : + leave.leaveType === LeaveTypeEnum.Unpaid ? '💼 Ücretsiz' : '📋 Diğer'} İzin +

+ + {leave.status === LeaveStatusEnum.Approved ? 'Onaylandı' : + leave.status === LeaveStatusEnum.Pending ? 'Bekliyor' : 'Reddedildi'} + +
+

+ {dayjs(leave.startDate).format('DD MMM')} - {dayjs(leave.endDate).format('DD MMM')} ({leave.totalDays} gün) +

+
+ ))} +
+ + +
+
+ + {/* Mesai Yönetimi */} +
+
+

+ + Mesai Yönetimi +

+
+
+ {/* Mesai özeti */} +
+

Bu Ay Toplam

+

24 saat

+

20 onaylandı, 4 bekliyor

+
+ + {/* Son mesai talepleri */} +
+ {mockOvertimeRequests.slice(0, 3).map((overtime) => ( +
+
+

+ ⏰ {overtime.totalHours} saat +

+ + {overtime.status === LeaveStatusEnum.Approved ? 'Onaylandı' : + overtime.status === LeaveStatusEnum.Pending ? 'Bekliyor' : 'Reddedildi'} + +
+

+ {dayjs(overtime.date).format('DD MMM YYYY')} +

+
+ ))} +
+ + +
+
+ + {/* Harcama Yönetimi */} +
+
+

+ + Harcama Yönetimi +

+
+
+ {/* Harcama özeti */} +
+

Bu Ay Toplam

+

₺2,370

+

₺2,050 onaylandı

+
+ + {/* Son harcama talepleri */} +
+ {mockExpenseRequests.slice(0, 3).map((expense) => ( +
+
+
+

+ {expense.category === 'travel' ? '✈️' : + expense.category === 'meal' ? '🍽️' : + expense.category === 'accommodation' ? '🏨' : + expense.category === 'transport' ? '🚗' : '📋'} {expense.description} +

+

+ ₺{expense.amount.toLocaleString('tr-TR')} +

+
+ + {expense.status === 'approved' ? 'Onaylandı' : + expense.status === 'pending' ? 'Bekliyor' : 'Reddedildi'} + +
+
+ ))} +
+ + +
+
+ {/* Survey Modal */} + + {showSurveyModal && selectedSurvey && ( + <> + setShowSurveyModal(false)} + /> +
+ e.stopPropagation()} + > +
+
+

+ {selectedSurvey.title} +

+

+ {selectedSurvey.description} +

+
+ +
+ +
{ + e.preventDefault() + handleSubmitSurvey() + }} + className="p-6 space-y-6" + > + {/* Örnek Anket Soruları */} +
+
+ +
+ {[1, 2, 3, 4, 5].map((rating) => ( + + ))} +
+
+ +
+ + +
+ +
+ +