diff --git a/src/components/moderation/SubmissionChangesDisplay.tsx b/src/components/moderation/SubmissionChangesDisplay.tsx index 3cdab6bd..31de9e96 100644 --- a/src/components/moderation/SubmissionChangesDisplay.tsx +++ b/src/components/moderation/SubmissionChangesDisplay.tsx @@ -1,6 +1,9 @@ +import { useState, useEffect } from 'react'; import { Badge } from '@/components/ui/badge'; +import { Skeleton } from '@/components/ui/skeleton'; import { FieldDiff, ImageDiff, LocationDiff } from './FieldComparison'; -import { detectChanges } from '@/lib/submissionChangeDetection'; +import { PhotoAdditionPreview, PhotoEditPreview, PhotoDeletionPreview } from './PhotoComparison'; +import { detectChanges, type ChangesSummary } from '@/lib/submissionChangeDetection'; import type { SubmissionItemData } from '@/types/submissions'; import type { SubmissionItemWithDeps } from '@/lib/submissionItemsService'; import { Building2, Train, MapPin, Building, User, ImageIcon, Trash2, Edit, Plus, AlertTriangle } from 'lucide-react'; @@ -9,6 +12,7 @@ interface SubmissionChangesDisplayProps { item: SubmissionItemData | SubmissionItemWithDeps; view?: 'summary' | 'detailed'; showImages?: boolean; + submissionId?: string; } // Helper to determine change magnitude @@ -24,9 +28,25 @@ function getChangeMagnitude(totalChanges: number, hasImages: boolean, action: st export function SubmissionChangesDisplay({ item, view = 'summary', - showImages = true + showImages = true, + submissionId }: SubmissionChangesDisplayProps) { - const changes = detectChanges(item); + const [changes, setChanges] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const loadChanges = async () => { + setLoading(true); + const detectedChanges = await detectChanges(item, submissionId); + setChanges(detectedChanges); + setLoading(false); + }; + loadChanges(); + }, [item, submissionId]); + + if (loading || !changes) { + return ; + } // Get appropriate icon for entity type const getEntityIcon = () => { @@ -83,6 +103,18 @@ export function SubmissionChangesDisplay({ {changes.imageChanges.map((change, idx) => ( ))} + {changes.photoChanges.map((change, idx) => { + if (change.type === 'added' && change.photos) { + return ; + } + if (change.type === 'edited' && change.photo) { + return ; + } + if (change.type === 'deleted' && change.photo) { + return ; + } + return null; + })} {changes.hasLocationChange && ( Location @@ -156,6 +188,26 @@ export function SubmissionChangesDisplay({ )} + {showImages && changes.photoChanges.length > 0 && ( +
+

Photo Changes

+
+ {changes.photoChanges.map((change, idx) => { + if (change.type === 'added' && change.photos) { + return ; + } + if (change.type === 'edited' && change.photo) { + return ; + } + if (change.type === 'deleted' && change.photo) { + return ; + } + return null; + })} +
+
+ )} + {changes.hasLocationChange && (

Location Change

diff --git a/src/components/moderation/SubmissionItemsList.tsx b/src/components/moderation/SubmissionItemsList.tsx index 9f63b20f..7df9c8d7 100644 --- a/src/components/moderation/SubmissionItemsList.tsx +++ b/src/components/moderation/SubmissionItemsList.tsx @@ -97,6 +97,7 @@ export function SubmissionItemsList({ item={item} view={view} showImages={showImages} + submissionId={submissionId} />
))} diff --git a/src/lib/submissionChangeDetection.ts b/src/lib/submissionChangeDetection.ts index c4e6be93..434baf33 100644 --- a/src/lib/submissionChangeDetection.ts +++ b/src/lib/submissionChangeDetection.ts @@ -1,4 +1,5 @@ import type { SubmissionItemData } from '@/types/submissions'; +import { supabase } from '@/integrations/supabase/client'; export interface FieldChange { field: string; @@ -17,11 +18,16 @@ export interface ImageChange { export interface PhotoChange { type: 'added' | 'edited' | 'deleted'; - photoUrl: string; - title?: string; - caption?: string; - oldCaption?: string; - newCaption?: string; + photos?: Array<{ url: string; title?: string; caption?: string }>; + photo?: { + url: string; + title?: string; + caption?: string; + oldCaption?: string; + newCaption?: string; + oldTitle?: string; + newTitle?: string; + }; } export interface ChangesSummary { @@ -35,10 +41,54 @@ export interface ChangesSummary { totalChanges: number; } +/** + * Detects photo changes for a submission + */ +async function detectPhotoChanges(submissionId: string): Promise { + const changes: PhotoChange[] = []; + + try { + // Fetch photo submission with items + const { data: photoSubmission, error } = await supabase + .from('photo_submissions') + .select(` + *, + items:photo_submission_items(*) + `) + .eq('submission_id', submissionId) + .maybeSingle(); + + if (error) { + console.error('Error fetching photo submissions:', error); + return changes; + } + + if (photoSubmission?.items && photoSubmission.items.length > 0) { + // For now, treat all photos as additions + // TODO: Implement edit/delete detection by comparing with existing entity photos + changes.push({ + type: 'added', + photos: photoSubmission.items.map((item: any) => ({ + url: item.cloudflare_image_url, + title: item.title, + caption: item.caption + })) + }); + } + } catch (err) { + console.error('Error detecting photo changes:', err); + } + + return changes; +} + /** * Detects what changed between original_data and item_data */ -export function detectChanges(item: { item_data?: any; original_data?: any; item_type: string }): ChangesSummary { +export async function detectChanges( + item: { item_data?: any; original_data?: any; item_type: string }, + submissionId?: string +): Promise { const itemData = item.item_data || {}; const originalData = item.original_data || {}; @@ -124,15 +174,18 @@ export function detectChanges(item: { item_data?: any; original_data?: any; item // Get entity name const entityName = itemData.name || originalData?.name || 'Unknown'; + // Detect photo changes if submissionId provided + const photoChanges = submissionId ? await detectPhotoChanges(submissionId) : []; + return { action, entityType: item.item_type, entityName, fieldChanges, imageChanges, - photoChanges: [], // Will be populated by component with submissionId + photoChanges, hasLocationChange, - totalChanges: fieldChanges.length + imageChanges.length + (hasLocationChange ? 1 : 0) + totalChanges: fieldChanges.length + imageChanges.length + photoChanges.length + (hasLocationChange ? 1 : 0) }; }