erp-platform/ui/src/views/intranet/SocialWall/index.tsx

213 lines
6.4 KiB
TypeScript
Raw Normal View History

2025-10-18 20:04:24 +00:00
import React, { useState } from 'react'
import { AnimatePresence } from 'framer-motion'
import PostItem from './PostItem'
2025-10-27 21:08:36 +00:00
import { SocialMedia } from '@/types/intranet'
2025-10-18 20:04:24 +00:00
import CreatePost from './CreatePost'
2025-10-28 10:57:32 +00:00
import { SocialPost } from '@/types/intranet'
2025-10-27 21:08:36 +00:00
import { HrEmployee } from '@/types/hr'
2025-10-20 18:48:22 +00:00
import { mockSocialPosts } from '@/mocks/mockIntranet'
2025-10-27 21:08:36 +00:00
import { mockEmployees } from '@/mocks/mockEmployees'
2025-10-18 20:04:24 +00:00
const SocialWall: React.FC = () => {
const [posts, setPosts] = useState<SocialPost[]>(mockSocialPosts)
const [filter, setFilter] = useState<'all' | 'mine'>('all')
2025-10-27 21:08:36 +00:00
// Ali Öztürk'ü "Siz" kullanıcısı olarak kullan
const currentUserAuthor: HrEmployee = { ...mockEmployees[0], fullName: 'Siz' }
2025-10-18 20:04:24 +00:00
const handleCreatePost = (postData: {
content: string
2025-10-28 10:57:32 +00:00
location?: string
2025-10-18 20:04:24 +00:00
media?: {
type: 'mixed' | 'poll'
2025-10-27 21:08:36 +00:00
mediaItems?: SocialMedia[]
2025-10-18 20:04:24 +00:00
poll?: {
question: string
options: Array<{ text: string }>
}
}
}) => {
let mediaForPost = undefined
if (postData.media) {
if (postData.media.type === 'mixed' && postData.media.mediaItems) {
// Convert MediaItems to post format
const images = postData.media.mediaItems.filter(m => m.type === 'image')
const videos = postData.media.mediaItems.filter(m => m.type === 'video')
if (images.length > 0 && videos.length === 0) {
mediaForPost = {
type: 'image' as const,
2025-10-28 10:57:32 +00:00
urls: images.map(i => i.urls?.[0]).filter(url => url !== undefined) as string[]
2025-10-18 20:04:24 +00:00
}
} else if (videos.length > 0 && images.length === 0) {
mediaForPost = {
type: 'video' as const,
2025-10-28 10:57:32 +00:00
urls: videos[0].urls || []
2025-10-18 20:04:24 +00:00
}
} else if (images.length > 0 || videos.length > 0) {
// Mixed media - use first image for now
mediaForPost = {
type: 'image' as const,
2025-10-28 10:57:32 +00:00
urls: images.map(i => i.urls?.[0]).filter(url => url !== undefined) as string[]
2025-10-18 20:04:24 +00:00
}
}
} else if (postData.media.type === 'poll' && postData.media.poll) {
mediaForPost = {
type: 'poll' as const,
2025-10-28 10:57:32 +00:00
pollQuestion: postData.media.poll.question,
pollOptions: postData.media.poll.options.map((opt, index) => ({
id: `opt-${index}`,
text: opt.text,
votes: 0
})),
pollTotalVotes: 0,
pollEndsAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
2025-10-18 20:04:24 +00:00
}
}
}
const newPost: SocialPost = {
id: Date.now().toString(),
2025-10-28 10:57:32 +00:00
creator: currentUserAuthor,
2025-10-18 20:04:24 +00:00
content: postData.content,
2025-10-20 18:38:21 +00:00
creationTime: new Date(),
2025-10-18 20:04:24 +00:00
media: mediaForPost,
2025-10-28 10:57:32 +00:00
locationJson: postData.location,
likeCount: 0,
isLiked: false,
likeUsers: [],
2025-10-18 20:04:24 +00:00
comments: [],
isOwnPost: true
}
setPosts([newPost, ...posts])
}
const handleLike = (postId: string) => {
setPosts(
posts.map((post) => {
if (post.id === postId) {
return {
...post,
2025-10-28 10:57:32 +00:00
likeCount: post.isLiked ? post.likeCount - 1 : post.likeCount + 1,
isLiked: !post.isLiked
2025-10-18 20:04:24 +00:00
}
}
return post
})
)
}
const handleComment = (postId: string, content: string) => {
setPosts(
posts.map((post) => {
if (post.id === postId) {
2025-10-27 21:08:36 +00:00
const commentAuthor = currentUserAuthor
2025-10-18 20:04:24 +00:00
const newComment = {
id: Date.now().toString(),
2025-10-28 10:57:32 +00:00
creator: commentAuthor,
2025-10-18 20:04:24 +00:00
content,
2025-10-20 18:38:21 +00:00
creationTime: new Date()
2025-10-18 20:04:24 +00:00
}
return {
...post,
comments: [...post.comments, newComment]
}
}
return post
})
)
}
const handleDelete = (postId: string) => {
if (window.confirm('Bu gönderiyi silmek istediğinizden emin misiniz?')) {
setPosts(posts.filter((post) => post.id !== postId))
}
}
const handleVote = (postId: string, optionId: string) => {
setPosts(
posts.map((post) => {
2025-10-28 10:57:32 +00:00
if (post.id === postId && post.media?.type === 'poll' && post.media.pollOptions) {
2025-10-18 20:04:24 +00:00
// If user already voted, don't allow voting again
2025-10-28 10:57:32 +00:00
if (post.media.pollUserVoteId) {
2025-10-18 20:04:24 +00:00
return post
}
return {
...post,
media: {
...post.media,
2025-10-28 10:57:32 +00:00
pollOptions: post.media.pollOptions.map((opt) =>
opt.id === optionId ? { ...opt, votes: opt.votes + 1 } : opt
),
pollTotalVotes: (post.media.pollTotalVotes || 0) + 1,
pollUserVoteId: optionId
2025-10-18 20:04:24 +00:00
}
}
}
return post
})
)
}
const filteredPosts = filter === 'mine' ? posts.filter((post) => post.isOwnPost) : posts
return (
2025-10-20 13:11:46 +00:00
<div className="mx-auto px-4">
2025-10-18 20:04:24 +00:00
{/* Filter Tabs */}
<div className="flex gap-4 mb-6 border-b border-gray-200 dark:border-gray-700">
<button
onClick={() => setFilter('all')}
className={`pb-3 px-1 border-b-2 transition-colors font-medium ${
filter === 'all'
? 'border-blue-600 text-blue-600'
: 'border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200'
}`}
>
Tüm Gönderiler
</button>
<button
onClick={() => setFilter('mine')}
className={`pb-3 px-1 border-b-2 transition-colors font-medium ${
filter === 'mine'
? 'border-blue-600 text-blue-600'
: 'border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200'
}`}
>
Gönderilerim
</button>
</div>
{/* Create Post */}
<CreatePost onCreatePost={handleCreatePost} />
{/* Posts Feed */}
<AnimatePresence>
{filteredPosts.length > 0 ? (
filteredPosts.map((post) => (
<PostItem
key={post.id}
post={post}
onLike={handleLike}
onComment={handleComment}
onDelete={handleDelete}
onVote={handleVote}
/>
))
) : (
<div className="text-center py-12">
<p className="text-gray-500 dark:text-gray-400 text-lg">
{filter === 'mine' ? 'Henüz bir gönderi paylaşmadınız.' : 'Henüz gönderi yok.'}
</p>
</div>
)}
</AnimatePresence>
</div>
)
}
export default SocialWall