Refactor: Stabilize admin panel auto-refresh

This commit is contained in:
gpt-engineer-app[bot]
2025-10-06 19:31:15 +00:00
parent 71f497a001
commit d965d2c299

View File

@@ -80,6 +80,7 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
const [interactingWith, setInteractingWith] = useState<Set<string>>(new Set());
const [newItemsCount, setNewItemsCount] = useState(0);
const [isRefreshing, setIsRefreshing] = useState(false);
const [profileCache, setProfileCache] = useState<Map<string, any>>(new Map());
const { toast } = useToast();
const { isAdmin, isSuperuser } = useUserRole();
const { user } = useAuth();
@@ -109,8 +110,8 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
return;
}
// Prevent duplicate requests
if (isRefreshing && silent) {
// Prevent ANY refresh if one is in progress
if (isRefreshing) {
console.log('⏭️ Skipping refresh - already in progress');
return;
}
@@ -377,7 +378,20 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
.select('user_id, username, display_name, avatar_url')
.in('user_id', userIds);
const profileMap = new Map(profiles?.map(p => [p.user_id, p]) || []);
// Update profile cache with stable references
setProfileCache(prevCache => {
const newCache = new Map(prevCache);
profiles?.forEach(p => {
const existing = newCache.get(p.user_id);
// Only update if data actually changed
if (!existing || JSON.stringify(existing) !== JSON.stringify(p)) {
newCache.set(p.user_id, p);
}
});
return newCache;
});
const profileMap = profileCache;
// Combine and format items
const formattedItems: ModerationItem[] = [
@@ -448,7 +462,7 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
addToTop: true,
});
// If there are changes
// Only update state if there are actual changes
if (mergeResult.hasChanges) {
const actuallyNewItems = mergeResult.changes.added.length;
@@ -458,30 +472,31 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
updated: mergeResult.changes.updated.length,
removed: mergeResult.changes.removed.length,
totalItems: mergeResult.items.length,
protectedIds: Array.from(preserveInteraction ? interactingWith : new Set<string>()),
strategy: refreshStrategy,
preserveInteraction
});
// Filter out items user is interacting with
const protectedIds = preserveInteraction ? interactingWith : new Set<string>();
const mergedWithProtection = mergeResult.items.map(item => {
if (protectedIds.has(item.id)) {
// Find and preserve the current version of this item
// Only apply protection map if needed
let finalItems = mergeResult.items;
if (preserveInteraction && interactingWith.size > 0) {
finalItems = mergeResult.items.map(item => {
if (interactingWith.has(item.id)) {
const currentItem = items.find(i => i.id === item.id);
return currentItem || item;
}
return item;
});
}
setItems(mergedWithProtection);
// Only call setItems if reference has actually changed
if (finalItems !== items) {
setItems(finalItems);
}
// Only set new items count if there are genuinely new items
if (actuallyNewItems > 0) {
setNewItemsCount(actuallyNewItems);
}
} else {
// No changes detected - keep current state completely unchanged
// No changes detected - skip all state updates
console.log('✅ No changes detected, keeping current state');
}
} else {