mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 06:31:13 -05:00
feat: Implement Phase 5 optimization and best practices
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { useState, useCallback, useRef, useEffect, useMemo } from "react";
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { logger } from "@/lib/logger";
|
||||
import { MODERATION_CONSTANTS } from "@/lib/moderation/constants";
|
||||
import type { User } from "@supabase/supabase-js";
|
||||
import {
|
||||
useEntityCache,
|
||||
@@ -71,7 +73,7 @@ export interface ModerationQueueManager {
|
||||
* Consolidates all queue-related logic into a single hook
|
||||
*/
|
||||
export function useModerationQueueManager(config: ModerationQueueManagerConfig): ModerationQueueManager {
|
||||
console.log('🚀 [QUEUE MANAGER] Hook mounting/rendering', {
|
||||
logger.log('🚀 [QUEUE MANAGER] Hook mounting/rendering', {
|
||||
hasUser: !!config.user,
|
||||
isAdmin: config.isAdmin,
|
||||
timestamp: new Date().toISOString()
|
||||
@@ -169,7 +171,7 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
||||
useEffect(() => {
|
||||
if (queueQuery.items) {
|
||||
setItems(queueQuery.items);
|
||||
console.log('✅ Queue items updated from TanStack Query:', queueQuery.items.length);
|
||||
logger.log('✅ Queue items updated from TanStack Query:', queueQuery.items.length);
|
||||
}
|
||||
}, [queueQuery.items]);
|
||||
|
||||
@@ -187,7 +189,7 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
||||
// Show error toast when query fails
|
||||
useEffect(() => {
|
||||
if (queueQuery.error) {
|
||||
console.error('❌ Queue query error:', queueQuery.error);
|
||||
logger.error('❌ Queue query error:', queueQuery.error);
|
||||
toast({
|
||||
variant: 'destructive',
|
||||
title: 'Failed to Load Queue',
|
||||
@@ -205,7 +207,7 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
||||
useEffect(() => {
|
||||
if (!queueQuery.isLoading && !initialFetchCompleteRef.current) {
|
||||
initialFetchCompleteRef.current = true;
|
||||
console.log('✅ Initial queue fetch complete');
|
||||
logger.log('✅ Initial queue fetch complete');
|
||||
}
|
||||
}, [queueQuery.isLoading]);
|
||||
|
||||
@@ -213,7 +215,7 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
||||
* Manual refresh function
|
||||
*/
|
||||
const refresh = useCallback(async () => {
|
||||
console.log('🔄 Manual refresh triggered');
|
||||
logger.log('🔄 Manual refresh triggered');
|
||||
await queueQuery.refetch();
|
||||
}, [queueQuery]);
|
||||
|
||||
@@ -221,7 +223,7 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
||||
* Show pending new items by invalidating query
|
||||
*/
|
||||
const showNewItems = useCallback(async () => {
|
||||
console.log('✅ Showing new items via query invalidation');
|
||||
logger.log('✅ Showing new items via query invalidation');
|
||||
await queueQuery.invalidate();
|
||||
setPendingNewItems([]);
|
||||
setNewItemsCount(0);
|
||||
@@ -521,16 +523,25 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
||||
[filters.statusFilter, toast],
|
||||
);
|
||||
|
||||
// Extract stable callbacks for dependencies
|
||||
const invalidateQuery = useCallback(() => {
|
||||
queueQuery.invalidate();
|
||||
}, [queueQuery.invalidate]);
|
||||
|
||||
const resetPagination = useCallback(() => {
|
||||
pagination.reset();
|
||||
}, [pagination.reset]);
|
||||
|
||||
// Mark initial fetch as complete when query loads
|
||||
useEffect(() => {
|
||||
if (!queueQuery.isLoading && !initialFetchCompleteRef.current) {
|
||||
initialFetchCompleteRef.current = true;
|
||||
isMountingRef.current = false;
|
||||
console.log('✅ Initial queue fetch complete');
|
||||
logger.log('✅ Initial queue fetch complete');
|
||||
}
|
||||
}, [queueQuery.isLoading]);
|
||||
|
||||
// Invalidate query when filters or sort changes
|
||||
// Invalidate query when filters or sort changes (OPTIMIZED)
|
||||
useEffect(() => {
|
||||
if (
|
||||
!user ||
|
||||
@@ -538,36 +549,41 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
||||
isMountingRef.current
|
||||
) return;
|
||||
|
||||
console.log('🔄 Filters/sort changed, invalidating query');
|
||||
pagination.reset();
|
||||
queueQuery.invalidate();
|
||||
logger.log('🔄 Filters/sort changed, invalidating query');
|
||||
resetPagination();
|
||||
invalidateQuery();
|
||||
}, [
|
||||
filters.debouncedEntityFilter,
|
||||
filters.debouncedStatusFilter,
|
||||
filters.debouncedSortConfig.field,
|
||||
filters.debouncedSortConfig.direction,
|
||||
user,
|
||||
queueQuery,
|
||||
pagination
|
||||
invalidateQuery,
|
||||
resetPagination
|
||||
]);
|
||||
|
||||
// Polling effect (when realtime disabled)
|
||||
// Polling effect (when realtime disabled) - MUTUALLY EXCLUSIVE
|
||||
useEffect(() => {
|
||||
if (!user || settings.refreshMode !== "auto" || loadingState === "initial" || settings.useRealtimeQueue) {
|
||||
const shouldPoll = settings.refreshMode === 'auto'
|
||||
&& !settings.useRealtimeQueue
|
||||
&& loadingState !== 'initial'
|
||||
&& !!user;
|
||||
|
||||
if (!shouldPoll) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("⚠️ Polling ENABLED - interval:", settings.pollInterval);
|
||||
logger.log("⚠️ Polling ENABLED - interval:", settings.pollInterval);
|
||||
const interval = setInterval(() => {
|
||||
console.log("🔄 Polling refresh triggered");
|
||||
logger.log("🔄 Polling refresh triggered");
|
||||
queueQuery.refetch();
|
||||
}, settings.pollInterval);
|
||||
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
console.log("🛑 Polling stopped");
|
||||
logger.log("🛑 Polling stopped");
|
||||
};
|
||||
}, [user, settings.refreshMode, settings.pollInterval, loadingState, settings.useRealtimeQueue, queueQuery]);
|
||||
}, [user, settings.refreshMode, settings.pollInterval, loadingState, settings.useRealtimeQueue, queueQuery.refetch]);
|
||||
|
||||
// Initialize realtime subscriptions
|
||||
useRealtimeSubscriptions({
|
||||
@@ -591,21 +607,18 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig):
|
||||
if (recentlyRemovedRef.current.has(item.id)) return;
|
||||
if (interactingWith.has(item.id)) return;
|
||||
|
||||
if (shouldRemove) {
|
||||
setItems((prev) => prev.filter((i) => i.id !== item.id));
|
||||
} else {
|
||||
setItems((prev) => {
|
||||
const exists = prev.some((i) => i.id === item.id);
|
||||
if (exists) {
|
||||
return prev.map((i) => (i.id === item.id ? item : i));
|
||||
} else {
|
||||
return [item, ...prev];
|
||||
}
|
||||
});
|
||||
// Only track removals for optimistic update protection
|
||||
if (shouldRemove && !recentlyRemovedRef.current.has(item.id)) {
|
||||
recentlyRemovedRef.current.add(item.id);
|
||||
setTimeout(() => recentlyRemovedRef.current.delete(item.id), MODERATION_CONSTANTS.REALTIME_OPTIMISTIC_REMOVAL_TIMEOUT);
|
||||
}
|
||||
// TanStack Query handles actual state updates via invalidation
|
||||
},
|
||||
onItemRemoved: (itemId: string) => {
|
||||
setItems((prev) => prev.filter((i) => i.id !== itemId));
|
||||
// Track for optimistic update protection
|
||||
recentlyRemovedRef.current.add(itemId);
|
||||
setTimeout(() => recentlyRemovedRef.current.delete(itemId), MODERATION_CONSTANTS.REALTIME_OPTIMISTIC_REMOVAL_TIMEOUT);
|
||||
// TanStack Query handles removal via invalidation
|
||||
},
|
||||
entityCache,
|
||||
profileCache,
|
||||
|
||||
Reference in New Issue
Block a user