mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 15:11:12 -05:00
111 lines
3.1 KiB
TypeScript
111 lines
3.1 KiB
TypeScript
/**
|
|
* Moderation Lock Monitor
|
|
*
|
|
* Monitors lock expiry and provides automatic renewal prompts for moderators.
|
|
* Prevents loss of work due to expired locks.
|
|
*/
|
|
|
|
import { useEffect } from 'react';
|
|
import type { ModerationState } from '../moderationStateMachine';
|
|
import type { ModerationAction } from '../moderationStateMachine';
|
|
import { hasActiveLock, needsLockRenewal } from '../moderationStateMachine';
|
|
import { toast } from '@/hooks/use-toast';
|
|
import { supabase } from '@/lib/supabaseClient';
|
|
import { handleNonCriticalError } from '../errorHandler';
|
|
|
|
/**
|
|
* Hook to monitor lock status and warn about expiry
|
|
*
|
|
* @param state - Current moderation state
|
|
* @param dispatch - State machine dispatch function
|
|
* @param itemId - ID of the locked item (optional, for manual extension)
|
|
* @returns Extension function to manually extend lock
|
|
*/
|
|
export function useLockMonitor(
|
|
state: ModerationState,
|
|
dispatch: React.Dispatch<ModerationAction>,
|
|
itemId?: string
|
|
): { extendLock: () => Promise<void> } {
|
|
useEffect(() => {
|
|
if (!hasActiveLock(state)) {
|
|
return;
|
|
}
|
|
|
|
const checkInterval = setInterval(() => {
|
|
if (needsLockRenewal(state)) {
|
|
// Dispatch lock expiry warning
|
|
dispatch({ type: 'LOCK_EXPIRED' });
|
|
|
|
// Show toast with extension option
|
|
toast({
|
|
title: 'Lock Expiring Soon',
|
|
description: 'Your lock on this submission will expire in less than 2 minutes. Click below to extend.',
|
|
duration: Infinity,
|
|
});
|
|
|
|
// Also call extension function automatically after showing toast
|
|
if (itemId) {
|
|
setTimeout(() => {
|
|
handleExtendLock(itemId, dispatch);
|
|
}, 100);
|
|
}
|
|
}
|
|
}, 30000); // Check every 30 seconds
|
|
|
|
return () => clearInterval(checkInterval);
|
|
}, [state, dispatch, itemId]);
|
|
|
|
const extendLock = async () => {
|
|
if (itemId) {
|
|
await handleExtendLock(itemId, dispatch);
|
|
}
|
|
};
|
|
|
|
return { extendLock };
|
|
}
|
|
|
|
/**
|
|
* Extend the lock on a submission
|
|
*
|
|
* @param submissionId - Submission ID
|
|
* @param dispatch - State machine dispatch function
|
|
*/
|
|
export async function handleExtendLock(
|
|
submissionId: string,
|
|
dispatch: React.Dispatch<ModerationAction>
|
|
) {
|
|
try {
|
|
// Call Supabase to extend lock (assumes 15 minute extension)
|
|
const { error } = await supabase
|
|
.from('content_submissions')
|
|
.update({
|
|
locked_until: new Date(Date.now() + 15 * 60 * 1000).toISOString(),
|
|
})
|
|
.eq('id', submissionId);
|
|
|
|
if (error) throw error;
|
|
|
|
// Update state machine with new lock time
|
|
dispatch({
|
|
type: 'LOCK_ACQUIRED',
|
|
payload: { lockExpires: new Date(Date.now() + 15 * 60 * 1000).toISOString() },
|
|
});
|
|
|
|
toast({
|
|
title: 'Lock Extended',
|
|
description: 'You have 15 more minutes to complete your review.',
|
|
});
|
|
} catch (error: unknown) {
|
|
handleNonCriticalError(error, {
|
|
action: 'Extend Lock',
|
|
metadata: { submissionId }
|
|
});
|
|
|
|
toast({
|
|
title: 'Extension Failed',
|
|
description: 'Could not extend lock. Please save your work and re-claim the item.',
|
|
variant: 'destructive',
|
|
});
|
|
}
|
|
}
|