mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 01:51:12 -05:00
feat: Implement Phase 4 Streamlined Enhancements
This commit is contained in:
@@ -184,6 +184,18 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
|||||||
}
|
}
|
||||||
}, [queueQuery.isLoading, queueQuery.isRefreshing]);
|
}, [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
|
// Update total count for pagination
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
paginationRef.current.setTotalCount(queueQuery.totalCount);
|
paginationRef.current.setTotalCount(queueQuery.totalCount);
|
||||||
|
|||||||
@@ -8,7 +8,14 @@
|
|||||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
import { fetchSubmissions, type QueryConfig } from '@/lib/moderation/queries';
|
import { fetchSubmissions, type QueryConfig } from '@/lib/moderation/queries';
|
||||||
import { supabase } from '@/integrations/supabase/client';
|
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
|
* Configuration for queue query
|
||||||
@@ -24,13 +31,13 @@ export interface UseQueueQueryConfig {
|
|||||||
isSuperuser: boolean;
|
isSuperuser: boolean;
|
||||||
|
|
||||||
/** Entity filter */
|
/** Entity filter */
|
||||||
entityFilter: string;
|
entityFilter: EntityFilter;
|
||||||
|
|
||||||
/** Status filter */
|
/** Status filter */
|
||||||
statusFilter: string;
|
statusFilter: StatusFilter;
|
||||||
|
|
||||||
/** Active tab */
|
/** Active tab */
|
||||||
tab: 'mainQueue' | 'archive';
|
tab: QueueTab;
|
||||||
|
|
||||||
/** Current page */
|
/** Current page */
|
||||||
currentPage: number;
|
currentPage: number;
|
||||||
@@ -40,8 +47,8 @@ export interface UseQueueQueryConfig {
|
|||||||
|
|
||||||
/** Sort configuration */
|
/** Sort configuration */
|
||||||
sortConfig: {
|
sortConfig: {
|
||||||
field: string;
|
field: SortField;
|
||||||
direction: 'asc' | 'desc';
|
direction: SortDirection;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Whether query is enabled (defaults to true) */
|
/** Whether query is enabled (defaults to true) */
|
||||||
@@ -85,12 +92,12 @@ export function useQueueQuery(config: UseQueueQueryConfig): UseQueueQueryReturn
|
|||||||
userId: config.userId || '',
|
userId: config.userId || '',
|
||||||
isAdmin: config.isAdmin,
|
isAdmin: config.isAdmin,
|
||||||
isSuperuser: config.isSuperuser,
|
isSuperuser: config.isSuperuser,
|
||||||
entityFilter: config.entityFilter as any,
|
entityFilter: config.entityFilter,
|
||||||
statusFilter: config.statusFilter as any,
|
statusFilter: config.statusFilter,
|
||||||
tab: config.tab,
|
tab: config.tab,
|
||||||
currentPage: config.currentPage,
|
currentPage: config.currentPage,
|
||||||
pageSize: config.pageSize,
|
pageSize: config.pageSize,
|
||||||
sortConfig: config.sortConfig as any,
|
sortConfig: config.sortConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create stable query key (TanStack Query uses this for caching/deduplication)
|
// 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);
|
const result = await fetchSubmissions(supabase, queryConfig);
|
||||||
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
|
console.error('❌ [TanStack Query] Error:', result.error);
|
||||||
throw result.error;
|
throw result.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,6 +130,8 @@ export function useQueueQuery(config: UseQueueQueryConfig): UseQueueQueryReturn
|
|||||||
enabled: config.enabled !== false && !!config.userId,
|
enabled: config.enabled !== false && !!config.userId,
|
||||||
staleTime: 30000, // 30 seconds
|
staleTime: 30000, // 30 seconds
|
||||||
gcTime: 5 * 60 * 1000, // 5 minutes
|
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
|
// Invalidate helper
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export interface RealtimeSubscriptionConfig {
|
|||||||
/** Pause subscriptions when tab is hidden (default: true) */
|
/** Pause subscriptions when tab is hidden (default: true) */
|
||||||
pauseWhenHidden?: boolean;
|
pauseWhenHidden?: boolean;
|
||||||
|
|
||||||
/** Debounce delay for UPDATE events in milliseconds (default: 1000) */
|
/** Debounce delay for UPDATE events in milliseconds (default: 500) */
|
||||||
debounceMs?: number;
|
debounceMs?: number;
|
||||||
|
|
||||||
/** Entity cache for resolving entity names */
|
/** Entity cache for resolving entity names */
|
||||||
@@ -95,7 +95,7 @@ export function useRealtimeSubscriptions(
|
|||||||
onUpdateItem,
|
onUpdateItem,
|
||||||
onItemRemoved,
|
onItemRemoved,
|
||||||
pauseWhenHidden = true,
|
pauseWhenHidden = true,
|
||||||
debounceMs = 1000,
|
debounceMs = 500,
|
||||||
entityCache,
|
entityCache,
|
||||||
profileCache,
|
profileCache,
|
||||||
recentlyRemovedIds,
|
recentlyRemovedIds,
|
||||||
@@ -314,6 +314,7 @@ export function useRealtimeSubscriptions(
|
|||||||
*/
|
*/
|
||||||
const handleUpdate = useCallback(async (payload: any) => {
|
const handleUpdate = useCallback(async (payload: any) => {
|
||||||
const updatedSubmission = payload.new as any;
|
const updatedSubmission = payload.new as any;
|
||||||
|
const oldSubmission = payload.old as any;
|
||||||
|
|
||||||
console.log('🔄 Realtime UPDATE:', updatedSubmission.id);
|
console.log('🔄 Realtime UPDATE:', updatedSubmission.id);
|
||||||
|
|
||||||
@@ -335,7 +336,24 @@ export function useRealtimeSubscriptions(
|
|||||||
return;
|
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 () => {
|
debouncedUpdate(updatedSubmission.id, async () => {
|
||||||
console.log('🔄 Invalidating query due to UPDATE:', updatedSubmission.id);
|
console.log('🔄 Invalidating query due to UPDATE:', updatedSubmission.id);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user