From db082cc9e35a0773458845323bb5e10cece0963e Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 13:15:46 +0000 Subject: [PATCH] Refactor: Implement moderation queue enhancements --- src/components/moderation/QueueItem.tsx | 120 ++++++++++++++++-------- src/lib/photoHelpers.ts | 8 +- src/types/moderation.ts | 1 + src/types/photos.ts | 12 +-- 4 files changed, 86 insertions(+), 55 deletions(-) diff --git a/src/components/moderation/QueueItem.tsx b/src/components/moderation/QueueItem.tsx index a86132f2..b21c559f 100644 --- a/src/components/moderation/QueueItem.tsx +++ b/src/components/moderation/QueueItem.tsx @@ -2,6 +2,7 @@ import { memo, useState, useCallback } from 'react'; import { CheckCircle, XCircle, Eye, Calendar, MessageSquare, FileText, Image, ListTree, RefreshCw, AlertCircle, Lock, Trash2, AlertTriangle, Edit } from 'lucide-react'; import { usePhotoSubmissionItems } from '@/hooks/usePhotoSubmissionItems'; import { PhotoGrid } from '@/components/common/PhotoGrid'; +import { normalizePhotoData } from '@/lib/photoHelpers'; import type { PhotoItem } from '@/types/photos'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; @@ -86,6 +87,11 @@ export const QueueItem = memo(({ item.submission_type === 'photo' ? item.id : undefined ); + // Check if submission has any moderator-edited items + const hasModeratorEdits = item.submission_items?.some( + si => si.original_data && Object.keys(si.original_data).length > 0 + ); + const handleValidationChange = useCallback((result: ValidationResult) => { setValidationResult(result); }, []); @@ -95,6 +101,8 @@ export const QueueItem = memo(({ key={item.id} className={`border-l-4 transition-all duration-300 ${ item._removing ? 'opacity-0 scale-95 pointer-events-none' : '' + } ${ + hasModeratorEdits ? 'ring-2 ring-blue-200 dark:ring-blue-800' : '' } ${ validationResult?.blockingErrors && validationResult.blockingErrors.length > 0 ? 'border-l-red-600' : item.status === 'flagged' ? 'border-l-red-500' : @@ -134,6 +142,22 @@ export const QueueItem = memo(({ {item.status === 'partially_approved' ? 'Partially Approved' : item.status.charAt(0).toUpperCase() + item.status.slice(1)} + {hasModeratorEdits && ( + + + + + Edited + + + +

This submission has been modified by a moderator

+
+
+ )} {item.status === 'partially_approved' && ( @@ -231,36 +255,29 @@ export const QueueItem = memo(({ )} )} - {item.content.photos && item.content.photos.length > 0 && ( -
-
Attached Photos:
-
- {item.content.photos.map((photo: any, index: number) => ( -
{ - onOpenPhotos(item.content.photos.map((p: any, i: number) => ({ - id: `${item.id}-${i}`, - url: p.url, - filename: `Review photo ${i + 1}`, - caption: p.caption - })), index); - }}> - {`Review { - console.error('Failed to load review photo:', photo.url); - (e.target as HTMLImageElement).style.display = 'none'; - }} - /> -
- -
-
- ))} + {item.content.photos && item.content.photos.length > 0 && (() => { + const reviewPhotos: PhotoItem[] = normalizePhotoData({ + type: 'review', + photos: item.content.photos + }); + + return ( +
+
Attached Photos:
+ + {item.content.photos[0]?.caption && ( +

+ {item.content.photos[0].caption} +

+ )}
-
- )} + ); + })()}
) : item.submission_type === 'photo' ? (
@@ -286,10 +303,10 @@ export const QueueItem = memo(({ photos={photoItems.map(photo => ({ id: photo.id, url: photo.cloudflare_image_url, - filename: (photo as any).filename || `Photo ${photo.order_index + 1}`, + filename: photo.filename || `Photo ${photo.order_index + 1}`, caption: photo.caption, title: photo.title, - date_taken: (photo as any).date_taken, + date_taken: photo.date_taken, }))} onPhotoClick={onOpenPhotos} /> @@ -370,16 +387,37 @@ export const QueueItem = memo(({
{/* Show Review Items button for content submissions */} {item.type === 'content_submission' && ( - + <> + + {isAdmin && !isLockedByOther && currentLockSubmissionId === item.id && ( + + + + + +

Edit submission items directly as a moderator

+
+
+ )} + )}