import { useState, useImperativeHandle, forwardRef, useMemo } from 'react'; import { Card, CardContent } from '@/components/ui/card'; import { TooltipProvider } from '@/components/ui/tooltip'; import { useToast } from '@/hooks/use-toast'; import { useUserRole } from '@/hooks/useUserRole'; import { useAuth } from '@/hooks/useAuth'; import { PhotoModal } from './PhotoModal'; import { SubmissionReviewManager } from './SubmissionReviewManager'; import { useIsMobile } from '@/hooks/use-mobile'; import { useAdminSettings } from '@/hooks/useAdminSettings'; import { useModerationQueueManager } from '@/hooks/moderation'; import { QueueItem } from './QueueItem'; import { QueueSkeleton } from './QueueSkeleton'; import { LockStatusDisplay } from './LockStatusDisplay'; import { getLockStatus } from '@/lib/moderation/lockHelpers'; import { QueueStats } from './QueueStats'; import { QueueFilters } from './QueueFilters'; import { ActiveFiltersDisplay } from './ActiveFiltersDisplay'; import { AutoRefreshIndicator } from './AutoRefreshIndicator'; import { NewItemsAlert } from './NewItemsAlert'; import { EmptyQueueState } from './EmptyQueueState'; import { QueuePagination } from './QueuePagination'; import type { ModerationQueueRef } from '@/types/moderation'; import type { PhotoItem } from '@/types/photos'; export const ModerationQueue = forwardRef((props, ref) => { const isMobile = useIsMobile(); const { user } = useAuth(); const { toast } = useToast(); const { isAdmin, isSuperuser } = useUserRole(); const adminSettings = useAdminSettings(); // Extract settings values to stable primitives for memoization const refreshMode = adminSettings.getAdminPanelRefreshMode(); const pollInterval = adminSettings.getAdminPanelPollInterval(); const refreshStrategy = adminSettings.getAutoRefreshStrategy(); const preserveInteraction = adminSettings.getPreserveInteractionState(); const useRealtimeQueue = adminSettings.getUseRealtimeQueue(); // Memoize settings object using stable primitive dependencies const settings = useMemo(() => ({ refreshMode, pollInterval, refreshStrategy, preserveInteraction, useRealtimeQueue, }), [refreshMode, pollInterval, refreshStrategy, preserveInteraction, useRealtimeQueue]); // Initialize queue manager (replaces all state management, fetchItems, effects) const queueManager = useModerationQueueManager({ user, isAdmin: isAdmin(), isSuperuser: isSuperuser(), toast, settings, }); // UI-only state const [notes, setNotes] = useState>({}); const [photoModalOpen, setPhotoModalOpen] = useState(false); const [selectedPhotos, setSelectedPhotos] = useState([]); const [selectedPhotoIndex, setSelectedPhotoIndex] = useState(0); const [reviewManagerOpen, setReviewManagerOpen] = useState(false); const [selectedSubmissionId, setSelectedSubmissionId] = useState(null); // UI-specific handlers const handleNoteChange = (id: string, value: string) => { setNotes(prev => ({ ...prev, [id]: value })); }; const handleOpenPhotos = (photos: any[], index: number) => { setSelectedPhotos(photos); setSelectedPhotoIndex(index); setPhotoModalOpen(true); }; const handleOpenReviewManager = (submissionId: string) => { setSelectedSubmissionId(submissionId); setReviewManagerOpen(true); }; // Expose imperative API useImperativeHandle(ref, () => ({ refresh: async () => { await queueManager.refresh(); } })); return (
{/* Queue Statistics & Lock Status */} {queueManager.queue.queueStats && (
{ await queueManager.queue.claimNext(); }} onExtendLock={queueManager.queue.extendLock} onReleaseLock={queueManager.queue.releaseLock} getTimeRemaining={queueManager.queue.getTimeRemaining} getLockProgress={queueManager.queue.getLockProgress} />
)} {/* Filter Bar */} {/* Active Filters Display */} {queueManager.filters.hasActiveFilters && ( )} {/* Auto-refresh Indicator */} {adminSettings.getAdminPanelRefreshMode() === 'auto' && ( )} {/* New Items Alert */} {queueManager.newItemsCount > 0 && ( )} {/* Queue Content */} {queueManager.loadingState === 'loading' || queueManager.loadingState === 'initial' ? ( ) : queueManager.items.length === 0 ? ( ) : (
{queueManager.items.map((item, index) => ( queueManager.markInteracting(id, true)} onInteractionBlur={(id) => queueManager.markInteracting(id, false)} /> ))}
)} {/* Pagination */} {queueManager.loadingState === 'ready' && queueManager.pagination.totalPages > 1 && ( )} {/* Modals */} setPhotoModalOpen(false)} /> {selectedSubmissionId && ( setReviewManagerOpen(false)} /> )}
); }); ModerationQueue.displayName = 'ModerationQueue'; export type { ModerationQueueRef } from '@/types/moderation';