mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 01:11:13 -05:00
feat: Implement submission reset functionality
This commit is contained in:
@@ -383,6 +383,31 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
|||||||
}
|
}
|
||||||
}, [activeEntityFilter, activeStatusFilter, user]);
|
}, [activeEntityFilter, activeStatusFilter, user]);
|
||||||
|
|
||||||
|
const handleResetToPending = async (item: ModerationItem) => {
|
||||||
|
setActionLoading(item.id);
|
||||||
|
try {
|
||||||
|
const { resetRejectedItemsToPending } = await import('@/lib/submissionItemsService');
|
||||||
|
|
||||||
|
await resetRejectedItemsToPending(item.id);
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "Reset Complete",
|
||||||
|
description: "Submission and all items have been reset to pending status",
|
||||||
|
});
|
||||||
|
|
||||||
|
fetchItems(activeEntityFilter, activeStatusFilter);
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('Error resetting submission:', error);
|
||||||
|
toast({
|
||||||
|
title: "Reset Failed",
|
||||||
|
description: error.message,
|
||||||
|
variant: "destructive",
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setActionLoading(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleRetryFailedItems = async (item: ModerationItem) => {
|
const handleRetryFailedItems = async (item: ModerationItem) => {
|
||||||
setActionLoading(item.id);
|
setActionLoading(item.id);
|
||||||
try {
|
try {
|
||||||
@@ -1536,14 +1561,36 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Retry button for partially approved items */}
|
{/* Reset button for rejected items */}
|
||||||
|
{item.status === 'rejected' && item.type === 'content_submission' && (
|
||||||
|
<div className="space-y-3 pt-4 border-t bg-red-50 dark:bg-red-950/20 -mx-4 px-4 py-3 rounded-b-lg">
|
||||||
|
<div className="flex items-start gap-2 text-sm text-red-800 dark:text-red-300">
|
||||||
|
<AlertCircle className="w-5 h-5 mt-0.5 flex-shrink-0" />
|
||||||
|
<div>
|
||||||
|
<p className="font-medium">This submission was rejected</p>
|
||||||
|
<p className="text-xs mt-1">You can reset it to pending to re-review and approve it.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
onClick={() => handleResetToPending(item)}
|
||||||
|
disabled={actionLoading === item.id}
|
||||||
|
variant="outline"
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
<RefreshCw className="w-4 h-4 mr-2" />
|
||||||
|
Reset to Pending
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Retry/Reset buttons for partially approved items */}
|
||||||
{item.status === 'partially_approved' && item.type === 'content_submission' && (
|
{item.status === 'partially_approved' && item.type === 'content_submission' && (
|
||||||
<div className="space-y-3 pt-4 border-t bg-yellow-50 dark:bg-yellow-950/20 -mx-4 px-4 py-3 rounded-b-lg">
|
<div className="space-y-3 pt-4 border-t bg-yellow-50 dark:bg-yellow-950/20 -mx-4 px-4 py-3 rounded-b-lg">
|
||||||
<div className="flex items-start gap-2 text-sm text-yellow-800 dark:text-yellow-300">
|
<div className="flex items-start gap-2 text-sm text-yellow-800 dark:text-yellow-300">
|
||||||
<AlertCircle className="w-5 h-5 mt-0.5 flex-shrink-0" />
|
<AlertCircle className="w-5 h-5 mt-0.5 flex-shrink-0" />
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium">This submission was partially approved</p>
|
<p className="font-medium">This submission was partially approved</p>
|
||||||
<p className="text-xs mt-1">Some items failed to process. Click "Retry Failed Items" to process them again.</p>
|
<p className="text-xs mt-1">Some items failed. You can retry them or reset everything to pending.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
@@ -1559,13 +1606,22 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
|||||||
<ListTree className="w-4 h-4 mr-2" />
|
<ListTree className="w-4 h-4 mr-2" />
|
||||||
Review Items
|
Review Items
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => handleResetToPending(item)}
|
||||||
|
disabled={actionLoading === item.id}
|
||||||
|
variant="outline"
|
||||||
|
className="flex-1"
|
||||||
|
>
|
||||||
|
<RefreshCw className="w-4 h-4 mr-2" />
|
||||||
|
Reset All
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleRetryFailedItems(item)}
|
onClick={() => handleRetryFailedItems(item)}
|
||||||
disabled={actionLoading === item.id}
|
disabled={actionLoading === item.id}
|
||||||
className="flex-1 bg-yellow-600 hover:bg-yellow-700"
|
className="flex-1 bg-yellow-600 hover:bg-yellow-700"
|
||||||
>
|
>
|
||||||
<RefreshCw className="w-4 h-4 mr-2" />
|
<RefreshCw className="w-4 h-4 mr-2" />
|
||||||
Retry Failed Items
|
Retry Failed
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -733,6 +733,45 @@ function resolveDependencies(data: any, dependencyMap: Map<string, string>): any
|
|||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset rejected items back to pending status
|
||||||
|
*/
|
||||||
|
export async function resetRejectedItemsToPending(
|
||||||
|
submissionId: string
|
||||||
|
): Promise<void> {
|
||||||
|
// Reset rejected submission items to pending
|
||||||
|
const { error: itemsError } = await supabase
|
||||||
|
.from('submission_items')
|
||||||
|
.update({
|
||||||
|
status: 'pending',
|
||||||
|
rejection_reason: null,
|
||||||
|
updated_at: new Date().toISOString()
|
||||||
|
})
|
||||||
|
.eq('submission_id', submissionId)
|
||||||
|
.eq('status', 'rejected');
|
||||||
|
|
||||||
|
if (itemsError) {
|
||||||
|
throw new Error(`Failed to reset items: ${itemsError.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset parent submission to pending
|
||||||
|
const { error: submissionError } = await supabase
|
||||||
|
.from('content_submissions')
|
||||||
|
.update({
|
||||||
|
status: 'pending',
|
||||||
|
reviewed_at: null,
|
||||||
|
reviewer_id: null,
|
||||||
|
reviewer_notes: null,
|
||||||
|
updated_at: new Date().toISOString()
|
||||||
|
})
|
||||||
|
.eq('id', submissionId)
|
||||||
|
.in('status', ['rejected', 'partially_approved']);
|
||||||
|
|
||||||
|
if (submissionError) {
|
||||||
|
throw new Error(`Failed to reset submission: ${submissionError.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reject multiple items with optional cascade to dependents
|
* Reject multiple items with optional cascade to dependents
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user