From 68a2572c23e669ff3eaab38094edfe0114c2b405 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Mon, 13 Oct 2025 22:46:42 +0000 Subject: [PATCH] feat: Implement Phase 4 Streamlined Enhancements --- .../moderation/useModerationQueueManager.ts | 12 ++++++++ src/hooks/moderation/useQueueQuery.ts | 28 +++++++++++++------ .../moderation/useRealtimeSubscriptions.ts | 24 ++++++++++++++-- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/hooks/moderation/useModerationQueueManager.ts b/src/hooks/moderation/useModerationQueueManager.ts index 2bf837bb..d2b0e33d 100644 --- a/src/hooks/moderation/useModerationQueueManager.ts +++ b/src/hooks/moderation/useModerationQueueManager.ts @@ -184,6 +184,18 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig): } }, [queueQuery.isLoading, queueQuery.isRefreshing]); + // Show error toast when query fails + useEffect(() => { + if (queueQuery.error) { + console.error('❌ Queue query error:', queueQuery.error); + toast({ + variant: 'destructive', + title: 'Failed to Load Queue', + description: queueQuery.error.message || 'An error occurred while fetching the moderation queue.', + }); + } + }, [queueQuery.error, toast]); + // Update total count for pagination useEffect(() => { paginationRef.current.setTotalCount(queueQuery.totalCount); diff --git a/src/hooks/moderation/useQueueQuery.ts b/src/hooks/moderation/useQueueQuery.ts index 53085501..1adb08d8 100644 --- a/src/hooks/moderation/useQueueQuery.ts +++ b/src/hooks/moderation/useQueueQuery.ts @@ -8,7 +8,14 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; import { fetchSubmissions, type QueryConfig } from '@/lib/moderation/queries'; import { supabase } from '@/integrations/supabase/client'; -import type { ModerationItem } from '@/types/moderation'; +import type { + ModerationItem, + EntityFilter, + StatusFilter, + QueueTab, + SortField, + SortDirection +} from '@/types/moderation'; /** * Configuration for queue query @@ -24,13 +31,13 @@ export interface UseQueueQueryConfig { isSuperuser: boolean; /** Entity filter */ - entityFilter: string; + entityFilter: EntityFilter; /** Status filter */ - statusFilter: string; + statusFilter: StatusFilter; /** Active tab */ - tab: 'mainQueue' | 'archive'; + tab: QueueTab; /** Current page */ currentPage: number; @@ -40,8 +47,8 @@ export interface UseQueueQueryConfig { /** Sort configuration */ sortConfig: { - field: string; - direction: 'asc' | 'desc'; + field: SortField; + direction: SortDirection; }; /** Whether query is enabled (defaults to true) */ @@ -85,12 +92,12 @@ export function useQueueQuery(config: UseQueueQueryConfig): UseQueueQueryReturn userId: config.userId || '', isAdmin: config.isAdmin, isSuperuser: config.isSuperuser, - entityFilter: config.entityFilter as any, - statusFilter: config.statusFilter as any, + entityFilter: config.entityFilter, + statusFilter: config.statusFilter, tab: config.tab, currentPage: config.currentPage, pageSize: config.pageSize, - sortConfig: config.sortConfig as any, + sortConfig: config.sortConfig, }; // Create stable query key (TanStack Query uses this for caching/deduplication) @@ -113,6 +120,7 @@ export function useQueueQuery(config: UseQueueQueryConfig): UseQueueQueryReturn const result = await fetchSubmissions(supabase, queryConfig); if (result.error) { + console.error('❌ [TanStack Query] Error:', result.error); throw result.error; } @@ -122,6 +130,8 @@ export function useQueueQuery(config: UseQueueQueryConfig): UseQueueQueryReturn enabled: config.enabled !== false && !!config.userId, staleTime: 30000, // 30 seconds gcTime: 5 * 60 * 1000, // 5 minutes + retry: 2, // Retry failed requests up to 2 times + retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), // Exponential backoff }); // Invalidate helper diff --git a/src/hooks/moderation/useRealtimeSubscriptions.ts b/src/hooks/moderation/useRealtimeSubscriptions.ts index 4228b55f..96c1b5ec 100644 --- a/src/hooks/moderation/useRealtimeSubscriptions.ts +++ b/src/hooks/moderation/useRealtimeSubscriptions.ts @@ -47,7 +47,7 @@ export interface RealtimeSubscriptionConfig { /** Pause subscriptions when tab is hidden (default: true) */ pauseWhenHidden?: boolean; - /** Debounce delay for UPDATE events in milliseconds (default: 1000) */ + /** Debounce delay for UPDATE events in milliseconds (default: 500) */ debounceMs?: number; /** Entity cache for resolving entity names */ @@ -95,7 +95,7 @@ export function useRealtimeSubscriptions( onUpdateItem, onItemRemoved, pauseWhenHidden = true, - debounceMs = 1000, + debounceMs = 500, entityCache, profileCache, recentlyRemovedIds, @@ -314,6 +314,7 @@ export function useRealtimeSubscriptions( */ const handleUpdate = useCallback(async (payload: any) => { const updatedSubmission = payload.new as any; + const oldSubmission = payload.old as any; console.log('🔄 Realtime UPDATE:', updatedSubmission.id); @@ -335,7 +336,24 @@ export function useRealtimeSubscriptions( return; } - // Debounce the update + // Skip debounce for status changes (critical updates) + const isStatusChange = oldSubmission?.status !== updatedSubmission.status; + + if (isStatusChange) { + console.log('⚡ Status change detected, invalidating immediately'); + await queryClient.invalidateQueries({ queryKey: ['moderation-queue'] }); + + const matchesEntity = matchesEntityFilter(updatedSubmission, filters.entityFilter); + const matchesStatus = matchesStatusFilter(updatedSubmission, filters.statusFilter); + const shouldBeInQueue = matchesEntity && matchesStatus; + + if (!shouldBeInQueue) { + onItemRemoved(updatedSubmission.id); + } + return; // Skip debounced update + } + + // Use debounce for non-critical updates debouncedUpdate(updatedSubmission.id, async () => { console.log('🔄 Invalidating query due to UPDATE:', updatedSubmission.id);