Fix moderation queue claim logic

This commit is contained in:
gpt-engineer-app[bot]
2025-11-05 16:37:54 +00:00
parent 7c35f2932b
commit 80d823a1b9
2 changed files with 78 additions and 9 deletions

View File

@@ -134,6 +134,17 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
}; };
}, [queueManager, toast]); }, [queueManager, toast]);
// Auto-dismiss lock restored banner after 10 seconds
useEffect(() => {
if (lockRestored && queueManager.queue.currentLock) {
const timer = setTimeout(() => {
setLockRestored(false);
}, 10000); // Auto-dismiss after 10 seconds
return () => clearTimeout(timer);
}
}, [lockRestored, queueManager.queue.currentLock]);
// Fetch active locks count for superusers // Fetch active locks count for superusers
const isSuperuserValue = isSuperuser(); const isSuperuserValue = isSuperuser();
@@ -377,15 +388,43 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
)} )}
{/* Lock Restored Alert */} {/* Lock Restored Alert */}
{lockRestored && queueManager.queue.currentLock && ( {lockRestored && queueManager.queue.currentLock && (() => {
<Alert className="border-blue-500/50 bg-blue-500/5"> // Check if restored submission is in current queue
<Info className="h-4 w-4 text-blue-600" /> const restoredSubmissionInQueue = queueManager.items.some(
<AlertTitle>Active Claim Restored</AlertTitle> item => item.id === queueManager.queue.currentLock?.submissionId
);
if (!restoredSubmissionInQueue) return null;
// Calculate time remaining
const timeRemainingMs = queueManager.queue.currentLock.expiresAt.getTime() - Date.now();
const timeRemainingSec = Math.max(0, Math.floor(timeRemainingMs / 1000));
const isExpiringSoon = timeRemainingSec < 300; // Less than 5 minutes
return (
<Alert className={isExpiringSoon
? "border-orange-500/50 bg-orange-500/10"
: "border-blue-500/50 bg-blue-500/5"
}>
<Info className={isExpiringSoon
? "h-4 w-4 text-orange-600"
: "h-4 w-4 text-blue-600"
} />
<AlertTitle>
{isExpiringSoon
? `Lock Expiring Soon (${Math.floor(timeRemainingSec / 60)}m ${timeRemainingSec % 60}s)`
: "Active Claim Restored"
}
</AlertTitle>
<AlertDescription> <AlertDescription>
Your previous claim was restored. You still have time to review this submission. {isExpiringSoon
? "Your lock is about to expire. Complete your review or extend the lock."
: "Your previous claim was restored. You still have time to review this submission."
}
</AlertDescription> </AlertDescription>
</Alert> </Alert>
)} );
})()}
{/* Filter Bar */} {/* Filter Bar */}
<QueueFilters <QueueFilters

View File

@@ -187,6 +187,26 @@ export const useModerationQueue = (config?: UseModerationQueueConfig) => {
// Only restore if lock hasn't expired (race condition check) // Only restore if lock hasn't expired (race condition check)
if (data.locked_until && expiresAt > new Date()) { if (data.locked_until && expiresAt > new Date()) {
const timeRemaining = expiresAt.getTime() - new Date().getTime();
const minTimeMs = 60 * 1000; // 60 seconds minimum
if (timeRemaining < minTimeMs) {
// Lock expires too soon - auto-release it
logger.info('Lock expired or expiring soon, auto-releasing', {
submissionId: data.id,
timeRemainingSeconds: Math.floor(timeRemaining / 1000),
});
// Release the stale lock
await supabase.rpc('release_submission_lock', {
submission_id: data.id,
moderator_id: user.id,
});
return; // Don't restore
}
// Lock has sufficient time - restore it
setCurrentLock({ setCurrentLock({
submissionId: data.id, submissionId: data.id,
expiresAt, expiresAt,
@@ -198,6 +218,7 @@ export const useModerationQueue = (config?: UseModerationQueueConfig) => {
logger.info('Lock state restored from database', { logger.info('Lock state restored from database', {
submissionId: data.id, submissionId: data.id,
expiresAt: expiresAt.toISOString(), expiresAt: expiresAt.toISOString(),
timeRemainingSeconds: Math.floor(timeRemaining / 1000),
}); });
} }
} }
@@ -399,6 +420,15 @@ export const useModerationQueue = (config?: UseModerationQueueConfig) => {
return false; return false;
} }
// Check if trying to claim same submission user already has locked
if (currentLock && currentLock.submissionId === submissionId) {
toast({
title: 'Already Claimed',
description: 'You already have this submission claimed. Review it below.',
});
return true; // Return success, don't re-claim
}
// Check if user already has an active lock on a different submission // Check if user already has an active lock on a different submission
if (currentLock && currentLock.submissionId !== submissionId) { if (currentLock && currentLock.submissionId !== submissionId) {
toast({ toast({