feat: Implement Phase 5 optimization and best practices

This commit is contained in:
gpt-engineer-app[bot]
2025-10-13 22:56:47 +00:00
parent 68a2572c23
commit 3e520e1520
14 changed files with 341 additions and 165 deletions

View File

@@ -8,6 +8,8 @@
import { useEffect, useRef, useState, useCallback } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { supabase } from '@/integrations/supabase/client';
import { logger } from '@/lib/logger';
import { MODERATION_CONSTANTS } from '@/lib/moderation/constants';
import type { RealtimeChannel } from '@supabase/supabase-js';
import type { ModerationItem, EntityFilter, StatusFilter } from '@/types/moderation';
import type { useEntityCache } from './useEntityCache';
@@ -47,7 +49,7 @@ export interface RealtimeSubscriptionConfig {
/** Pause subscriptions when tab is hidden (default: true) */
pauseWhenHidden?: boolean;
/** Debounce delay for UPDATE events in milliseconds (default: 500) */
/** Debounce delay for UPDATE events in milliseconds */
debounceMs?: number;
/** Entity cache for resolving entity names */
@@ -95,7 +97,7 @@ export function useRealtimeSubscriptions(
onUpdateItem,
onItemRemoved,
pauseWhenHidden = true,
debounceMs = 500,
debounceMs = MODERATION_CONSTANTS.REALTIME_DEBOUNCE_MS,
entityCache,
profileCache,
recentlyRemovedIds,
@@ -151,7 +153,7 @@ export function useRealtimeSubscriptions(
.single();
if (error || !submission) {
console.error('Error fetching submission details:', error);
logger.error('Error fetching submission details:', error);
return null;
}
@@ -243,17 +245,17 @@ export function useRealtimeSubscriptions(
const handleInsert = useCallback(async (payload: any) => {
const newSubmission = payload.new as any;
console.log('🆕 Realtime INSERT:', newSubmission.id);
logger.log('🆕 Realtime INSERT:', newSubmission.id);
// Queue updates if tab is hidden
if (pauseWhenHidden && document.hidden) {
console.log('📴 Realtime event received while hidden - queuing for later');
logger.log('📴 Realtime event received while hidden - queuing for later');
return;
}
// Ignore if recently removed (optimistic update)
if (recentlyRemovedIds.has(newSubmission.id)) {
console.log('⏭️ Ignoring INSERT for recently removed submission:', newSubmission.id);
logger.log('⏭️ Ignoring INSERT for recently removed submission:', newSubmission.id);
return;
}
@@ -271,7 +273,7 @@ export function useRealtimeSubscriptions(
return;
}
console.log('✅ NEW submission matches filters, invalidating query:', newSubmission.id);
logger.log('✅ NEW submission matches filters, invalidating query:', newSubmission.id);
// Invalidate the query to trigger background refetch
await queryClient.invalidateQueries({ queryKey: ['moderation-queue'] });
@@ -296,7 +298,7 @@ export function useRealtimeSubscriptions(
onNewItem(fullItem);
} catch (error) {
console.error('Error building new item notification:', error);
logger.error('Error building new item notification:', error);
}
}, [
filters,
@@ -316,23 +318,23 @@ export function useRealtimeSubscriptions(
const updatedSubmission = payload.new as any;
const oldSubmission = payload.old as any;
console.log('🔄 Realtime UPDATE:', updatedSubmission.id);
logger.log('🔄 Realtime UPDATE:', updatedSubmission.id);
// Queue updates if tab is hidden
if (pauseWhenHidden && document.hidden) {
console.log('📴 Realtime UPDATE received while hidden - queuing for later');
logger.log('📴 Realtime UPDATE received while hidden - queuing for later');
return;
}
// Ignore if recently removed (optimistic update in progress)
if (recentlyRemovedIds.has(updatedSubmission.id)) {
console.log('⏭️ Ignoring UPDATE for recently removed submission:', updatedSubmission.id);
logger.log('⏭️ Ignoring UPDATE for recently removed submission:', updatedSubmission.id);
return;
}
// Ignore if currently being interacted with
if (interactingWithIds.has(updatedSubmission.id)) {
console.log('⏭️ Ignoring UPDATE for interacting submission:', updatedSubmission.id);
logger.log('⏭️ Ignoring UPDATE for interacting submission:', updatedSubmission.id);
return;
}
@@ -340,7 +342,7 @@ export function useRealtimeSubscriptions(
const isStatusChange = oldSubmission?.status !== updatedSubmission.status;
if (isStatusChange) {
console.log('⚡ Status change detected, invalidating immediately');
logger.log('⚡ Status change detected, invalidating immediately');
await queryClient.invalidateQueries({ queryKey: ['moderation-queue'] });
const matchesEntity = matchesEntityFilter(updatedSubmission, filters.entityFilter);
@@ -355,7 +357,7 @@ export function useRealtimeSubscriptions(
// Use debounce for non-critical updates
debouncedUpdate(updatedSubmission.id, async () => {
console.log('🔄 Invalidating query due to UPDATE:', updatedSubmission.id);
logger.log('🔄 Invalidating query due to UPDATE:', updatedSubmission.id);
// Simply invalidate the query - TanStack Query handles the rest
await queryClient.invalidateQueries({ queryKey: ['moderation-queue'] });
@@ -388,7 +390,7 @@ export function useRealtimeSubscriptions(
return;
}
console.log('📡 Setting up INSERT subscription');
logger.log('📡 Setting up INSERT subscription');
const channel = supabase
.channel('moderation-new-submissions')
@@ -402,7 +404,7 @@ export function useRealtimeSubscriptions(
handleInsert
)
.subscribe((status) => {
console.log('INSERT subscription status:', status);
logger.log('INSERT subscription status:', status);
if (status === 'SUBSCRIBED') {
setChannelStatus('connected');
} else if (status === 'CHANNEL_ERROR') {
@@ -413,7 +415,7 @@ export function useRealtimeSubscriptions(
insertChannelRef.current = channel;
return () => {
console.log('🛑 Cleaning up INSERT subscription');
logger.log('🛑 Cleaning up INSERT subscription');
supabase.removeChannel(channel);
insertChannelRef.current = null;
};
@@ -425,7 +427,7 @@ export function useRealtimeSubscriptions(
useEffect(() => {
if (!enabled) return;
console.log('📡 Setting up UPDATE subscription');
logger.log('📡 Setting up UPDATE subscription');
const channel = supabase
.channel('moderation-updated-submissions')
@@ -439,7 +441,7 @@ export function useRealtimeSubscriptions(
handleUpdate
)
.subscribe((status) => {
console.log('UPDATE subscription status:', status);
logger.log('UPDATE subscription status:', status);
if (status === 'SUBSCRIBED') {
setChannelStatus('connected');
} else if (status === 'CHANNEL_ERROR') {
@@ -450,7 +452,7 @@ export function useRealtimeSubscriptions(
updateChannelRef.current = channel;
return () => {
console.log('🛑 Cleaning up UPDATE subscription');
logger.log('🛑 Cleaning up UPDATE subscription');
supabase.removeChannel(channel);
updateChannelRef.current = null;
};
@@ -470,7 +472,7 @@ export function useRealtimeSubscriptions(
* Manual reconnect function
*/
const reconnect = useCallback(() => {
console.log('🔄 Manually reconnecting subscriptions...');
logger.log('🔄 Manually reconnecting subscriptions...');
setReconnectTrigger(prev => prev + 1);
}, []);