source: chapterx-frontend/src/pages/admin/AdminDashboard.tsx@ 0b502c2

main
Last change on this file since 0b502c2 was b62cefc, checked in by kikisrbinoska <srbinoskakristina07@…>, 4 months ago

Added frontend and imporoved AI Suggestions service

  • Property mode set to 100644
File size: 5.8 KB
Line 
1import React from 'react'
2import { useNavigate } from 'react-router-dom'
3import { Shield, Users, BookOpen, AlertTriangle, Settings, ChevronRight } from 'lucide-react'
4import { useAuthStore } from '../../store/authStore'
5import { useStoryStore } from '../../store/storyStore'
6import { useNotificationStore } from '../../store/notificationStore'
7import { PlatformStats } from '../../components/admin/PlatformStats'
8import { Button } from '../../components/ui/Button'
9import { RoleBadge } from '../../components/ui/Badge'
10import { Avatar } from '../../components/ui/Avatar'
11
12function timeAgo(str: string): string {
13 const diff = Date.now() - new Date(str).getTime()
14 const m = Math.floor(diff / 60000)
15 if (m < 1) return 'just now'
16 if (m < 60) return `${m}m ago`
17 const h = Math.floor(m / 60)
18 if (h < 24) return `${h}h ago`
19 return `${Math.floor(h / 24)}d ago`
20}
21
22export const AdminDashboard: React.FC = () => {
23 const navigate = useNavigate()
24 const { allUsers } = useAuthStore()
25 const { stories } = useStoryStore()
26 const { notifications } = useNotificationStore()
27
28 const recentUsers = [...allUsers].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()).slice(0, 5)
29 const recentStories = [...stories].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()).slice(0, 5)
30
31 const adminLinks = [
32 { to: '/admin/users', icon: <Users size={20} className="text-blue-400" />, label: 'Manage Users', desc: `${allUsers.length} registered users`, color: 'bg-blue-500/10 border-blue-500/20' },
33 { to: '/admin/content', icon: <BookOpen size={20} className="text-violet-400" />, label: 'Content Moderation', desc: `${stories.length} total stories`, color: 'bg-violet-500/10 border-violet-500/20' },
34 { to: '/admin/genres', icon: <Settings size={20} className="text-amber-400" />, label: 'Manage Genres', desc: 'Add or remove genres', color: 'bg-amber-500/10 border-amber-500/20' },
35 ]
36
37 return (
38 <div className="max-w-7xl mx-auto px-4 py-8">
39 {/* Header */}
40 <div className="flex items-center gap-3 mb-8">
41 <div className="w-10 h-10 rounded-xl bg-rose-500/20 flex items-center justify-center">
42 <Shield size={20} className="text-rose-400" />
43 </div>
44 <div>
45 <h1 className="font-serif text-3xl font-bold text-white">Admin Dashboard</h1>
46 <p className="text-slate-400 text-sm mt-0.5">Platform management and moderation</p>
47 </div>
48 </div>
49
50 {/* Platform stats */}
51 <div className="mb-8">
52 <h2 className="font-serif text-xl font-bold text-white mb-4">Platform Overview</h2>
53 <PlatformStats />
54 </div>
55
56 {/* Quick links */}
57 <div className="grid grid-cols-1 sm:grid-cols-3 gap-4 mb-8">
58 {adminLinks.map(link => (
59 <button
60 key={link.to}
61 onClick={() => navigate(link.to)}
62 className={`flex items-center gap-4 p-5 rounded-2xl border ${link.color} hover:scale-105 transition-all group text-left`}
63 >
64 <div className="w-12 h-12 rounded-xl bg-slate-800 flex items-center justify-center">
65 {link.icon}
66 </div>
67 <div className="flex-1">
68 <p className="text-white font-semibold">{link.label}</p>
69 <p className="text-slate-400 text-sm">{link.desc}</p>
70 </div>
71 <ChevronRight size={16} className="text-slate-500 group-hover:text-white transition-colors" />
72 </button>
73 ))}
74 </div>
75
76 <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
77 {/* Recent users */}
78 <div className="bg-slate-800 border border-slate-700 rounded-2xl p-6">
79 <div className="flex items-center justify-between mb-4">
80 <h3 className="font-serif text-lg font-bold text-white">Recent Users</h3>
81 <Button size="sm" variant="ghost" onClick={() => navigate('/admin/users')}>
82 View all <ChevronRight size={14} />
83 </Button>
84 </div>
85 <div className="space-y-3">
86 {recentUsers.map(user => (
87 <div key={user.user_id} className="flex items-center gap-3">
88 <Avatar name={user.name} size="sm" />
89 <div className="flex-1 min-w-0">
90 <p className="text-white text-sm font-medium">{user.name} {user.surname}</p>
91 <p className="text-slate-500 text-xs">@{user.username}</p>
92 </div>
93 <RoleBadge role={user.role} />
94 </div>
95 ))}
96 </div>
97 </div>
98
99 {/* Recent stories */}
100 <div className="bg-slate-800 border border-slate-700 rounded-2xl p-6">
101 <div className="flex items-center justify-between mb-4">
102 <h3 className="font-serif text-lg font-bold text-white">Recent Stories</h3>
103 <Button size="sm" variant="ghost" onClick={() => navigate('/admin/content')}>
104 View all <ChevronRight size={14} />
105 </Button>
106 </div>
107 <div className="space-y-3">
108 {recentStories.map(story => (
109 <div key={story.story_id} className="flex items-center gap-3">
110 <div className="flex-1 min-w-0">
111 <p className="text-white text-sm font-medium truncate">{story.title}</p>
112 <p className="text-slate-500 text-xs">by @{story.author_username}</p>
113 </div>
114 <span className={`text-xs px-2 py-0.5 rounded-full ${
115 story.status === 'published'
116 ? 'bg-emerald-500/20 text-emerald-400'
117 : story.status === 'draft'
118 ? 'bg-amber-500/20 text-amber-400'
119 : 'bg-slate-500/20 text-slate-400'
120 }`}>
121 {story.status}
122 </span>
123 </div>
124 ))}
125 </div>
126 </div>
127 </div>
128 </div>
129 )
130}
Note: See TracBrowser for help on using the repository browser.