2026-05-06 14:48:44 +00:00
|
|
|
import React from 'react'
|
2026-05-08 18:11:56 +00:00
|
|
|
import { FaCalendarAlt, FaHeart } from 'react-icons/fa'
|
2026-05-06 14:48:44 +00:00
|
|
|
import dayjs from 'dayjs'
|
|
|
|
|
import { EventDto } from '@/proxy/intranet/models'
|
|
|
|
|
import useLocale from '@/utils/hooks/useLocale'
|
|
|
|
|
import { currentLocalDate } from '@/utils/dateUtils'
|
|
|
|
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
2026-05-08 18:11:56 +00:00
|
|
|
import { Avatar } from '@/components/ui'
|
|
|
|
|
import { AVATAR_URL } from '@/constants/app.constant'
|
2026-05-06 14:48:44 +00:00
|
|
|
|
2026-05-07 14:25:06 +00:00
|
|
|
interface UpcomingEventsProps {
|
|
|
|
|
events: EventDto[]
|
|
|
|
|
onEventClick?: (event: EventDto) => void
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getFirstPhoto = (photos?: string): string | null => {
|
|
|
|
|
if (!photos) return null
|
|
|
|
|
const parts = photos.split('|').filter(Boolean)
|
|
|
|
|
return parts.length > 0 ? parts[0] : null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const photoSrc = (img: string) => {
|
|
|
|
|
if (
|
|
|
|
|
img.startsWith('data:') ||
|
|
|
|
|
img.startsWith('http://') ||
|
|
|
|
|
img.startsWith('https://') ||
|
|
|
|
|
img.startsWith('/')
|
|
|
|
|
)
|
|
|
|
|
return img
|
|
|
|
|
return `data:image/jpeg;base64,${img}`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const UpcomingEvents: React.FC<UpcomingEventsProps> = ({ events, onEventClick }) => {
|
2026-05-06 14:48:44 +00:00
|
|
|
const currentLocale = useLocale()
|
2026-05-06 19:07:30 +00:00
|
|
|
const { translate } = useLocalization()
|
|
|
|
|
|
|
|
|
|
const now = dayjs()
|
|
|
|
|
const upcomingEvents = events
|
|
|
|
|
.filter((event) => event.isPublished && !dayjs(event.date).isBefore(now, 'day'))
|
|
|
|
|
.sort((left, right) => dayjs(left.date).valueOf() - dayjs(right.date).valueOf())
|
2026-05-06 14:48:44 +00:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
|
|
|
|
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
|
|
|
|
<h2 className="text-base font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
|
|
|
|
<FaCalendarAlt className="w-5 h-5" />
|
|
|
|
|
{translate('::App.Platform.Intranet.Widgets.UpcomingEvents.Title')}
|
|
|
|
|
</h2>
|
|
|
|
|
</div>
|
2026-05-08 18:11:56 +00:00
|
|
|
<div className="divide-y divide-gray-200 dark:divide-gray-700">
|
2026-05-06 14:48:44 +00:00
|
|
|
{upcomingEvents.length > 0 ? (
|
2026-05-07 14:25:06 +00:00
|
|
|
upcomingEvents.slice(0, 3).map((event) => {
|
|
|
|
|
const firstPhoto = getFirstPhoto(event.photos)
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
key={event.id}
|
|
|
|
|
onClick={() => onEventClick?.(event)}
|
2026-05-08 18:11:56 +00:00
|
|
|
className={`p-6 transition-colors ${onEventClick ? 'cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700/50' : ''}`}
|
2026-05-07 14:25:06 +00:00
|
|
|
>
|
2026-05-08 18:11:56 +00:00
|
|
|
<div className="flex items-start gap-4">
|
|
|
|
|
<div className="flex-1 min-w-0">
|
|
|
|
|
<h4 className="text-base font-semibold text-gray-900 dark:text-white">{event.name}</h4>
|
|
|
|
|
<p className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
|
|
|
|
|
{currentLocalDate(event.date, currentLocale || 'tr')} - {event.place}
|
|
|
|
|
</p>
|
|
|
|
|
{event.description && (
|
|
|
|
|
<p className="text-sm text-gray-600 dark:text-gray-400 line-clamp-2 mt-1">
|
|
|
|
|
{event.description}
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
<div className="flex items-center gap-2 mt-3 text-xs text-gray-500 dark:text-gray-400">
|
|
|
|
|
<Avatar
|
|
|
|
|
size={24}
|
|
|
|
|
shape="circle"
|
|
|
|
|
src={AVATAR_URL(event.user.id, event.user.tenantId)}
|
|
|
|
|
/>
|
|
|
|
|
<span>{event.user.fullName}</span>
|
|
|
|
|
<span>•</span>
|
|
|
|
|
<span>{dayjs(event.date).fromNow()}</span>
|
|
|
|
|
{event.likes > 0 && (
|
|
|
|
|
<>
|
|
|
|
|
<span>•</span>
|
|
|
|
|
<span className={`flex items-center gap-1 ${event.isLiked ? 'text-red-500' : ''}`}>
|
|
|
|
|
<FaHeart className="w-3 h-3" />
|
|
|
|
|
{event.likes}
|
|
|
|
|
</span>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
{firstPhoto && (
|
|
|
|
|
<img
|
|
|
|
|
src={photoSrc(firstPhoto)}
|
|
|
|
|
alt={event.name}
|
|
|
|
|
className="w-14 h-14 rounded-lg object-cover flex-shrink-0"
|
|
|
|
|
/>
|
|
|
|
|
)}
|
2026-05-07 14:25:06 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
})
|
2026-05-06 14:48:44 +00:00
|
|
|
) : (
|
2026-05-08 18:11:56 +00:00
|
|
|
<div className="text-center py-12">
|
|
|
|
|
<div className="inline-flex items-center justify-center w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-full mb-4">
|
|
|
|
|
<FaCalendarAlt className="w-8 h-8 text-gray-400" />
|
|
|
|
|
</div>
|
|
|
|
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
|
|
|
|
{translate('::App.Platform.Intranet.Widgets.UpcomingEvents.NoEvent')}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
2026-05-06 14:48:44 +00:00
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default UpcomingEvents
|
2026-05-07 14:25:06 +00:00
|
|
|
|