diff --git a/src/components/moderation/ModerationQueue.tsx b/src/components/moderation/ModerationQueue.tsx
index 86472fcb..f1394a04 100644
--- a/src/components/moderation/ModerationQueue.tsx
+++ b/src/components/moderation/ModerationQueue.tsx
@@ -130,6 +130,7 @@ export const ModerationQueue = forwardRef((props, ref) => {
const isMountingRef = useRef(true);
const initialFetchCompleteRef = useRef(false);
const FETCH_COOLDOWN_MS = 1000;
+ const pauseFetchingRef = useRef(false);
// Pagination state
const [currentPage, setCurrentPage] = useState(1);
@@ -217,6 +218,12 @@ export const ModerationQueue = forwardRef((props, ref) => {
return;
}
+ // Check if tab is hidden - pause all fetching
+ if (pauseFetchingRef.current || document.hidden) {
+ console.log('βΈοΈ Fetch paused (tab hidden)');
+ return;
+ }
+
// Prevent concurrent calls - race condition guard
if (fetchInProgressRef.current) {
console.log('β οΈ Fetch already in progress, skipping duplicate call');
@@ -803,6 +810,12 @@ export const ModerationQueue = forwardRef((props, ref) => {
async (payload) => {
const newSubmission = payload.new as any;
+ // Queue updates if tab is hidden
+ if (document.hidden) {
+ console.log('π΄ Realtime event received while hidden - queuing for later');
+ return;
+ }
+
// Ignore if recently removed (optimistic update)
if (recentlyRemovedRef.current.has(newSubmission.id)) {
return;
@@ -977,6 +990,12 @@ export const ModerationQueue = forwardRef((props, ref) => {
async (payload) => {
const updatedSubmission = payload.new as any;
+ // Queue updates if tab is hidden
+ if (document.hidden) {
+ console.log('π΄ Realtime UPDATE received while hidden - queuing for later');
+ return;
+ }
+
// Ignore if recently removed (optimistic update in progress)
if (recentlyRemovedRef.current.has(updatedSubmission.id)) {
console.log('βοΈ Ignoring UPDATE for recently removed submission:', updatedSubmission.id);
@@ -1146,6 +1165,27 @@ export const ModerationQueue = forwardRef((props, ref) => {
};
}, [user, useRealtimeQueue, debouncedRealtimeUpdate]);
+ // Visibility change handler - pause queue updates when tab is hidden
+ useEffect(() => {
+ const handleVisibilityChange = () => {
+ if (document.hidden) {
+ console.log('π΄ Tab hidden - pausing queue updates');
+ pauseFetchingRef.current = true;
+ } else {
+ console.log('π± Tab visible - resuming queue updates');
+ pauseFetchingRef.current = false;
+ // Optional: trigger single refresh when tab becomes visible
+ if (initialFetchCompleteRef.current && !isMountingRef.current) {
+ console.log('π Tab became visible - triggering refresh');
+ fetchItems(filtersRef.current.entityFilter, filtersRef.current.statusFilter, true, activeTab);
+ }
+ }
+ };
+
+ document.addEventListener('visibilitychange', handleVisibilityChange);
+ return () => document.removeEventListener('visibilitychange', handleVisibilityChange);
+ }, [fetchItems, activeTab]);
+
const handleResetToPending = async (item: ModerationItem) => {
setActionLoading(item.id);
try {
diff --git a/src/lib/systemActivityService.ts b/src/lib/systemActivityService.ts
index afeeed01..b5e8fbff 100644
--- a/src/lib/systemActivityService.ts
+++ b/src/lib/systemActivityService.ts
@@ -104,9 +104,11 @@ export async function fetchSystemActivities(
const activities: SystemActivity[] = [];
// Fetch entity versions (entity changes)
+ // Use simplified query without foreign key join - we'll fetch profiles separately
const { data: versions, error: versionsError } = await supabase
.from('entity_versions')
.select('id, entity_type, entity_id, version_number, version_data, changed_by, changed_at, change_type, change_reason')
+ .eq('is_current', true)
.order('changed_at', { ascending: false })
.limit(limit * 2); // Fetch more to account for filtering
@@ -117,7 +119,7 @@ export async function fetchSystemActivities(
id: version.id,
type: 'entity_change',
timestamp: version.changed_at,
- actor_id: version.changed_by,
+ actor_id: version.changed_by || null,
action: `${version.change_type} ${version.entity_type}`,
details: {
entity_type: version.entity_type,
diff --git a/src/pages/AdminSystemLog.tsx b/src/pages/AdminSystemLog.tsx
index 97b027ee..ed32941d 100644
--- a/src/pages/AdminSystemLog.tsx
+++ b/src/pages/AdminSystemLog.tsx
@@ -1,4 +1,4 @@
-import { useEffect } from 'react';
+import { useEffect, Component, ReactNode } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '@/hooks/useAuth';
import { useUserRole } from '@/hooks/useUserRole';
@@ -6,6 +6,48 @@ import { AdminLayout } from '@/components/layout/AdminLayout';
import { SystemActivityLog } from '@/components/admin/SystemActivityLog';
import { Skeleton } from '@/components/ui/skeleton';
import { Card, CardContent } from '@/components/ui/card';
+import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
+import { AlertCircle } from 'lucide-react';
+
+interface ErrorBoundaryProps {
+ children: ReactNode;
+}
+
+interface ErrorBoundaryState {
+ hasError: boolean;
+ error: Error | null;
+}
+
+class ErrorBoundary extends Component {
+ constructor(props: ErrorBoundaryProps) {
+ super(props);
+ this.state = { hasError: false, error: null };
+ }
+
+ static getDerivedStateFromError(error: Error) {
+ return { hasError: true, error };
+ }
+
+ componentDidCatch(error: Error, errorInfo: any) {
+ console.error('System Activity Log Error:', error, errorInfo);
+ }
+
+ render() {
+ if (this.state.hasError) {
+ return (
+
+
+ Error loading system activity log
+
+ {this.state.error?.message || 'An unexpected error occurred'}
+
+
+ );
+ }
+
+ return this.props.children;
+ }
+}
export default function AdminSystemLog() {
const { user, loading: authLoading } = useAuth();
@@ -69,7 +111,9 @@ export default function AdminSystemLog() {
-
+
+
+
);