erp-platform/ui/src/views/intranet/Birthday.tsx
2025-10-19 23:02:09 +03:00

279 lines
12 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, { useState } from 'react'
import { motion } from 'framer-motion'
import { HiCake, HiGift, HiCalendar } from 'react-icons/hi2'
import dayjs from 'dayjs'
import isBetween from 'dayjs/plugin/isBetween'
import { mockBirthdays, mockAnniversaries, Birthday, WorkAnniversary } from '../../mocks/mockIntranetData'
dayjs.extend(isBetween)
const BirthdaysModule: React.FC = () => {
const [selectedMonth, setSelectedMonth] = useState(dayjs().month())
const months = [
'Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran',
'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık'
]
// Bugünün doğum günleri
const todayBirthdays = mockBirthdays.filter(b =>
dayjs(b.date).month() === dayjs().month() &&
dayjs(b.date).date() === dayjs().date()
)
// Bu haftanın doğum günleri
const thisWeekBirthdays = mockBirthdays.filter(b => {
const birthDate = dayjs().year(dayjs().year()).month(dayjs(b.date).month()).date(dayjs(b.date).date())
return birthDate.isBetween(dayjs().startOf('week'), dayjs().endOf('week'), null, '[]')
})
// Seçilen aydaki doğum günleri
const monthBirthdays = mockBirthdays.filter(b => dayjs(b.date).month() === selectedMonth)
.sort((a, b) => dayjs(a.date).date() - dayjs(b.date).date())
// Bu ayki iş yıldönümleri
const thisMonthAnniversaries = mockAnniversaries.filter((a: WorkAnniversary) => dayjs(a.hireDate).month() === dayjs().month())
const getBirthdayMessage = (birthday: Birthday) => {
const age = birthday.age || dayjs().year() - dayjs(birthday.date).year()
return `${age}. yaş günü kutlu olsun! 🎉`
}
const getAnniversaryMessage = (anniversary: WorkAnniversary) => {
return `${anniversary.years} yıllık iş birliğimiz için teşekkürler! 🎊`
}
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 p-6">
<div className="max-w-7xl mx-auto space-y-6">
{/* Header */}
<div>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">
🎂 Doğum Günleri & Yıldönümleri
</h1>
<p className="text-gray-600 dark:text-gray-400 mt-1">
Ekip üyelerimizin özel günlerini kutlayalım
</p>
</div>
{/* Stats */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{/* Bugün */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="bg-gradient-to-br from-pink-500 to-purple-600 rounded-lg p-6 text-white"
>
<div className="flex items-center justify-between mb-4">
<HiCake className="w-8 h-8" />
<span className="text-3xl font-bold">{todayBirthdays.length}</span>
</div>
<h3 className="font-semibold text-lg mb-1">Bugün Doğanlar</h3>
<p className="text-pink-100 text-sm">
{todayBirthdays.length > 0 ? 'Kutlama zamanı!' : 'Bugün doğum günü yok'}
</p>
</motion.div>
{/* Bu Hafta */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.1 }}
className="bg-gradient-to-br from-blue-500 to-cyan-600 rounded-lg p-6 text-white"
>
<div className="flex items-center justify-between mb-4">
<HiGift className="w-8 h-8" />
<span className="text-3xl font-bold">{thisWeekBirthdays.length}</span>
</div>
<h3 className="font-semibold text-lg mb-1">Bu Hafta</h3>
<p className="text-blue-100 text-sm">
{dayjs().startOf('week').format('DD MMM')} - {dayjs().endOf('week').format('DD MMM')}
</p>
</motion.div>
{/* İş Yıldönümleri */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
className="bg-gradient-to-br from-orange-500 to-red-600 rounded-lg p-6 text-white"
>
<div className="flex items-center justify-between mb-4">
<HiCalendar className="w-8 h-8" />
<span className="text-3xl font-bold">{thisMonthAnniversaries.length}</span>
</div>
<h3 className="font-semibold text-lg mb-1">Bu Ay Yıldönümü</h3>
<p className="text-orange-100 text-sm">
{dayjs().format('MMMM')} ayında
</p>
</motion.div>
</div>
{/* Bugünün Doğum Günleri */}
{todayBirthdays.length > 0 && (
<div className="bg-white dark:bg-gray-800 rounded-lg p-6 border-2 border-pink-300 dark:border-pink-700">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
🎉 Bugün Doğum Günü Olanlar
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{todayBirthdays.map((birthday, idx) => (
<motion.div
key={idx}
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
className="bg-gradient-to-r from-pink-50 to-purple-50 dark:from-pink-900/20 dark:to-purple-900/20 rounded-lg p-4 border border-pink-200 dark:border-pink-800"
>
<div className="flex items-center gap-4">
<img
src={birthday.employee.avatar}
alt={birthday.employee.fullName}
className="w-16 h-16 rounded-full border-4 border-white dark:border-gray-800 shadow-lg"
/>
<div className="flex-1">
<h3 className="font-semibold text-gray-900 dark:text-white">
{birthday.employee.fullName}
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
{birthday.employee.department?.name || 'Genel'}
</p>
<p className="text-sm font-medium text-pink-600 dark:text-pink-400 mt-1">
{getBirthdayMessage(birthday)}
</p>
</div>
</div>
</motion.div>
))}
</div>
</div>
)}
{/* Ay Seçici */}
<div className="bg-white dark:bg-gray-800 rounded-lg p-6">
<div className="flex items-center justify-between mb-6">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white">
📅 Aylık Doğum Günleri
</h2>
<select
value={selectedMonth}
onChange={(e) => setSelectedMonth(Number(e.target.value))}
className="px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
>
{months.map((month, idx) => (
<option key={idx} value={idx}>
{month}
</option>
))}
</select>
</div>
{/* Doğum Günleri Listesi */}
<div className="space-y-3">
{monthBirthdays.map((birthday, idx) => {
const isToday = dayjs(birthday.date).month() === dayjs().month() &&
dayjs(birthday.date).date() === dayjs().date()
return (
<motion.div
key={idx}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: idx * 0.05 }}
className={`flex items-center gap-4 p-4 rounded-lg border ${
isToday
? 'bg-pink-50 dark:bg-pink-900/20 border-pink-300 dark:border-pink-700'
: 'bg-gray-50 dark:bg-gray-700/50 border-gray-200 dark:border-gray-700'
}`}
>
<div className={`w-16 h-16 rounded-lg flex flex-col items-center justify-center ${
isToday
? 'bg-pink-500 text-white'
: 'bg-gray-200 dark:bg-gray-600 text-gray-700 dark:text-gray-300'
}`}>
<span className="text-2xl font-bold">{dayjs(birthday.date).date()}</span>
<span className="text-xs">{months[selectedMonth].substring(0, 3)}</span>
</div>
<img
src={birthday.employee.avatar}
alt={birthday.employee.fullName}
className="w-12 h-12 rounded-full"
/>
<div className="flex-1">
<h3 className="font-semibold text-gray-900 dark:text-white">
{birthday.employee.fullName}
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
{birthday.employee.department?.name || 'Genel'}
</p>
</div>
<div className="text-right">
<p className="text-sm font-medium text-gray-900 dark:text-white">
{birthday.age || dayjs().year() - dayjs(birthday.date).year()} yaşında
</p>
{isToday && (
<span className="text-xs text-pink-600 dark:text-pink-400 font-medium">
🎂 Bugün!
</span>
)}
</div>
</motion.div>
)
})}
{monthBirthdays.length === 0 && (
<div className="text-center py-12 text-gray-500 dark:text-gray-400">
<HiCake className="w-16 h-16 mx-auto mb-4 opacity-20" />
<p>{months[selectedMonth]} ayında doğum günü yok</p>
</div>
)}
</div>
</div>
{/* İş Yıldönümleri */}
{thisMonthAnniversaries.length > 0 && (
<div className="bg-white dark:bg-gray-800 rounded-lg p-6">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
🎊 Bu Ayki İş Yıldönümleri
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{thisMonthAnniversaries.map((anniversary: WorkAnniversary, idx: number) => (
<motion.div
key={idx}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: idx * 0.1 }}
className="bg-gradient-to-r from-orange-50 to-amber-50 dark:from-orange-900/20 dark:to-amber-900/20 rounded-lg p-4 border border-orange-200 dark:border-orange-800"
>
<div className="flex items-center gap-4">
<img
src={anniversary.employee.avatar}
alt={anniversary.employee.fullName}
className="w-16 h-16 rounded-full border-4 border-white dark:border-gray-800 shadow-lg"
/>
<div className="flex-1">
<h3 className="font-semibold text-gray-900 dark:text-white">
{anniversary.employee.fullName}
</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">
{anniversary.employee.department?.name || 'Genel'}
</p>
<p className="text-sm font-medium text-orange-600 dark:text-orange-400 mt-1">
{getAnniversaryMessage(anniversary)}
</p>
</div>
<div className="text-center bg-orange-500 text-white rounded-full w-16 h-16 flex flex-col items-center justify-center">
<span className="text-2xl font-bold">{anniversary.years}</span>
<span className="text-xs">YIL</span>
</div>
</div>
</motion.div>
))}
</div>
</div>
)}
</div>
</div>
)
}
export default BirthdaysModule