From 065b1b4be5584121230c06581e3e839d4df08b35 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sat, 4 Oct 2025 19:16:36 +0000 Subject: [PATCH] Reverted to commit 095907b3a5834ecda1bb67145ad6d665d314daca --- src/App.tsx | 10 +- src/components/admin/UserManagement.tsx | 52 +++-- src/components/layout/AdminHeader.tsx | 29 +-- src/components/layout/AdminLayout.tsx | 62 ------ src/components/layout/AdminSidebar.tsx | 148 -------------- src/components/layout/AdminTopBar.tsx | 38 ---- src/components/moderation/ProfileManager.tsx | 93 +++++---- src/components/moderation/ReportsQueue.tsx | 51 ++--- src/components/moderation/UserRoleManager.tsx | 66 +++---- src/pages/Admin.tsx | 183 +++++++++--------- src/pages/AdminDashboard.tsx | 116 ----------- src/pages/AdminModeration.tsx | 22 --- src/pages/AdminReports.tsx | 22 --- src/pages/AdminSettings.tsx | 30 +-- src/pages/AdminUsers.tsx | 15 -- 15 files changed, 257 insertions(+), 680 deletions(-) delete mode 100644 src/components/layout/AdminLayout.tsx delete mode 100644 src/components/layout/AdminSidebar.tsx delete mode 100644 src/components/layout/AdminTopBar.tsx delete mode 100644 src/pages/AdminDashboard.tsx delete mode 100644 src/pages/AdminModeration.tsx delete mode 100644 src/pages/AdminReports.tsx delete mode 100644 src/pages/AdminUsers.tsx diff --git a/src/App.tsx b/src/App.tsx index de92886b..5fdb92ca 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -33,10 +33,7 @@ import NotFound from "./pages/NotFound"; import Terms from "./pages/Terms"; import Privacy from "./pages/Privacy"; import SubmissionGuidelines from "./pages/SubmissionGuidelines"; -import AdminDashboard from "./pages/AdminDashboard"; -import AdminModeration from "./pages/AdminModeration"; -import AdminReports from "./pages/AdminReports"; -import AdminUsers from "./pages/AdminUsers"; +import Admin from "./pages/Admin"; import AdminSettings from "./pages/AdminSettings"; const queryClient = new QueryClient(); @@ -74,10 +71,7 @@ function AppContent() { } /> } /> } /> - } /> - } /> - } /> - } /> + } /> } /> } /> } /> diff --git a/src/components/admin/UserManagement.tsx b/src/components/admin/UserManagement.tsx index 5bc137d2..d7558783 100644 --- a/src/components/admin/UserManagement.tsx +++ b/src/components/admin/UserManagement.tsx @@ -4,26 +4,38 @@ import { ProfileManager } from '@/components/moderation/ProfileManager'; import { UserRoleManager } from '@/components/moderation/UserRoleManager'; import { Users, Shield, UserCheck, UserX } from 'lucide-react'; export function UserManagement() { - return ( - - - - - Users - - - - Roles - - + return
+ + + + + + + Users + + + + Roles + + - - - + + + + + + + + - - - - - ); + + + + + + + + + +
; } \ No newline at end of file diff --git a/src/components/layout/AdminHeader.tsx b/src/components/layout/AdminHeader.tsx index 2ef0cd3b..02ec6125 100644 --- a/src/components/layout/AdminHeader.tsx +++ b/src/components/layout/AdminHeader.tsx @@ -27,23 +27,26 @@ export function AdminHeader({ onRefresh }: { onRefresh?: () => void }) { const pageTitle = isSettingsPage ? 'Admin Settings' : 'Admin Dashboard'; return ( -
-
+
+
{/* Left Section - Navigation */} -
+
-
+
-

- Admin - {pageTitle} -

+
+ +

+ Admin + {pageTitle} +

+
{/* Right Section - Admin actions */} @@ -91,16 +94,16 @@ export function AdminHeader({ onRefresh }: { onRefresh?: () => void }) { size="sm" onClick={onRefresh} title="Refresh admin data" - className="hidden md:flex gap-2" + className="hidden md:flex" > - Refresh + Refresh {permissions?.role_level === 'superuser' && !isSettingsPage && ( - )} diff --git a/src/components/layout/AdminLayout.tsx b/src/components/layout/AdminLayout.tsx deleted file mode 100644 index 5fa4fa0b..00000000 --- a/src/components/layout/AdminLayout.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { ReactNode, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { SidebarProvider } from '@/components/ui/sidebar'; -import { AdminSidebar } from './AdminSidebar'; -import { AdminTopBar } from './AdminTopBar'; -import { useAuth } from '@/hooks/useAuth'; -import { useUserRole } from '@/hooks/useUserRole'; - -interface AdminLayoutProps { - children: ReactNode; - onRefresh?: () => void; - isRefreshing?: boolean; -} - -export function AdminLayout({ children, onRefresh, isRefreshing }: AdminLayoutProps) { - const { user, loading: authLoading } = useAuth(); - const { isModerator, loading: roleLoading } = useUserRole(); - const navigate = useNavigate(); - - useEffect(() => { - if (!authLoading && !roleLoading) { - if (!user) { - navigate('/auth'); - return; - } - - if (!isModerator()) { - navigate('/'); - return; - } - } - }, [user, authLoading, roleLoading, navigate, isModerator]); - - if (authLoading || roleLoading) { - return ( -
-
-
-

Loading admin panel...

-
-
- ); - } - - if (!user || !isModerator()) { - return null; - } - - return ( - -
- -
- -
- {children} -
-
-
-
- ); -} diff --git a/src/components/layout/AdminSidebar.tsx b/src/components/layout/AdminSidebar.tsx deleted file mode 100644 index 1f9e73c5..00000000 --- a/src/components/layout/AdminSidebar.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import { LayoutDashboard, FileText, Flag, Users, Settings, ArrowLeft } from 'lucide-react'; -import { NavLink, useLocation } from 'react-router-dom'; -import { - Sidebar, - SidebarContent, - SidebarGroup, - SidebarGroupContent, - SidebarGroupLabel, - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, - SidebarFooter, - SidebarHeader, - useSidebar, -} from '@/components/ui/sidebar'; -import { cn } from '@/lib/utils'; -import { useUserRole } from '@/hooks/useUserRole'; - -const navigationItems = [ - { - title: 'Dashboard', - url: '/admin', - icon: LayoutDashboard, - }, - { - title: 'Moderation Queue', - url: '/admin/moderation', - icon: FileText, - }, - { - title: 'Reports', - url: '/admin/reports', - icon: Flag, - }, - { - title: 'User Management', - url: '/admin/users', - icon: Users, - }, -]; - -export function AdminSidebar() { - const location = useLocation(); - const { state } = useSidebar(); - const { isSuperuser } = useUserRole(); - const isCollapsed = state === 'collapsed'; - - const isActive = (path: string) => { - if (path === '/admin') { - return location.pathname === '/admin'; - } - return location.pathname.startsWith(path); - }; - - return ( - - -
-
- TW -
- {!isCollapsed && ( -
- ThrillWiki - Admin Panel -
- )} -
-
- - - - Navigation - - - {navigationItems.map((item) => ( - - - - cn( - 'flex items-center gap-3 rounded-md transition-colors', - isActive - ? 'bg-primary/10 text-primary font-medium' - : 'hover:bg-muted/50' - ) - } - > - - {!isCollapsed && {item.title}} - - - - ))} - - {isSuperuser() && ( - - - - cn( - 'flex items-center gap-3 rounded-md transition-colors', - isActive - ? 'bg-primary/10 text-primary font-medium' - : 'hover:bg-muted/50' - ) - } - > - - {!isCollapsed && Settings} - - - - )} - - - - - - - - - - - - {!isCollapsed && Back to ThrillWiki} - - - - - -
- ); -} diff --git a/src/components/layout/AdminTopBar.tsx b/src/components/layout/AdminTopBar.tsx deleted file mode 100644 index f182ce35..00000000 --- a/src/components/layout/AdminTopBar.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { RefreshCw } from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import { SidebarTrigger } from '@/components/ui/sidebar'; -import { ThemeToggle } from '@/components/theme/ThemeToggle'; -import { NotificationCenter } from '@/components/notifications/NotificationCenter'; -import { AuthButtons } from '@/components/auth/AuthButtons'; - -interface AdminTopBarProps { - onRefresh?: () => void; - isRefreshing?: boolean; -} - -export function AdminTopBar({ onRefresh, isRefreshing }: AdminTopBarProps) { - return ( -
- - - {onRefresh && ( - - )} - -
- - - -
-
- ); -} diff --git a/src/components/moderation/ProfileManager.tsx b/src/components/moderation/ProfileManager.tsx index 52fe11cb..8ab41c4d 100644 --- a/src/components/moderation/ProfileManager.tsx +++ b/src/components/moderation/ProfileManager.tsx @@ -264,32 +264,32 @@ export function ProfileManager() { } return ( -
- {/* Filters - compact single row */} -
+
+ {/* Filters */} +
setSearchTerm(e.target.value)} - className="pl-10 h-9" + className="pl-10" />
)} @@ -425,10 +422,10 @@ export function ProfileManager() { ))} {filteredProfiles.length === 0 && ( -
- -

No Users Found

-

+

+ +

No Users Found

+

No users match your current filters.

diff --git a/src/components/moderation/ReportsQueue.tsx b/src/components/moderation/ReportsQueue.tsx index c2f48718..b07642f4 100644 --- a/src/components/moderation/ReportsQueue.tsx +++ b/src/components/moderation/ReportsQueue.tsx @@ -212,44 +212,47 @@ export const ReportsQueue = forwardRef((props, ref) => { } return ( -
+
{reports.map((report) => ( - - -
-
- + + +
+
+ {REPORT_TYPE_LABELS[report.report_type as keyof typeof REPORT_TYPE_LABELS]} - + {report.reported_entity_type}
-
- - {format(new Date(report.created_at), 'MMM d, HH:mm')} +
+ + {format(new Date(report.created_at), 'MMM d, yyyy HH:mm')}
{report.reporter_profile && ( -
- - +
+ + Reported by: + {report.reporter_profile.display_name || report.reporter_profile.username} {report.reporter_profile.display_name && ( - @{report.reporter_profile.username} + + @{report.reporter_profile.username} + )}
)} - + {report.reason && (
- -

+ +

{report.reason}

@@ -257,17 +260,17 @@ export const ReportsQueue = forwardRef((props, ref) => { {report.reported_content && (
- -
+ +
{report.reported_entity_type === 'review' && (
{report.reported_content.title && ( -

{report.reported_content.title}

+

{report.reported_content.title}

)} {report.reported_content.content && ( -

{report.reported_content.content}

+

{report.reported_content.content}

)} -
+
Rating: {report.reported_content.rating}/5
@@ -276,11 +279,10 @@ export const ReportsQueue = forwardRef((props, ref) => {
)} -
+
; } const filteredRoles = userRoles.filter(role => role.profiles?.username?.toLowerCase().includes(searchTerm.toLowerCase()) || role.profiles?.display_name?.toLowerCase().includes(searchTerm.toLowerCase()) || role.role.toLowerCase().includes(searchTerm.toLowerCase())); - return
+ return
{/* Add new role */} - - - Grant Role - - -
+ + + +
- +
- - setNewUserSearch(e.target.value)} className="pl-10 h-9 mt-1" /> + + setNewUserSearch(e.target.value)} className="pl-10" />
- {searchResults.length > 0 &&
- {searchResults.map(profile =>
{ + {searchResults.length > 0 &&
+ {searchResults.map(profile =>
{ setNewUserSearch(profile.display_name || profile.username); setSearchResults([profile]); }}>
{profile.display_name || profile.username}
- {profile.display_name &&
+ {profile.display_name &&
@{profile.username}
}
)} @@ -210,10 +208,10 @@ export function UserRoleManager() {
- + setSearchTerm(e.target.value)} className="pl-10 h-9 mt-1" /> + + setSearchTerm(e.target.value)} className="pl-10" />
{/* User roles list */} -
- {filteredRoles.length === 0 ?
- -

No roles found

-

- {searchTerm ? 'No users match your search.' : 'No user roles granted yet.'} +

+ {filteredRoles.length === 0 ?
+ +

No roles found

+

+ {searchTerm ? 'No users match your search criteria.' : 'No user roles have been granted yet.'}

-
: filteredRoles.map(userRole => - -
-
-
+
: filteredRoles.map(userRole => + +
+
+
{userRole.profiles?.display_name || userRole.profiles?.username}
- {userRole.profiles?.display_name &&
+ {userRole.profiles?.display_name &&
@{userRole.profiles.username}
}
- + {userRole.role}
{/* Only show revoke button if current user can manage this role */} - {(isSuperuser() || isAdmin() && !['admin', 'superuser'].includes(userRole.role)) && } diff --git a/src/pages/Admin.tsx b/src/pages/Admin.tsx index 96c638e9..8e4f8139 100644 --- a/src/pages/Admin.tsx +++ b/src/pages/Admin.tsx @@ -79,118 +79,109 @@ export default function Admin() { return ( <> -
- {/* Refresh status indicator - subtle */} -
- - {refreshMode === 'auto' ? ( - Auto-refresh: every {pollInterval / 1000}s - ) : ( - Manual refresh - )} - {lastUpdated && ( - • {lastUpdated.toLocaleTimeString()} - )} +
+
+ {/* Refresh status indicator */} +
+
+ + {refreshMode === 'auto' ? ( + Auto-refresh: every {pollInterval / 1000}s + ) : ( + Manual refresh only + )} + {lastUpdated && ( + + • Last updated: {lastUpdated.toLocaleTimeString()} + + )} +
- {/* Stats cards - horizontal layout */} -
- - -
-
-
- -
-
-

Pending

-

Submissions

-
-
-
- {stats.pendingSubmissions} -
+ {/* Stats cards */} +
+ + + + Pending Submissions + + +
+ {stats.pendingSubmissions}
- - -
-
-
- -
-
-

Open

-

Reports

-
-
-
- {stats.openReports} -
+ + + + Open Reports + + +
+ {stats.openReports}
- - -
-
-
- -
-
-

Flagged

-

Content

-
-
-
- {stats.flaggedContent} -
+ + + + Flagged Content + + +
+ {stats.flaggedContent}
+
- {/* Content Moderation Section - flatter design */} -
-
-

- - Moderation Queue -

- - - - - {isMobile ? 'Queue' : 'Moderation Queue'} - - - - Reports - - - - - - - - - - - -
+ {/* Content Moderation Section */} + + + + + Moderation Queue + + + + + + + + {isMobile ? 'Queue' : 'Moderation Queue'} + + + + Reports + + + + + + + + + + + + + - {/* User Management Section - flatter design */} -
-

- - User Management -

- -
-
+ {/* User Management Section */} + + + + + User Management + + + + + +
); diff --git a/src/pages/AdminDashboard.tsx b/src/pages/AdminDashboard.tsx deleted file mode 100644 index bd62a375..00000000 --- a/src/pages/AdminDashboard.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import { useRef, useCallback } from 'react'; -import { RefreshCw, FileText, Flag, AlertCircle } from 'lucide-react'; -import { Card, CardContent } from '@/components/ui/card'; -import { AdminLayout } from '@/components/layout/AdminLayout'; -import { useModerationStats } from '@/hooks/useModerationStats'; -import { useAdminSettings } from '@/hooks/useAdminSettings'; -import { useAuth } from '@/hooks/useAuth'; -import { useUserRole } from '@/hooks/useUserRole'; - -export default function AdminDashboard() { - const { user, loading: authLoading } = useAuth(); - const { isModerator, loading: roleLoading } = useUserRole(); - - // Get admin settings for polling configuration - const { - getAdminPanelRefreshMode, - getAdminPanelPollInterval, - } = useAdminSettings(); - - const refreshMode = getAdminPanelRefreshMode(); - const pollInterval = getAdminPanelPollInterval(); - - // Use stats hook with configurable polling - const { stats, refresh: refreshStats, lastUpdated } = useModerationStats({ - enabled: !!user && !authLoading && !roleLoading && isModerator(), - pollingEnabled: refreshMode === 'auto', - pollingInterval: pollInterval, - }); - - const handleRefresh = useCallback(() => { - refreshStats(); - }, [refreshStats]); - - return ( - -
- {/* Refresh status indicator */} -
- - {refreshMode === 'auto' ? ( - Auto-refresh: every {pollInterval / 1000}s - ) : ( - Manual refresh - )} - {lastUpdated && ( - • {lastUpdated.toLocaleTimeString()} - )} -
- - {/* Stats Overview */} -
-

Dashboard Overview

- -
- - -
-
-
- -
-
-

Pending

-

Submissions

-
-
-
- {stats.pendingSubmissions} -
-
-
-
- - - -
-
-
- -
-
-

Open

-

Reports

-
-
-
- {stats.openReports} -
-
-
-
- - - -
-
-
- -
-
-

Flagged

-

Content

-
-
-
- {stats.flaggedContent} -
-
-
-
-
-
-
-
- ); -} diff --git a/src/pages/AdminModeration.tsx b/src/pages/AdminModeration.tsx deleted file mode 100644 index 68783bff..00000000 --- a/src/pages/AdminModeration.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { useRef, useCallback } from 'react'; -import { AdminLayout } from '@/components/layout/AdminLayout'; -import { ModerationQueue, ModerationQueueRef } from '@/components/moderation/ModerationQueue'; - -export default function AdminModeration() { - const moderationQueueRef = useRef(null); - - const handleRefresh = useCallback(() => { - moderationQueueRef.current?.refresh(); - }, []); - - return ( - -
-
-

Moderation Queue

- -
-
-
- ); -} diff --git a/src/pages/AdminReports.tsx b/src/pages/AdminReports.tsx deleted file mode 100644 index 5c3c3ceb..00000000 --- a/src/pages/AdminReports.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { useRef, useCallback } from 'react'; -import { AdminLayout } from '@/components/layout/AdminLayout'; -import { ReportsQueue, ReportsQueueRef } from '@/components/moderation/ReportsQueue'; - -export default function AdminReports() { - const reportsQueueRef = useRef(null); - - const handleRefresh = useCallback(() => { - reportsQueueRef.current?.refresh(); - }, []); - - return ( - -
-
-

Reports Queue

- -
-
-
- ); -} diff --git a/src/pages/AdminSettings.tsx b/src/pages/AdminSettings.tsx index 0a9997f4..632bdada 100644 --- a/src/pages/AdminSettings.tsx +++ b/src/pages/AdminSettings.tsx @@ -7,7 +7,7 @@ import { Switch } from '@/components/ui/switch'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Badge } from '@/components/ui/badge'; -import { AdminLayout } from '@/components/layout/AdminLayout'; +import { AdminHeader } from '@/components/layout/AdminHeader'; import { useAuth } from '@/hooks/useAuth'; import { useUserRole } from '@/hooks/useUserRole'; import { useAdminSettings } from '@/hooks/useAdminSettings'; @@ -28,18 +28,20 @@ export default function AdminSettings() { if (roleLoading || isLoading) { return ( - + <> +
-
+ ); } if (!user || !isSuperuser()) { return ( - -
+ <> + +

Access Denied

You don't have permission to access admin settings.

@@ -50,14 +52,15 @@ export default function AdminSettings() { )}
- + ); } if (!settings || settings.length === 0) { return ( - -
+ <> + +

No Settings Found

@@ -70,7 +73,7 @@ export default function AdminSettings() { )}

- + ); } @@ -428,10 +431,11 @@ export default function AdminSettings() { }; return ( - -
+ <> + +
-

Admin Settings

+

Admin Settings

Configure system-wide settings and preferences with easy-to-use controls

@@ -594,6 +598,6 @@ export default function AdminSettings() {
- + ); } \ No newline at end of file diff --git a/src/pages/AdminUsers.tsx b/src/pages/AdminUsers.tsx deleted file mode 100644 index 30a1fd5a..00000000 --- a/src/pages/AdminUsers.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { AdminLayout } from '@/components/layout/AdminLayout'; -import { UserManagement } from '@/components/admin/UserManagement'; - -export default function AdminUsers() { - return ( - -
-
-

User Management

- -
-
-
- ); -}