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-29 19:24:40 +00:00
|
|
|
|
import { SocialPostDto } from '@/proxy/intranet/models'
|
2025-10-18 20:04:24 +00:00
|
|
|
|
|
|
|
|
|
|
dayjs.extend(relativeTime)
|
|
|
|
|
|
dayjs.locale('tr')
|
|
|
|
|
|
|
|
|
|
|
|
interface PostItemProps {
|
2025-10-29 19:24:40 +00:00
|
|
|
|
post: SocialPostDto
|
2025-10-18 20:04:24 +00:00
|
|
|
|
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}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)
|
2025-10-28 10:57:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
case 'video':
|
|
|
|
|
|
if (post.media.urls && post.media.urls.length > 0) {
|
2025-10-18 20:04:24 +00:00
|
|
|
|
return (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<div
|
2025-10-28 10:57:32 +00:00
|
|
|
|
className="mt-3 rounded-lg overflow-hidden cursor-pointer relative group"
|
2025-10-18 20:04:24 +00:00
|
|
|
|
onClick={() => setLightboxOpen(true)}
|
|
|
|
|
|
>
|
2025-10-28 10:57:32 +00:00
|
|
|
|
<video
|
|
|
|
|
|
ref={videoRef}
|
|
|
|
|
|
src={post.media.urls[0]}
|
|
|
|
|
|
className="w-full max-h-96 object-cover"
|
|
|
|
|
|
controls
|
|
|
|
|
|
playsInline
|
|
|
|
|
|
muted
|
|
|
|
|
|
loop
|
2025-10-18 20:04:24 +00:00
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<MediaLightbox
|
|
|
|
|
|
isOpen={lightboxOpen}
|
|
|
|
|
|
onClose={() => setLightboxOpen(false)}
|
2025-10-28 10:57:32 +00:00
|
|
|
|
media={{ type: 'video', urls: [post.media.urls[0]] }}
|
2025-10-18 20:04:24 +00:00
|
|
|
|
/>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
case 'poll':
|
2025-10-28 10:57:32 +00:00
|
|
|
|
if (post.media.pollQuestion && post.media.pollOptions) {
|
|
|
|
|
|
const isExpired = post.media.pollEndsAt ? new Date() > post.media.pollEndsAt : false
|
|
|
|
|
|
const hasVoted = !!post.media.pollUserVoteId
|
|
|
|
|
|
const totalVotes = post.media.pollTotalVotes || 0
|
|
|
|
|
|
const pollUserVoteId = post.media.pollUserVoteId
|
2025-10-18 20:04:24 +00:00
|
|
|
|
|
|
|
|
|
|
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">
|
2025-10-28 10:57:32 +00:00
|
|
|
|
{post.media.pollQuestion}
|
2025-10-18 20:04:24 +00:00
|
|
|
|
</h4>
|
|
|
|
|
|
<div className="space-y-2">
|
2025-10-28 10:57:32 +00:00
|
|
|
|
{post.media.pollOptions.map((option) => {
|
|
|
|
|
|
const percentage = totalVotes > 0 ? (option.votes / totalVotes) * 100 : 0
|
|
|
|
|
|
const isSelected = pollUserVoteId === option.id
|
2025-10-18 20:04:24 +00:00
|
|
|
|
|
|
|
|
|
|
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">
|
2025-10-28 10:57:32 +00:00
|
|
|
|
{totalVotes} oy • {isExpired ? 'Sona erdi' : post.media.pollEndsAt ? dayjs(post.media.pollEndsAt).fromNow() + ' bitiyor' : ''}
|
2025-10-18 20:04:24 +00:00
|
|
|
|
</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-29 19:24:40 +00:00
|
|
|
|
src={post.employee.avatar || 'https://i.pravatar.cc/150?img=1'}
|
|
|
|
|
|
alt={post.employee.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={{
|
2025-10-29 19:24:40 +00:00
|
|
|
|
id: post.employee.id,
|
|
|
|
|
|
name: post.employee.fullName,
|
|
|
|
|
|
avatar: post.employee.avatar || 'https://i.pravatar.cc/150?img=1',
|
|
|
|
|
|
title: post.employee.jobPosition?.name || 'Çalışan',
|
|
|
|
|
|
email: post.employee.email,
|
2025-11-03 20:31:28 +00:00
|
|
|
|
phoneNumber: post.employee.phoneNumber,
|
2025-10-29 19:24:40 +00:00
|
|
|
|
department: post.employee.department?.name,
|
|
|
|
|
|
location: post.employee.workLocation
|
2025-10-27 21:08:36 +00:00
|
|
|
|
}}
|
|
|
|
|
|
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-29 19:24:40 +00:00
|
|
|
|
{post.employee.fullName}
|
2025-10-18 20:04:24 +00:00
|
|
|
|
</h3>
|
|
|
|
|
|
<p className="text-sm text-gray-600 dark:text-gray-400">
|
2025-10-29 19:24:40 +00:00
|
|
|
|
{post.employee.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 */}
|
2025-10-28 10:57:32 +00:00
|
|
|
|
{post.locationJson && (
|
2025-10-18 20:04:24 +00:00
|
|
|
|
<div className="mt-3">
|
2025-10-28 10:57:32 +00:00
|
|
|
|
<LocationMap location={post.locationJson} />
|
2025-10-18 20:04:24 +00:00
|
|
|
|
</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',
|
2025-10-28 10:57:32 +00:00
|
|
|
|
post.isLiked
|
2025-10-18 20:04:24 +00:00
|
|
|
|
? 'text-red-600 hover:text-red-700'
|
|
|
|
|
|
: 'text-gray-600 dark:text-gray-400 hover:text-red-600'
|
|
|
|
|
|
)}
|
|
|
|
|
|
>
|
2025-10-28 10:57:32 +00:00
|
|
|
|
{post.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
|
|
|
|
)}
|
2025-10-28 10:57:32 +00:00
|
|
|
|
<span className="text-sm font-medium">{post.likeCount}</span>
|
2025-10-18 20:04:24 +00:00
|
|
|
|
</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-28 10:57:32 +00:00
|
|
|
|
src={comment.creator.avatar || 'https://i.pravatar.cc/150?img=1'}
|
|
|
|
|
|
alt={comment.creator.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={{
|
2025-10-28 10:57:32 +00:00
|
|
|
|
id: comment.creator.id,
|
|
|
|
|
|
name: comment.creator.fullName,
|
|
|
|
|
|
avatar: comment.creator.avatar || 'https://i.pravatar.cc/150?img=1',
|
|
|
|
|
|
title: comment.creator.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-28 10:57:32 +00:00
|
|
|
|
{comment.creator.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
|