mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 11:51:14 -05:00
Fix moderation queue claim logic
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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({
|
||||||
|
|||||||
Reference in New Issue
Block a user