diff --git a/apps/web/src/components/admin/AdminDashboardView.tsx b/apps/web/src/components/admin/AdminDashboardView.tsx new file mode 100644 index 000000000..4772935cc --- /dev/null +++ b/apps/web/src/components/admin/AdminDashboardView.tsx @@ -0,0 +1,164 @@ + +import React, { useState, useEffect } from 'react'; +import { Card } from '../ui/card'; +import { Button } from '../ui/button'; +import { StatCard } from '../dashboard/StatCard'; +import { Users, DollarSign, Activity, AlertTriangle, HardDrive, ShoppingBag, ShieldAlert, CheckCircle, Loader2 } from 'lucide-react'; +import { adminService } from '../../services/adminService'; +import { Report } from '../../types'; +import { useToast } from '../../context/ToastContext'; +import { logger } from '@/utils/logger'; + +export const AdminDashboardView: React.FC = () => { + const { addToast } = useToast(); + const [stats, setStats] = useState({}); + const [reports, setReports] = useState([]); + const [uploads, setUploads] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchData = async () => { + setLoading(true); + try { + const [statsData, reportsData, uploadsData] = await Promise.all([ + adminService.getDashboardStats(), + adminService.getModerationQueue('pending'), + adminService.getRecentUploads() + ]); + setStats(statsData); + setReports(reportsData); + setUploads(uploadsData); + } catch (e) { + logger.error('Error loading admin dashboard data', { + error: e instanceof Error ? e.message : String(e), + stack: e instanceof Error ? e.stack : undefined, + }); + } finally { + setLoading(false); + } + }; + fetchData(); + }, []); + + const handleAction = async (id: string, action: string) => { + await adminService.resolveReport(id, action); + setReports(reports.filter(r => r.id !== id)); + addToast(`Report ${action}`, 'success'); + }; + + if (loading) return
; + + return ( +
+

SYSTEM OVERVIEW

+ + {/* Stats Grid */} +
+ } trend={stats.trends?.users} color="cyan" /> + } trend={stats.trends?.revenue} color="gold" /> + } trend={stats.trends?.sessions} color="lime" /> + } trend={stats.trends?.reports} color="red" /> +
+ +
+ + {/* Main Chart Area (Mock) */} + +
+

Traffic & Server Load

+
+
Traffic
+
CPU
+
+
+
+ {Array.from({length: 40}).map((_, i) => ( +
+
+
+
+ ))} +
+
+ + {/* Quick Actions */} +
+ +

Quick Actions

+
+ + + + +
+
+ + +

System Health

+
+
+ Database + Healthy +
+
+ Storage + 65% Used +
+
+ API Latency + 45ms +
+
+
+
+
+ +
+ {/* Recent Reports */} + +
+

Recent Reports

+ +
+
+ {reports.map(report => ( +
+
+
{report.targetName}
+
{report.targetType} • {report.reason}
+
+
+ + +
+
+ ))} + {reports.length === 0 &&
No pending reports.
} +
+
+ + {/* Recent Uploads */} + +
+

Moderation Queue

+ +
+
+ {uploads.map(upload => ( +
+
+
{upload.name}
+
{upload.user} • {upload.size}
+
+
+ + +
+
+ ))} +
+
+
+
+ ); +}; diff --git a/apps/web/src/components/admin/AdminModerationView.tsx b/apps/web/src/components/admin/AdminModerationView.tsx new file mode 100644 index 000000000..2b1b07e31 --- /dev/null +++ b/apps/web/src/components/admin/AdminModerationView.tsx @@ -0,0 +1,116 @@ + +import React, { useState, useEffect } from 'react'; +import { Card } from '../ui/card'; +import { Button } from '../ui/button'; +import { Badge } from '../ui/badge'; +import { Report } from '../../types'; +import { ShieldAlert, CheckCircle, Ban, MessageSquare, Clock, Loader2 } from 'lucide-react'; +import { useToast } from '../../context/ToastContext'; +import { adminService } from '../../services/adminService'; +import { logger } from '@/utils/logger'; + +export const AdminModerationView: React.FC = () => { + const { addToast } = useToast(); + const [queue, setQueue] = useState([]); + const [activeTab, setActiveTab] = useState<'pending' | 'reviewed' | 'resolved'>('pending'); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const loadQueue = async () => { + setLoading(true); + try { + const data = await adminService.getModerationQueue('all'); + setQueue(data); + } catch (e) { + logger.error('Error loading moderation queue', { + error: e instanceof Error ? e.message : String(e), + stack: e instanceof Error ? e.stack : undefined, + }); + } finally { + setLoading(false); + } + }; + loadQueue(); + }, []); + + const filteredQueue = queue.filter(r => + activeTab === 'pending' ? r.status === 'pending' : + activeTab === 'reviewed' ? r.status === 'reviewed' : + r.status === 'resolved' || r.status === 'dismissed' + ); + + const handleAction = async (id: string, action: string) => { + try { + await adminService.resolveReport(id, action); + addToast(`Report ${action}`, 'success'); + setQueue(queue.map(r => r.id === id ? { ...r, status: action === 'dismissed' ? 'dismissed' : 'resolved' } as any : r)); + } catch (e) { + addToast("Action failed", "error"); + } + }; + + return ( +
+

MODERATION QUEUE

+ +
+ {['pending', 'reviewed', 'resolved'].map(tab => ( + + ))} +
+ +
+ {loading &&
} + + {!loading && filteredQueue.length === 0 && ( +
+ +

All caught up! No reports in this queue.

+
+ )} + + {!loading && filteredQueue.map(report => ( + +
+
+
+ + {report.targetName} + + {report.timestamp} + +
+
+
Reason: {report.reason}
+

{report.description}

+
+
Reported by: {report.reportedBy}
+
+ +
+ + + + +
+
+
+ ))} +
+
+ ); +}; diff --git a/apps/web/src/components/admin/AdminSettingsView.tsx b/apps/web/src/components/admin/AdminSettingsView.tsx new file mode 100644 index 000000000..5a80e731d --- /dev/null +++ b/apps/web/src/components/admin/AdminSettingsView.tsx @@ -0,0 +1,105 @@ + +import React, { useState } from 'react'; +import { Card } from '../ui/card'; +import { Button } from '../ui/button'; +import { Save, AlertTriangle, Server, Activity } from 'lucide-react'; +import { useToast } from '../../context/ToastContext'; + +export const AdminSettingsView: React.FC = () => { + const { addToast } = useToast(); + const [maintenance, setMaintenance] = useState(false); + const [uploadLimit, setUploadLimit] = useState(500); // MB + const [announcement, setAnnouncement] = useState(''); + + const handleSave = () => { + addToast("System settings updated", "success"); + }; + + return ( +
+
+

SYSTEM SETTINGS

+ +
+ + {/* General Config */} + +

+ General Configuration +

+ +
+
+ + setUploadLimit(Number(e.target.value))} + /> +

Maximum file size for standard users.

+
+
+ + +
+
+
+ + {/* Feature Flags */} + +

+ Feature Flags +

+
+ {['Live Streaming', 'Marketplace Transactions', 'AI Mastering', 'Public Registrations'].map(feature => ( +
+ {feature} +
+
+
+
+ ))} +
+
+ + {/* Maintenance */} + +

+ Emergency & Maintenance +

+ +
+
+
+
Maintenance Mode
+
Disable access for non-admin users
+
+
setMaintenance(!maintenance)} + className={`w-12 h-6 rounded-full relative cursor-pointer transition-colors ${maintenance ? 'bg-kodo-red' : 'bg-gray-600'}`} + > +
+
+
+ +
+ +