mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 16:11:12 -05:00
Implement superuser lock management
This commit is contained in:
@@ -8,6 +8,7 @@ import { useToast } from '@/hooks/use-toast';
|
||||
import { useUserRole } from '@/hooks/useUserRole';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { PhotoModal } from './PhotoModal';
|
||||
import { SubmissionReviewManager } from './SubmissionReviewManager';
|
||||
import { ItemEditDialog } from './ItemEditDialog';
|
||||
@@ -29,6 +30,7 @@ import { EnhancedEmptyState } from './EnhancedEmptyState';
|
||||
import { QueuePagination } from './QueuePagination';
|
||||
import { ConfirmationDialog } from './ConfirmationDialog';
|
||||
import { KeyboardShortcutsHelp } from './KeyboardShortcutsHelp';
|
||||
import { SuperuserQueueControls } from './SuperuserQueueControls';
|
||||
import { useKeyboardShortcuts } from '@/hooks/useKeyboardShortcuts';
|
||||
import { fetchSubmissionItems, type SubmissionItemWithDeps } from '@/lib/submissionItemsService';
|
||||
import type { ModerationQueueRef, ModerationItem } from '@/types/moderation';
|
||||
@@ -85,6 +87,7 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
|
||||
const [availableItems, setAvailableItems] = useState<SubmissionItemWithDeps[]>([]);
|
||||
const [bulkEditMode, setBulkEditMode] = useState(false);
|
||||
const [bulkEditItems, setBulkEditItems] = useState<SubmissionItemWithDeps[]>([]);
|
||||
const [activeLocksCount, setActiveLocksCount] = useState(0);
|
||||
|
||||
// Confirmation dialog state
|
||||
const [confirmDialog, setConfirmDialog] = useState<{
|
||||
@@ -129,6 +132,27 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
|
||||
};
|
||||
}, [queueManager, toast]);
|
||||
|
||||
// Fetch active locks count for superusers
|
||||
useEffect(() => {
|
||||
if (!isSuperuser()) return;
|
||||
|
||||
const fetchActiveLocksCount = async () => {
|
||||
const { count } = await supabase
|
||||
.from('content_submissions')
|
||||
.select('id', { count: 'exact', head: true })
|
||||
.not('assigned_to', 'is', null)
|
||||
.gt('locked_until', new Date().toISOString());
|
||||
|
||||
setActiveLocksCount(count || 0);
|
||||
};
|
||||
|
||||
fetchActiveLocksCount();
|
||||
|
||||
// Refresh count periodically
|
||||
const interval = setInterval(fetchActiveLocksCount, 30000); // Every 30s
|
||||
return () => clearInterval(interval);
|
||||
}, [isSuperuser, queueManager.queue.queueStats]);
|
||||
|
||||
// Virtual scrolling setup
|
||||
const parentRef = useRef<HTMLDivElement>(null);
|
||||
const virtualizer = useVirtualizer({
|
||||
@@ -154,6 +178,22 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
|
||||
});
|
||||
}, [queueManager]);
|
||||
|
||||
// Superuser force release lock
|
||||
const handleSuperuserReleaseLock = useCallback(async (submissionId: string) => {
|
||||
await queueManager.queue.superuserReleaseLock(submissionId);
|
||||
// Refresh locks count and queue
|
||||
setActiveLocksCount(prev => Math.max(0, prev - 1));
|
||||
queueManager.refresh();
|
||||
}, [queueManager]);
|
||||
|
||||
// Superuser clear all locks
|
||||
const handleClearAllLocks = useCallback(async () => {
|
||||
const count = await queueManager.queue.superuserReleaseAllLocks();
|
||||
setActiveLocksCount(0);
|
||||
// Force queue refresh
|
||||
queueManager.refresh();
|
||||
}, [queueManager]);
|
||||
|
||||
// Clear filters handler
|
||||
const handleClearFilters = useCallback(() => {
|
||||
queueManager.filters.clearFilters();
|
||||
@@ -310,6 +350,15 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Superuser Queue Controls */}
|
||||
{isSuperuser() && (
|
||||
<SuperuserQueueControls
|
||||
activeLocksCount={activeLocksCount}
|
||||
onClearAllLocks={handleClearAllLocks}
|
||||
isLoading={queueManager.queue.isLoading}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Filter Bar */}
|
||||
<QueueFilters
|
||||
activeEntityFilter={queueManager.filters.entityFilter}
|
||||
@@ -390,6 +439,7 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
|
||||
onDeleteSubmission={handleDeleteSubmission}
|
||||
onInteractionFocus={(id) => queueManager.markInteracting(id, true)}
|
||||
onInteractionBlur={(id) => queueManager.markInteracting(id, false)}
|
||||
onSuperuserReleaseLock={isSuperuser() ? handleSuperuserReleaseLock : undefined}
|
||||
/>
|
||||
</ModerationErrorBoundary>
|
||||
))}
|
||||
@@ -451,6 +501,7 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
|
||||
onDeleteSubmission={handleDeleteSubmission}
|
||||
onInteractionFocus={(id) => queueManager.markInteracting(id, true)}
|
||||
onInteractionBlur={(id) => queueManager.markInteracting(id, false)}
|
||||
onSuperuserReleaseLock={isSuperuser() ? handleSuperuserReleaseLock : undefined}
|
||||
/>
|
||||
</ModerationErrorBoundary>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user