diff --git a/src/components/moderation/ModerationQueue.tsx b/src/components/moderation/ModerationQueue.tsx index 8b74c0bd..7b083382 100644 --- a/src/components/moderation/ModerationQueue.tsx +++ b/src/components/moderation/ModerationQueue.tsx @@ -56,6 +56,7 @@ export const ModerationQueue = forwardRef((props, ref) => { const isMobile = useIsMobile(); const [items, setItems] = useState([]); const [loading, setLoading] = useState(true); + const [isInitialLoad, setIsInitialLoad] = useState(true); const [actionLoading, setActionLoading] = useState(null); const [notes, setNotes] = useState>({}); const [activeEntityFilter, setActiveEntityFilter] = useState('all'); @@ -77,17 +78,20 @@ export const ModerationQueue = forwardRef((props, ref) => { // Expose refresh method via ref useImperativeHandle(ref, () => ({ refresh: () => { - fetchItems(activeEntityFilter, activeStatusFilter); + fetchItems(activeEntityFilter, activeStatusFilter, false); // Manual refresh shows loading } }), [activeEntityFilter, activeStatusFilter]); - const fetchItems = async (entityFilter: EntityFilter = 'all', statusFilter: StatusFilter = 'pending') => { + const fetchItems = async (entityFilter: EntityFilter = 'all', statusFilter: StatusFilter = 'pending', silent = false) => { if (!user) { return; } try { - setLoading(true); + // Only show loading on initial load or filter change + if (!silent) { + setLoading(true); + } let reviewStatuses: string[] = []; let submissionStatuses: string[] = []; @@ -346,29 +350,35 @@ export const ModerationQueue = forwardRef((props, ref) => { variant: "destructive", }); } finally { - setLoading(false); + // Only clear loading if it was set + if (!silent) { + setLoading(false); + } + if (isInitialLoad) { + setIsInitialLoad(false); + } } }; // Initial fetch on mount and filter changes useEffect(() => { if (user) { - fetchItems(activeEntityFilter, activeStatusFilter); + fetchItems(activeEntityFilter, activeStatusFilter, false); // Show loading } }, [activeEntityFilter, activeStatusFilter, user]); // Polling for auto-refresh useEffect(() => { - if (!user || refreshMode !== 'auto') return; + if (!user || refreshMode !== 'auto' || isInitialLoad) return; const interval = setInterval(() => { - fetchItems(activeEntityFilter, activeStatusFilter); + fetchItems(activeEntityFilter, activeStatusFilter, true); // Silent refresh }, pollInterval); return () => { clearInterval(interval); }; - }, [user, refreshMode, pollInterval, activeEntityFilter, activeStatusFilter]); + }, [user, refreshMode, pollInterval, activeEntityFilter, activeStatusFilter, isInitialLoad]); const handleResetToPending = async (item: ModerationItem) => { setActionLoading(item.id); diff --git a/src/components/moderation/ReportsQueue.tsx b/src/components/moderation/ReportsQueue.tsx index 2dcb9e7d..b07642f4 100644 --- a/src/components/moderation/ReportsQueue.tsx +++ b/src/components/moderation/ReportsQueue.tsx @@ -47,6 +47,7 @@ export interface ReportsQueueRef { export const ReportsQueue = forwardRef((props, ref) => { const [reports, setReports] = useState([]); const [loading, setLoading] = useState(true); + const [isInitialLoad, setIsInitialLoad] = useState(true); const [actionLoading, setActionLoading] = useState(null); const { toast } = useToast(); const { user } = useAuth(); @@ -58,11 +59,16 @@ export const ReportsQueue = forwardRef((props, ref) => { // Expose refresh method via ref useImperativeHandle(ref, () => ({ - refresh: fetchReports + refresh: () => fetchReports(false) // Manual refresh shows loading }), []); - const fetchReports = async () => { + const fetchReports = async (silent = false) => { try { + // Only show loading on initial load + if (!silent) { + setLoading(true); + } + const { data, error } = await supabase .from('reports') .select(` @@ -123,29 +129,35 @@ export const ReportsQueue = forwardRef((props, ref) => { variant: "destructive", }); } finally { - setLoading(false); + // Only clear loading if it was set + if (!silent) { + setLoading(false); + } + if (isInitialLoad) { + setIsInitialLoad(false); + } } }; // Initial fetch on mount useEffect(() => { if (user) { - fetchReports(); + fetchReports(false); // Show loading } }, [user]); // Polling for auto-refresh useEffect(() => { - if (!user || refreshMode !== 'auto') return; + if (!user || refreshMode !== 'auto' || isInitialLoad) return; const interval = setInterval(() => { - fetchReports(); + fetchReports(true); // Silent refresh }, pollInterval); return () => { clearInterval(interval); }; - }, [user, refreshMode, pollInterval]); + }, [user, refreshMode, pollInterval, isInitialLoad]); const handleReportAction = async (reportId: string, action: 'reviewed' | 'dismissed') => { setActionLoading(reportId); diff --git a/src/hooks/useModerationStats.ts b/src/hooks/useModerationStats.ts index dde6a2f8..714f608c 100644 --- a/src/hooks/useModerationStats.ts +++ b/src/hooks/useModerationStats.ts @@ -29,6 +29,7 @@ export const useModerationStats = (options: UseModerationStatsOptions = {}) => { }); const [isLoading, setIsLoading] = useState(true); + const [isInitialLoad, setIsInitialLoad] = useState(true); const [lastUpdated, setLastUpdated] = useState(null); const onStatsChangeRef = useRef(onStatsChange); @@ -37,11 +38,14 @@ export const useModerationStats = (options: UseModerationStatsOptions = {}) => { onStatsChangeRef.current = onStatsChange; }, [onStatsChange]); - const fetchStats = useCallback(async () => { + const fetchStats = useCallback(async (silent = false) => { if (!enabled) return; try { - setIsLoading(true); + // Only show loading on initial load + if (!silent) { + setIsLoading(true); + } const [submissionsResult, reportsResult, reviewsResult] = await Promise.all([ supabase @@ -70,27 +74,35 @@ export const useModerationStats = (options: UseModerationStatsOptions = {}) => { } catch (error) { console.error('Error fetching moderation stats:', error); } finally { - setIsLoading(false); + // Only clear loading if it was set + if (!silent) { + setIsLoading(false); + } + if (isInitialLoad) { + setIsInitialLoad(false); + } } - }, [enabled]); + }, [enabled, isInitialLoad]); // Initial fetch useEffect(() => { if (enabled) { - fetchStats(); + fetchStats(false); // Show loading } }, [enabled, fetchStats]); // Polling useEffect(() => { - if (!enabled || !pollingEnabled) return; + if (!enabled || !pollingEnabled || isInitialLoad) return; - const interval = setInterval(fetchStats, pollingInterval); + const interval = setInterval(() => { + fetchStats(true); // Silent refresh + }, pollingInterval); return () => { clearInterval(interval); }; - }, [enabled, pollingEnabled, pollingInterval, fetchStats]); + }, [enabled, pollingEnabled, pollingInterval, fetchStats, isInitialLoad]); return { stats,