mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 02:31:12 -05:00
Fix: Add dashboard widget for flow violations
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useRef, useEffect, useCallback, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { FileText, Flag, AlertCircle, Activity } from 'lucide-react';
|
||||
import { FileText, Flag, AlertCircle, Activity, ShieldAlert } from 'lucide-react';
|
||||
import { useUserRole } from '@/hooks/useUserRole';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
@@ -12,6 +12,8 @@ import { ReportsQueue } from '@/components/moderation/ReportsQueue';
|
||||
import { RecentActivity } from '@/components/moderation/RecentActivity';
|
||||
import { useModerationStats } from '@/hooks/useModerationStats';
|
||||
import { useAdminSettings } from '@/hooks/useAdminSettings';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
|
||||
export default function AdminDashboard() {
|
||||
const { user, loading: authLoading } = useAuth();
|
||||
@@ -19,6 +21,7 @@ export default function AdminDashboard() {
|
||||
const navigate = useNavigate();
|
||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState('moderation');
|
||||
const [suspiciousVersionsCount, setSuspiciousVersionsCount] = useState<number>(0);
|
||||
|
||||
const moderationQueueRef = useRef<ModerationQueueRef>(null);
|
||||
const reportsQueueRef = useRef<any>(null);
|
||||
@@ -38,9 +41,28 @@ export default function AdminDashboard() {
|
||||
pollingInterval: pollInterval,
|
||||
});
|
||||
|
||||
// Check for suspicious versions (bypassed submission flow)
|
||||
const checkSuspiciousVersions = useCallback(async () => {
|
||||
if (!user || !isModerator()) return;
|
||||
|
||||
const { count, error } = await supabase
|
||||
.from('entity_versions')
|
||||
.select('*', { count: 'exact', head: true })
|
||||
.is('changed_by', null);
|
||||
|
||||
if (!error && count !== null) {
|
||||
setSuspiciousVersionsCount(count);
|
||||
}
|
||||
}, [user, isModerator]);
|
||||
|
||||
useEffect(() => {
|
||||
checkSuspiciousVersions();
|
||||
}, [checkSuspiciousVersions]);
|
||||
|
||||
const handleRefresh = useCallback(async () => {
|
||||
setIsRefreshing(true);
|
||||
await refreshStats();
|
||||
await checkSuspiciousVersions();
|
||||
|
||||
// Refresh active tab's content
|
||||
switch (activeTab) {
|
||||
@@ -56,7 +78,7 @@ export default function AdminDashboard() {
|
||||
}
|
||||
|
||||
setTimeout(() => setIsRefreshing(false), 500);
|
||||
}, [refreshStats, activeTab]);
|
||||
}, [refreshStats, checkSuspiciousVersions, activeTab]);
|
||||
|
||||
const handleStatCardClick = (cardType: 'submissions' | 'reports' | 'flagged') => {
|
||||
switch (cardType) {
|
||||
@@ -143,6 +165,17 @@ export default function AdminDashboard() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Security Warning for Suspicious Versions */}
|
||||
{suspiciousVersionsCount > 0 && (
|
||||
<Alert variant="destructive" className="border-red-500/50 bg-red-500/10">
|
||||
<ShieldAlert className="h-5 w-5" />
|
||||
<AlertDescription className="ml-2">
|
||||
<strong>Security Alert:</strong> {suspiciousVersionsCount} entity version{suspiciousVersionsCount !== 1 ? 's' : ''} detected without user attribution.
|
||||
This may indicate submission flow bypass. Check admin audit logs for details.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
{statCards.map((card) => {
|
||||
const Icon = card.icon;
|
||||
|
||||
Reference in New Issue
Block a user