From fb10642fed59c5c564bd3d6b6cf1c4a2c9e658d0 Mon Sep 17 00:00:00 2001 From: pac7 <47831526-pac7@users.noreply.replit.com> Date: Wed, 8 Oct 2025 14:40:20 +0000 Subject: [PATCH] Transitioned from Plan to Build mode Replit-Commit-Author: Agent Replit-Commit-Session-Id: e14c2292-b0e5-43fe-b301-a4ad668949e9 Replit-Commit-Checkpoint-Type: full_checkpoint --- src/components/moderation/ModerationQueue.tsx | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/components/moderation/ModerationQueue.tsx b/src/components/moderation/ModerationQueue.tsx index cc1c753a..44633d0b 100644 --- a/src/components/moderation/ModerationQueue.tsx +++ b/src/components/moderation/ModerationQueue.tsx @@ -97,6 +97,7 @@ export const ModerationQueue = forwardRef((props, ref) => { const { user } = useAuth(); const queue = useModerationQueue(); const fetchInProgressRef = useRef(false); + const itemsRef = useRef([]); // Get admin settings for polling configuration const { @@ -110,6 +111,11 @@ export const ModerationQueue = forwardRef((props, ref) => { const refreshStrategy = getAutoRefreshStrategy(); const preserveInteraction = getPreserveInteractionState(); + // Sync itemsRef with items state + useEffect(() => { + itemsRef.current = items; + }, [items]); + const fetchItems = useCallback(async (entityFilter: EntityFilter = 'all', statusFilter: StatusFilter = 'pending', silent = false) => { if (!user) { return; @@ -378,8 +384,8 @@ export const ModerationQueue = forwardRef((props, ref) => { }); setSubmissionMemo(newMemoMap); - // Apply smart merge for state updates - const mergeResult = smartMergeArray(items, moderationItems, { + // Apply smart merge for state updates using ref for current items + const mergeResult = smartMergeArray(itemsRef.current, moderationItems, { compareFields: ['status', 'reviewed_at', 'reviewer_notes'], preserveOrder: silent && preserveInteraction, addToTop: false, @@ -413,7 +419,6 @@ export const ModerationQueue = forwardRef((props, ref) => { user, refreshStrategy, preserveInteraction, - interactingWith, toast ]); @@ -421,32 +426,40 @@ export const ModerationQueue = forwardRef((props, ref) => { const debouncedEntityFilter = useDebounce(activeEntityFilter, 500); const debouncedStatusFilter = useDebounce(activeStatusFilter, 500); + // Store latest filter values in ref to avoid dependency issues + const filtersRef = useRef({ entityFilter: debouncedEntityFilter, statusFilter: debouncedStatusFilter }); + useEffect(() => { + filtersRef.current = { entityFilter: debouncedEntityFilter, statusFilter: debouncedStatusFilter }; + }, [debouncedEntityFilter, debouncedStatusFilter]); + // Expose refresh method via ref useImperativeHandle(ref, () => ({ refresh: () => { - fetchItems(debouncedEntityFilter, debouncedStatusFilter, false); // Manual refresh shows loading + fetchItems(filtersRef.current.entityFilter, filtersRef.current.statusFilter, false); // Manual refresh shows loading } - }), [debouncedEntityFilter, debouncedStatusFilter, fetchItems]); + }), [fetchItems]); // Initial fetch on mount and filter changes useEffect(() => { if (user) { fetchItems(debouncedEntityFilter, debouncedStatusFilter, false); // Show loading } - }, [debouncedEntityFilter, debouncedStatusFilter, user, fetchItems]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [debouncedEntityFilter, debouncedStatusFilter, user]); // Polling for auto-refresh useEffect(() => { if (!user || refreshMode !== 'auto' || isInitialLoad) return; const interval = setInterval(() => { - fetchItems(debouncedEntityFilter, debouncedStatusFilter, true); // Silent refresh + fetchItems(filtersRef.current.entityFilter, filtersRef.current.statusFilter, true); // Silent refresh }, pollInterval); return () => { clearInterval(interval); }; - }, [user, refreshMode, pollInterval, debouncedEntityFilter, debouncedStatusFilter, isInitialLoad, fetchItems]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [user, refreshMode, pollInterval, isInitialLoad]); // Real-time subscription for lock status useEffect(() => { @@ -1623,6 +1636,12 @@ export const ModerationQueue = forwardRef((props, ref) => { placeholder="Add notes about your moderation decision..." value={notes[item.id] || ''} onChange={(e) => setNotes(prev => ({ ...prev, [item.id]: e.target.value }))} + onFocus={() => setInteractingWith(prev => new Set(prev).add(item.id))} + onBlur={() => setInteractingWith(prev => { + const next = new Set(prev); + next.delete(item.id); + return next; + })} rows={2} /> @@ -1772,6 +1791,12 @@ export const ModerationQueue = forwardRef((props, ref) => { placeholder="Add notes about reversing this decision..." value={notes[`reverse-${item.id}`] || ''} onChange={(e) => setNotes(prev => ({ ...prev, [`reverse-${item.id}`]: e.target.value }))} + onFocus={() => setInteractingWith(prev => new Set(prev).add(item.id))} + onBlur={() => setInteractingWith(prev => { + const next = new Set(prev); + next.delete(item.id); + return next; + })} rows={2} />