2025-10-20 13:41:31 +00:00
|
|
|
|
import React from 'react'
|
|
|
|
|
|
import { motion } from 'framer-motion'
|
|
|
|
|
|
import { FaTimes, FaEye, FaClipboard } from 'react-icons/fa'
|
|
|
|
|
|
import dayjs from 'dayjs'
|
2025-10-20 18:48:22 +00:00
|
|
|
|
import { Announcement } from '../../../mocks/mockIntranet'
|
2025-10-20 13:41:31 +00:00
|
|
|
|
|
|
|
|
|
|
interface AnnouncementDetailModalProps {
|
|
|
|
|
|
announcement: Announcement
|
|
|
|
|
|
onClose: () => void
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const AnnouncementDetailModal: React.FC<AnnouncementDetailModalProps> = ({ announcement, onClose }) => {
|
|
|
|
|
|
const getCategoryColor = (category: string) => {
|
|
|
|
|
|
const colors: Record<string, string> = {
|
|
|
|
|
|
general: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300',
|
|
|
|
|
|
hr: 'bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300',
|
|
|
|
|
|
it: 'bg-orange-100 dark:bg-orange-900/30 text-orange-700 dark:text-orange-300',
|
|
|
|
|
|
event: 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300',
|
|
|
|
|
|
urgent: 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300',
|
|
|
|
|
|
}
|
|
|
|
|
|
return colors[category] || colors.general
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
initial={{ opacity: 0 }}
|
|
|
|
|
|
animate={{ opacity: 1 }}
|
|
|
|
|
|
exit={{ opacity: 0 }}
|
|
|
|
|
|
className="fixed inset-0 bg-black/50 z-40"
|
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 overflow-y-auto">
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
initial={{ opacity: 0, scale: 0.95, y: 20 }}
|
|
|
|
|
|
animate={{ opacity: 1, scale: 1, y: 0 }}
|
|
|
|
|
|
exit={{ opacity: 0, scale: 0.95, y: 20 }}
|
|
|
|
|
|
className="bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-3xl w-full"
|
|
|
|
|
|
onClick={(e) => e.stopPropagation()}
|
|
|
|
|
|
>
|
|
|
|
|
|
{/* Header */}
|
|
|
|
|
|
<div className="p-6 border-b border-gray-200 dark:border-gray-700">
|
|
|
|
|
|
<div className="flex items-start justify-between">
|
|
|
|
|
|
<div className="flex-1">
|
|
|
|
|
|
<div className="flex items-center gap-3 mb-3">
|
|
|
|
|
|
<span
|
|
|
|
|
|
className={`px-3 py-1 text-xs font-medium rounded-full ${getCategoryColor(announcement.category)}`}
|
|
|
|
|
|
>
|
|
|
|
|
|
{announcement.category === 'general' && '📢 Genel'}
|
|
|
|
|
|
{announcement.category === 'hr' && '👥 İnsan Kaynakları'}
|
|
|
|
|
|
{announcement.category === 'it' && '💻 Bilgi Teknolojileri'}
|
|
|
|
|
|
{announcement.category === 'event' && '🎉 Etkinlik'}
|
|
|
|
|
|
{announcement.category === 'urgent' && '🚨 Acil'}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
{announcement.isPinned && (
|
|
|
|
|
|
<span className="text-yellow-500 text-sm">📌 Sabitlenmiş</span>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">
|
|
|
|
|
|
{announcement.title}
|
|
|
|
|
|
</h2>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
|
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"
|
|
|
|
|
|
>
|
|
|
|
|
|
<FaTimes className="w-6 h-6 text-gray-500" />
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Author Info */}
|
|
|
|
|
|
<div className="flex items-center gap-3 mt-4">
|
|
|
|
|
|
<img
|
|
|
|
|
|
src={announcement.author.avatar}
|
|
|
|
|
|
alt={announcement.author.fullName}
|
|
|
|
|
|
className="w-12 h-12 rounded-full"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p className="font-semibold text-gray-900 dark:text-white">
|
|
|
|
|
|
{announcement.author.fullName}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<div className="flex items-center gap-3 text-sm text-gray-600 dark:text-gray-400">
|
|
|
|
|
|
<span>
|
|
|
|
|
|
{dayjs(announcement.publishDate).format('DD MMMM YYYY, HH:mm')}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<span>•</span>
|
|
|
|
|
|
<span className="flex items-center gap-1">
|
|
|
|
|
|
<FaEye className="w-4 h-4" />
|
|
|
|
|
|
{announcement.viewCount} görüntülenme
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Content */}
|
|
|
|
|
|
<div className="p-6 max-h-[60vh] overflow-y-auto">
|
|
|
|
|
|
{/* Image if exists */}
|
|
|
|
|
|
{announcement.imageUrl && (
|
|
|
|
|
|
<img
|
|
|
|
|
|
src={announcement.imageUrl}
|
|
|
|
|
|
alt={announcement.title}
|
|
|
|
|
|
className="w-full rounded-lg mb-6"
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Full Content */}
|
|
|
|
|
|
<div className="prose prose-sm dark:prose-invert max-w-none">
|
|
|
|
|
|
<p className="text-gray-700 dark:text-gray-300 whitespace-pre-line">
|
|
|
|
|
|
{announcement.content}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Attachments */}
|
|
|
|
|
|
{announcement.attachments &&
|
|
|
|
|
|
announcement.attachments.length > 0 && (
|
|
|
|
|
|
<div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
|
|
|
|
|
|
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
|
|
|
|
|
|
<FaClipboard className="w-5 h-5" />
|
|
|
|
|
|
Ekler ({announcement.attachments.length})
|
|
|
|
|
|
</h3>
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
|
{announcement.attachments.map((attachment, idx) => (
|
|
|
|
|
|
<a
|
|
|
|
|
|
key={idx}
|
|
|
|
|
|
href={attachment.url}
|
|
|
|
|
|
target="_blank"
|
|
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
|
|
className="flex items-center gap-3 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
|
|
|
|
|
>
|
|
|
|
|
|
<FaClipboard className="w-5 h-5 text-gray-400" />
|
|
|
|
|
|
<div className="flex-1 min-w-0">
|
|
|
|
|
|
<p className="text-sm font-medium text-gray-900 dark:text-white truncate">
|
|
|
|
|
|
{attachment.name}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p className="text-xs text-gray-500 dark:text-gray-400">
|
|
|
|
|
|
{attachment.size}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span className="text-sm text-blue-600 dark:text-blue-400">
|
|
|
|
|
|
İndir
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Departments */}
|
|
|
|
|
|
{announcement.departments &&
|
|
|
|
|
|
announcement.departments.length > 0 && (
|
|
|
|
|
|
<div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
|
|
|
|
|
|
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3">
|
|
|
|
|
|
Hedef Departmanlar
|
|
|
|
|
|
</h3>
|
|
|
|
|
|
<div className="flex flex-wrap gap-2">
|
|
|
|
|
|
{announcement.departments.map((dept, idx) => (
|
|
|
|
|
|
<span
|
|
|
|
|
|
key={idx}
|
|
|
|
|
|
className="px-3 py-1 bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 text-sm rounded-full"
|
|
|
|
|
|
>
|
|
|
|
|
|
{dept}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Expiry Date */}
|
|
|
|
|
|
{announcement.expiryDate && (
|
|
|
|
|
|
<div className="mt-6 pt-6 border-t border-gray-200 dark:border-gray-700">
|
|
|
|
|
|
<p className="text-sm text-gray-600 dark:text-gray-400">
|
|
|
|
|
|
<span className="font-medium">Son Geçerlilik Tarihi:</span>{' '}
|
|
|
|
|
|
{dayjs(announcement.expiryDate).format('DD MMMM YYYY')}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Footer */}
|
|
|
|
|
|
<div className="p-6 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/50">
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
|
className="w-full px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors"
|
|
|
|
|
|
>
|
|
|
|
|
|
Kapat
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default AnnouncementDetailModal
|