sozsoft-platform/ui/src/views/forum/admin/Dashboard.tsx

153 lines
4.9 KiB
TypeScript
Raw Normal View History

2026-02-24 20:44:16 +00:00
import { FaFolder, FaCommentDots, FaFileAlt, FaChartLine } from 'react-icons/fa'
import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum'
import { useLocalization } from '@/utils/hooks/useLocalization'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import 'dayjs/locale/tr'
interface AdminStatsProps {
categories: ForumCategory[]
topics: ForumTopic[]
posts: ForumPost[]
}
interface Activity {
message: string
color: string
date: Date
}
export function AdminStats({ categories, topics, posts }: AdminStatsProps) {
const { translate } = useLocalization()
const totalCategories = categories.length
const activeCategories = categories.filter((c) => c.isActive).length
const totalTopics = topics.length
const solvedTopics = topics.filter((t) => t.isSolved).length
const totalPosts = posts.length
const acceptedAnswers = posts.filter((p) => p.isAcceptedAnswer).length
const stats = [
{
title: translate('::App.Forum.Dashboard.TotalCategories'),
value: totalCategories,
subtitle: `${activeCategories} active`,
icon: FaFolder,
color: 'bg-blue-500',
},
{
title: translate('::App.Forum.Dashboard.TotalTopics'),
value: totalTopics,
subtitle: `${solvedTopics} solved`,
icon: FaCommentDots,
color: 'bg-emerald-500',
},
{
title: translate('::App.Forum.Dashboard.TotalPosts'),
value: totalPosts,
subtitle: `${acceptedAnswers} accepted answers`,
icon: FaFileAlt,
color: 'bg-orange-500',
},
{
title: translate('::App.Forum.Dashboard.EngagementRate'),
value: totalTopics > 0 ? Math.round((totalPosts / totalTopics) * 100) / 100 : 0,
subtitle: 'posts per topic',
icon: FaChartLine,
color: 'bg-purple-500',
},
]
const recentActivities: Activity[] = []
dayjs.extend(relativeTime)
dayjs.locale('tr')
topics.forEach((topic) => {
const category = categories.find((c) => c.id === topic.categoryId)
if (topic.creationTime) {
recentActivities.push({
message: `New topic created in ${category?.name ?? 'Unknown Category'}`,
color: 'bg-blue-500',
date: new Date(topic.creationTime),
})
}
})
// Posts -> "Post marked as accepted answer"
posts.forEach((post) => {
if (post.isAcceptedAnswer && post.creationTime) {
recentActivities.push({
message: 'Post marked as accepted answer',
color: 'bg-emerald-500',
date: new Date(post.creationTime),
})
}
})
// Categories -> "New category created: {name}"
categories.forEach((category) => {
if (category.creationTime) {
recentActivities.push({
message: `New category created: ${category.name}`,
color: 'bg-orange-500',
date: new Date(category.creationTime),
})
}
})
// Tarihe göre sırala, en güncel ilk 3 aktiviteyi al
const latestActivities = recentActivities
.sort((a, b) => b.date.getTime() - a.date.getTime())
.slice(0, 3)
return (
<div className="space-y-8">
<div>
<h2 className="text-2xl font-bold text-gray-900 mb-6">
{translate('::App.Forum.Dashboard.Statistics')}
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{stats.map((stat, index) => {
const Icon = stat.icon
return (
<div key={index} className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
<div className="flex items-center justify-between mb-4">
<div
className={`w-12 h-12 ${stat.color} rounded-lg flex items-center justify-center`}
>
<Icon className="w-6 h-6 text-white" />
</div>
</div>
<div>
<h3 className="text-2xl font-bold text-gray-900 mb-1">{stat.value}</h3>
<p className="text-sm font-medium text-gray-600 mb-1">{stat.title}</p>
<p className="text-xs text-gray-500">{stat.subtitle}</p>
</div>
</div>
)
})}
</div>
</div>
{/* Recent Activity */}
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
<h3 className="text-lg font-semibold text-gray-900 mb-4">
{translate('::App.Forum.Dashboard.RecentActivity')}
</h3>
<div className="space-y-4">
{latestActivities.map((activity, index) => (
<div key={index} className="flex items-start space-x-3 p-3 bg-gray-50 rounded-lg">
<div className={`w-2 h-2 ${activity.color} rounded-full mt-2`} />
<div>
<p className="text-sm text-gray-900">{activity.message}</p>
<p className="text-xs text-gray-500">{dayjs(activity.date).fromNow()}</p>
</div>
</div>
))}
</div>
</div>
</div>
)
}