Implement real-time features

This commit is contained in:
gpt-engineer-app[bot]
2025-09-30 16:46:12 +00:00
parent 7bbf67156b
commit 7920bdb911
7 changed files with 313 additions and 85 deletions

View File

@@ -11,6 +11,7 @@ import { ReportsQueue } from '@/components/moderation/ReportsQueue';
import { UserManagement } from '@/components/admin/UserManagement';
import { AdminHeader } from '@/components/layout/AdminHeader';
import { supabase } from '@/integrations/supabase/client';
import { useRealtimeModerationStats } from '@/hooks/useRealtimeModerationStats';
export default function Admin() {
const { user, loading: authLoading } = useAuth();
@@ -18,76 +19,19 @@ export default function Admin() {
const navigate = useNavigate();
const moderationQueueRef = useRef<ModerationQueueRef>(null);
// State for dashboard stats
const [stats, setStats] = useState({
pendingSubmissions: 0,
openReports: 0,
flaggedContent: 0,
loading: true,
// Use realtime stats hook for live updates
const { stats: realtimeStats, refresh: refreshStats } = useRealtimeModerationStats({
onStatsChange: (newStats) => {
console.log('Stats updated in real-time:', newStats);
},
enabled: !!user && !authLoading && !roleLoading && isModerator(),
});
const [isFetching, setIsFetching] = useState(false);
const fetchStats = useCallback(async () => {
if (!user || isFetching) {
console.log('Skipping stats fetch - user not authenticated or already fetching');
return;
}
setIsFetching(true);
try {
setStats(prev => ({ ...prev, loading: true }));
// Fetch pending submissions count
const { count: pendingCount, error: submissionsError } = await supabase
.from('content_submissions')
.select('*', { count: 'exact', head: true })
.eq('status', 'pending');
if (submissionsError) {
console.error('Error fetching pending submissions:', submissionsError);
throw submissionsError;
}
// Fetch open reports count
const { count: reportsCount, error: reportsError } = await supabase
.from('reports')
.select('*', { count: 'exact', head: true })
.eq('status', 'pending');
if (reportsError) {
console.error('Error fetching reports:', reportsError);
throw reportsError;
}
// Fetch flagged content count (reviews)
const { count: flaggedCount, error: flaggedError } = await supabase
.from('reviews')
.select('*', { count: 'exact', head: true })
.eq('moderation_status', 'flagged');
if (flaggedError) {
console.error('Error fetching flagged content:', flaggedError);
throw flaggedError;
}
setStats({
pendingSubmissions: pendingCount || 0,
openReports: reportsCount || 0,
flaggedContent: flaggedCount || 0,
loading: false,
});
} catch (error: any) {
console.error('Error fetching admin stats:', error);
console.error('Error details:', {
message: error.message,
code: error.code,
details: error.details
});
setStats(prev => ({ ...prev, loading: false }));
} finally {
setIsFetching(false);
}
}, []);
refreshStats();
}, [refreshStats]);
const handleRefresh = useCallback(() => {
moderationQueueRef.current?.refresh();
@@ -105,11 +49,8 @@ export default function Admin() {
navigate('/');
return;
}
// Fetch stats when user is authenticated and authorized
fetchStats();
}
}, [user, authLoading, roleLoading, navigate]);
}, [user, authLoading, roleLoading, navigate, isModerator]);
if (authLoading || roleLoading) {
return (
@@ -146,11 +87,7 @@ export default function Admin() {
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">
{stats.loading ? (
<span className="animate-pulse">--</span>
) : (
stats.pendingSubmissions
)}
{realtimeStats.pendingSubmissions}
</div>
<p className="text-xs text-muted-foreground">
Content submissions awaiting moderation
@@ -165,11 +102,7 @@ export default function Admin() {
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">
{stats.loading ? (
<span className="animate-pulse">--</span>
) : (
stats.openReports
)}
{realtimeStats.openReports}
</div>
<p className="text-xs text-muted-foreground">
User reports to review
@@ -184,11 +117,7 @@ export default function Admin() {
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">
{stats.loading ? (
<span className="animate-pulse">--</span>
) : (
stats.flaggedContent
)}
{realtimeStats.flaggedContent}
</div>
<p className="text-xs text-muted-foreground">
Auto-flagged items