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
This commit is contained in:
pac7
2025-10-08 14:40:20 +00:00
parent eb39e794e0
commit fb10642fed

View File

@@ -97,6 +97,7 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
const { user } = useAuth();
const queue = useModerationQueue();
const fetchInProgressRef = useRef(false);
const itemsRef = useRef<ModerationItem[]>([]);
// Get admin settings for polling configuration
const {
@@ -110,6 +111,11 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((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<ModerationQueueRef>((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<ModerationQueueRef>((props, ref) => {
user,
refreshStrategy,
preserveInteraction,
interactingWith,
toast
]);
@@ -421,32 +426,40 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((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<ModerationQueueRef>((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}
/>
</div>
@@ -1772,6 +1791,12 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((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}
/>
<div className={`flex gap-2 ${isMobile ? 'flex-col' : ''}`}>