2025-10-18 20:04:24 +00:00
|
|
|
|
import React, { useState, useRef, useEffect } from 'react'
|
|
|
|
|
|
import { motion, AnimatePresence } from 'framer-motion'
|
|
|
|
|
|
import classNames from 'classnames'
|
|
|
|
|
|
import dayjs from 'dayjs'
|
|
|
|
|
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
|
|
|
|
|
import 'dayjs/locale/tr'
|
|
|
|
|
|
import {
|
2025-10-20 18:38:21 +00:00
|
|
|
|
FaHeart,
|
|
|
|
|
|
FaRegHeart,
|
|
|
|
|
|
FaRegCommentAlt,
|
|
|
|
|
|
FaTrash,
|
|
|
|
|
|
FaPaperPlane,
|
|
|
|
|
|
} from 'react-icons/fa'
|
2025-10-18 20:04:24 +00:00
|
|
|
|
import MediaLightbox from './MediaLightbox'
|
|
|
|
|
|
import LocationMap from './LocationMap'
|
|
|
|
|
|
import UserProfileCard from './UserProfileCard'
|
2025-10-20 18:38:21 +00:00
|
|
|
|
import { SocialPost } from '@/types/intranet'
|
2025-10-18 20:04:24 +00:00
|
|
|
|
|
|
|
|
|
|
dayjs.extend(relativeTime)
|
|
|
|
|
|
dayjs.locale('tr')
|
|
|
|
|
|
|
|
|
|
|
|
interface PostItemProps {
|
|
|
|
|
|
post: SocialPost
|
|
|
|
|
|
onLike: (postId: string) => void
|
|
|
|
|
|
onComment: (postId: string, content: string) => void
|
|
|
|
|
|
onDelete: (postId: string) => void
|
|
|
|
|
|
onVote: (postId: string, optionId: string) => void
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const PostItem: React.FC<PostItemProps> = ({ post, onLike, onComment, onDelete, onVote }) => {
|
|
|
|
|
|
const [showComments, setShowComments] = useState(false)
|
|
|
|
|
|
const [commentText, setCommentText] = useState('')
|
|
|
|
|
|
const [showAllImages, setShowAllImages] = useState(false)
|
|
|
|
|
|
const [lightboxOpen, setLightboxOpen] = useState(false)
|
|
|
|
|
|
const [lightboxIndex, setLightboxIndex] = useState(0)
|
|
|
|
|
|
const [showUserCard, setShowUserCard] = useState(false)
|
|
|
|
|
|
const [hoveredCommentAuthor, setHoveredCommentAuthor] = useState<string | null>(null)
|
|
|
|
|
|
const videoRef = useRef<HTMLVideoElement>(null)
|
|
|
|
|
|
|
|
|
|
|
|
// Intersection Observer for video autoplay/pause
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
const video = videoRef.current
|
|
|
|
|
|
if (!video) return
|
|
|
|
|
|
|
|
|
|
|
|
const observer = new IntersectionObserver(
|
|
|
|
|
|
(entries) => {
|
|
|
|
|
|
entries.forEach((entry) => {
|
|
|
|
|
|
if (entry.isIntersecting) {
|
|
|
|
|
|
// Video ekranda görünür - oynat
|
|
|
|
|
|
video.play().catch(err => {
|
|
|
|
|
|
console.log('Video autoplay failed:', err)
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Video ekrandan çıktı - durdur
|
|
|
|
|
|
video.pause()
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
threshold: 0.5 // Video %50 görünür olduğunda oynat
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
observer.observe(video)
|
|
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
|
observer.disconnect()
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [post.media?.type])
|
|
|
|
|
|
|
|
|
|
|
|
const handleSubmitComment = (e: React.FormEvent) => {
|
|
|
|
|
|
e.preventDefault()
|
|
|
|
|
|
if (commentText.trim()) {
|
|
|
|
|
|
onComment(post.id, commentText)
|
|
|
|
|
|
setCommentText('')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const getImageLayout = (images: string[]) => {
|
|
|
|
|
|
const count = images.length
|
|
|
|
|
|
if (count === 1) return 'single'
|
|
|
|
|
|
if (count === 2) return 'double'
|
|
|
|
|
|
if (count === 3) return 'triple'
|
|
|
|
|
|
return 'multiple'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const renderMedia = () => {
|
|
|
|
|
|
if (!post.media) return null
|
|
|
|
|
|
|
|
|
|
|
|
switch (post.media.type) {
|
|
|
|
|
|
case 'image':
|
|
|
|
|
|
if (post.media.urls && post.media.urls.length > 0) {
|
|
|
|
|
|
const layout = getImageLayout(post.media.urls)
|
|
|
|
|
|
const displayImages = showAllImages ? post.media.urls : post.media.urls.slice(0, 4)
|
|
|
|
|
|
const hasMore = post.media.urls.length > 4
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<div
|
|
|
|
|
|
className={classNames('mt-3 rounded-lg overflow-hidden', {
|
|
|
|
|
|
'grid gap-1': layout !== 'single',
|
|
|
|
|
|
'grid-cols-2': layout === 'double' || layout === 'multiple',
|
|
|
|
|
|
'grid-cols-3': layout === 'triple'
|
|
|
|
|
|
})}
|
|
|
|
|
|
>
|
|
|
|
|
|
{displayImages.map((url, index) => (
|
|
|
|
|
|
<div
|
|
|
|
|
|
key={index}
|
|
|
|
|
|
className={classNames('relative', {
|
|
|
|
|
|
'col-span-2': layout === 'triple' && index === 0,
|
|
|
|
|
|
'aspect-video': layout === 'single',
|
|
|
|
|
|
'aspect-square': layout !== 'single'
|
|
|
|
|
|
})}
|
|
|
|
|
|
>
|
|
|
|
|
|
<img
|
|
|
|
|
|
src={url}
|
|
|
|
|
|
alt={`Post image ${index + 1}`}
|
|
|
|
|
|
className="w-full h-full object-cover cursor-pointer hover:opacity-90 transition-opacity"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
setLightboxIndex(index)
|
|
|
|
|
|
setLightboxOpen(true)
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
{hasMore && index === 3 && !showAllImages && post.media?.urls && (
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="absolute inset-0 bg-black bg-opacity-60 flex items-center justify-center cursor-pointer"
|
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
|
e.stopPropagation()
|
|
|
|
|
|
setShowAllImages(true)
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<span className="text-white text-2xl font-bold">
|
|
|
|
|
|
+{post.media.urls.length - 4}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<MediaLightbox
|
|
|
|
|
|
isOpen={lightboxOpen}
|
|
|
|
|
|
onClose={() => setLightboxOpen(false)}
|
|
|
|
|
|
media={{ type: 'image', urls: post.media.urls }}
|
|
|
|
|
|
startIndex={lightboxIndex}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)
|
|
|
|
|
|
} else if (post.media.url) {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="mt-3 rounded-lg overflow-hidden cursor-pointer"
|
|
|
|
|
|
onClick={() => setLightboxOpen(true)}
|
|
|
|
|
|
>
|
|
|
|
|
|
<img
|
|
|
|
|
|
src={post.media.url}
|
|
|
|
|
|
alt="Post"
|
|
|
|
|
|
className="w-full object-cover max-h-96 hover:opacity-90 transition-opacity"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<MediaLightbox
|
|
|
|
|
|
isOpen={lightboxOpen}
|
|
|
|
|
|
onClose={() => setLightboxOpen(false)}
|
|
|
|
|
|
media={{ type: 'image', url: post.media.url }}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
case 'video':
|
|
|
|
|
|
return (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="mt-3 rounded-lg overflow-hidden cursor-pointer relative group"
|
|
|
|
|
|
onClick={() => setLightboxOpen(true)}
|
|
|
|
|
|
>
|
|
|
|
|
|
<video
|
|
|
|
|
|
ref={videoRef}
|
|
|
|
|
|
className="w-full max-h-96"
|
|
|
|
|
|
src={post.media.url}
|
|
|
|
|
|
loop
|
|
|
|
|
|
muted
|
|
|
|
|
|
playsInline
|
|
|
|
|
|
>
|
|
|
|
|
|
Tarayıcınız video etiketini desteklemiyor.
|
|
|
|
|
|
</video>
|
|
|
|
|
|
<div className="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-30 transition-all flex items-center justify-center">
|
|
|
|
|
|
<div className="w-16 h-16 bg-white bg-opacity-90 rounded-full flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
|
|
|
|
|
|
<div className="w-0 h-0 border-t-10 border-t-transparent border-l-16 border-l-blue-600 border-b-10 border-b-transparent ml-1"></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<MediaLightbox
|
|
|
|
|
|
isOpen={lightboxOpen}
|
|
|
|
|
|
onClose={() => setLightboxOpen(false)}
|
|
|
|
|
|
media={{ type: 'video', url: post.media.url || '' }}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
case 'poll':
|
|
|
|
|
|
if (post.media.poll) {
|
|
|
|
|
|
const poll = post.media.poll
|
|
|
|
|
|
const isExpired = new Date() > poll.endsAt
|
|
|
|
|
|
const hasVoted = !!poll.userVote
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className="mt-3 p-4 bg-gray-50 dark:bg-gray-700 rounded-lg">
|
|
|
|
|
|
<h4 className="font-medium text-gray-900 dark:text-gray-100 mb-3">
|
|
|
|
|
|
{poll.question}
|
|
|
|
|
|
</h4>
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
|
{poll.options.map((option) => {
|
|
|
|
|
|
const percentage =
|
|
|
|
|
|
poll.totalVotes > 0 ? (option.votes / poll.totalVotes) * 100 : 0
|
|
|
|
|
|
const isSelected = poll.userVote === option.id
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<button
|
|
|
|
|
|
key={option.id}
|
|
|
|
|
|
onClick={() => !hasVoted && !isExpired && onVote(post.id, option.id)}
|
|
|
|
|
|
disabled={hasVoted || isExpired}
|
|
|
|
|
|
className={classNames(
|
|
|
|
|
|
'w-full text-left p-3 rounded-lg relative overflow-hidden transition-all',
|
|
|
|
|
|
{
|
|
|
|
|
|
'bg-blue-100 dark:bg-blue-900 border-2 border-blue-500':
|
|
|
|
|
|
isSelected,
|
|
|
|
|
|
'bg-white dark:bg-gray-600 hover:bg-gray-50 dark:hover:bg-gray-500':
|
|
|
|
|
|
!isSelected && !hasVoted && !isExpired,
|
|
|
|
|
|
'bg-white dark:bg-gray-600 cursor-not-allowed':
|
|
|
|
|
|
hasVoted || isExpired
|
|
|
|
|
|
}
|
|
|
|
|
|
)}
|
|
|
|
|
|
>
|
|
|
|
|
|
{hasVoted && (
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="absolute inset-y-0 left-0 bg-blue-200 dark:bg-blue-800 transition-all"
|
|
|
|
|
|
style={{ width: `${percentage}%` }}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
<div className="relative z-10 flex justify-between items-center">
|
|
|
|
|
|
<span className="font-medium text-gray-900 dark:text-gray-100">
|
|
|
|
|
|
{option.text}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
{hasVoted && (
|
|
|
|
|
|
<span className="text-sm font-semibold text-gray-700 dark:text-gray-200">
|
|
|
|
|
|
{percentage.toFixed(0)}%
|
|
|
|
|
|
</span>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
)
|
|
|
|
|
|
})}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className="mt-3 text-sm text-gray-600 dark:text-gray-400">
|
|
|
|
|
|
{poll.totalVotes} oy • {isExpired ? 'Sona erdi' : dayjs(poll.endsAt).fromNow() + ' bitiyor'}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
initial={{ opacity: 0, y: 20 }}
|
|
|
|
|
|
animate={{ opacity: 1, y: 0 }}
|
|
|
|
|
|
exit={{ opacity: 0, y: -20 }}
|
|
|
|
|
|
className="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 p-4 mb-4"
|
|
|
|
|
|
>
|
|
|
|
|
|
{/* Header */}
|
|
|
|
|
|
<div className="flex items-start justify-between mb-3">
|
|
|
|
|
|
<div className="flex items-center gap-3">
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="relative"
|
|
|
|
|
|
onMouseEnter={() => setShowUserCard(true)}
|
|
|
|
|
|
onMouseLeave={() => setShowUserCard(false)}
|
|
|
|
|
|
>
|
|
|
|
|
|
<img
|
2025-10-27 21:08:36 +00:00
|
|
|
|
src={post.author.avatar || 'https://i.pravatar.cc/150?img=1'}
|
|
|
|
|
|
alt={post.author.fullName}
|
2025-10-18 20:04:24 +00:00
|
|
|
|
className="w-12 h-12 rounded-full object-cover cursor-pointer ring-2 ring-transparent hover:ring-blue-500 transition-all"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<AnimatePresence>
|
|
|
|
|
|
{showUserCard && (
|
2025-10-27 21:08:36 +00:00
|
|
|
|
<UserProfileCard
|
|
|
|
|
|
user={{
|
|
|
|
|
|
id: post.author.id,
|
|
|
|
|
|
name: post.author.fullName,
|
|
|
|
|
|
avatar: post.author.avatar || 'https://i.pravatar.cc/150?img=1',
|
|
|
|
|
|
title: post.author.jobPosition?.name || 'Çalışan',
|
|
|
|
|
|
email: post.author.email,
|
|
|
|
|
|
phone: post.author.phone,
|
|
|
|
|
|
department: post.author.department?.name,
|
|
|
|
|
|
location: post.author.workLocation
|
|
|
|
|
|
}}
|
|
|
|
|
|
position="bottom"
|
|
|
|
|
|
/>
|
2025-10-18 20:04:24 +00:00
|
|
|
|
)}
|
|
|
|
|
|
</AnimatePresence>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<h3 className="font-semibold text-gray-900 dark:text-gray-100">
|
2025-10-27 21:08:36 +00:00
|
|
|
|
{post.author.fullName}
|
2025-10-18 20:04:24 +00:00
|
|
|
|
</h3>
|
|
|
|
|
|
<p className="text-sm text-gray-600 dark:text-gray-400">
|
2025-10-27 21:08:36 +00:00
|
|
|
|
{post.author.jobPosition?.name || 'Çalışan'} • {dayjs(post.creationTime).fromNow()}
|
2025-10-18 20:04:24 +00:00
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{post.isOwnPost && (
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={() => onDelete(post.id)}
|
|
|
|
|
|
className="p-2 text-gray-500 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-full transition-colors"
|
|
|
|
|
|
title="Gönderiyi sil"
|
|
|
|
|
|
>
|
2025-10-20 18:38:21 +00:00
|
|
|
|
<FaTrash className="w-5 h-5" />
|
2025-10-18 20:04:24 +00:00
|
|
|
|
</button>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Content */}
|
|
|
|
|
|
<div className="mb-3">
|
|
|
|
|
|
<p className="text-gray-800 dark:text-gray-200 whitespace-pre-wrap">{post.content}</p>
|
|
|
|
|
|
{renderMedia()}
|
|
|
|
|
|
|
|
|
|
|
|
{/* Location */}
|
|
|
|
|
|
{post.location && (
|
|
|
|
|
|
<div className="mt-3">
|
|
|
|
|
|
<LocationMap location={post.location} />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Actions */}
|
|
|
|
|
|
<div className="flex items-center gap-6 pt-3 border-t border-gray-100 dark:border-gray-700">
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={() => onLike(post.id)}
|
|
|
|
|
|
className={classNames(
|
|
|
|
|
|
'flex items-center gap-2 transition-colors',
|
|
|
|
|
|
post.likes.isLiked
|
|
|
|
|
|
? 'text-red-600 hover:text-red-700'
|
|
|
|
|
|
: 'text-gray-600 dark:text-gray-400 hover:text-red-600'
|
|
|
|
|
|
)}
|
|
|
|
|
|
>
|
|
|
|
|
|
{post.likes.isLiked ? (
|
2025-10-20 18:38:21 +00:00
|
|
|
|
<FaHeart className="w-5 h-5" />
|
2025-10-18 20:04:24 +00:00
|
|
|
|
) : (
|
2025-10-20 18:38:21 +00:00
|
|
|
|
<FaRegHeart className="w-5 h-5" />
|
2025-10-18 20:04:24 +00:00
|
|
|
|
)}
|
|
|
|
|
|
<span className="text-sm font-medium">{post.likes.count}</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={() => setShowComments(!showComments)}
|
|
|
|
|
|
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-blue-600 transition-colors"
|
|
|
|
|
|
>
|
2025-10-20 18:38:21 +00:00
|
|
|
|
<FaRegCommentAlt className="w-5 h-5" />
|
2025-10-18 20:04:24 +00:00
|
|
|
|
<span className="text-sm font-medium">{post.comments.length}</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Comments Section */}
|
|
|
|
|
|
<AnimatePresence>
|
|
|
|
|
|
{showComments && (
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
initial={{ height: 0, opacity: 0 }}
|
|
|
|
|
|
animate={{ height: 'auto', opacity: 1 }}
|
|
|
|
|
|
exit={{ height: 0, opacity: 0 }}
|
|
|
|
|
|
className="mt-4 pt-4 border-t border-gray-100 dark:border-gray-700"
|
|
|
|
|
|
>
|
|
|
|
|
|
{/* Comment Form */}
|
|
|
|
|
|
<form onSubmit={handleSubmitComment} className="mb-4">
|
|
|
|
|
|
<div className="flex gap-2">
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
value={commentText}
|
|
|
|
|
|
onChange={(e) => setCommentText(e.target.value)}
|
|
|
|
|
|
placeholder="Yorum yazın..."
|
|
|
|
|
|
className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-full bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="submit"
|
|
|
|
|
|
disabled={!commentText.trim()}
|
|
|
|
|
|
className="p-2 bg-blue-600 text-white rounded-full hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed transition-colors"
|
|
|
|
|
|
>
|
2025-10-20 18:38:21 +00:00
|
|
|
|
<FaPaperPlane className="w-5 h-5" />
|
2025-10-18 20:04:24 +00:00
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
|
|
|
|
|
|
{/* Comments List */}
|
|
|
|
|
|
<div className="space-y-3">
|
|
|
|
|
|
{post.comments.map((comment) => (
|
|
|
|
|
|
<div key={comment.id} className="flex gap-3">
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="relative"
|
|
|
|
|
|
onMouseEnter={() => setHoveredCommentAuthor(comment.id)}
|
|
|
|
|
|
onMouseLeave={() => setHoveredCommentAuthor(null)}
|
|
|
|
|
|
>
|
|
|
|
|
|
<img
|
2025-10-27 21:08:36 +00:00
|
|
|
|
src={comment.author.avatar || 'https://i.pravatar.cc/150?img=1'}
|
|
|
|
|
|
alt={comment.author.fullName}
|
2025-10-18 20:04:24 +00:00
|
|
|
|
className="w-8 h-8 rounded-full object-cover cursor-pointer ring-2 ring-transparent hover:ring-blue-500 transition-all"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<AnimatePresence>
|
|
|
|
|
|
{hoveredCommentAuthor === comment.id && (
|
|
|
|
|
|
<UserProfileCard
|
|
|
|
|
|
user={{
|
|
|
|
|
|
id: comment.author.id,
|
2025-10-27 21:08:36 +00:00
|
|
|
|
name: comment.author.fullName,
|
|
|
|
|
|
avatar: comment.author.avatar || 'https://i.pravatar.cc/150?img=1',
|
|
|
|
|
|
title: comment.author.jobPosition?.name || 'Çalışan'
|
2025-10-18 20:04:24 +00:00
|
|
|
|
}}
|
|
|
|
|
|
position="bottom"
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</AnimatePresence>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div className="flex-1">
|
|
|
|
|
|
<div className="bg-gray-100 dark:bg-gray-700 rounded-lg px-4 py-2">
|
|
|
|
|
|
<h4 className="font-semibold text-sm text-gray-900 dark:text-gray-100">
|
2025-10-27 21:08:36 +00:00
|
|
|
|
{comment.author.fullName}
|
2025-10-18 20:04:24 +00:00
|
|
|
|
</h4>
|
|
|
|
|
|
<p className="text-sm text-gray-800 dark:text-gray-200">{comment.content}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1 ml-4">
|
2025-10-20 18:38:21 +00:00
|
|
|
|
{dayjs(comment.creationTime).fromNow()}
|
2025-10-18 20:04:24 +00:00
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</AnimatePresence>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default PostItem
|