From 63a7877314a3b63a19fa109b4d059fa1601b0e31 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 18:24:20 +0000 Subject: [PATCH] Refactor: Approve tool use --- src/components/moderation/PhotoComparison.tsx | 68 ++++++++++++------- .../moderation/SubmissionChangesDisplay.tsx | 56 ++++++++++++++- src/lib/submissionChangeDetection.ts | 31 ++++++--- ...6_6c75308d-dc6d-4942-a793-45ddb48ad7a9.sql | 53 +++++++++++++++ 4 files changed, 175 insertions(+), 33 deletions(-) create mode 100644 supabase/migrations/20251006182226_6c75308d-dc6d-4942-a793-45ddb48ad7a9.sql diff --git a/src/components/moderation/PhotoComparison.tsx b/src/components/moderation/PhotoComparison.tsx index cbccfa31..1c60a037 100644 --- a/src/components/moderation/PhotoComparison.tsx +++ b/src/components/moderation/PhotoComparison.tsx @@ -128,39 +128,61 @@ interface PhotoDeletionPreviewProps { export function PhotoDeletionPreview({ photo, compact = false }: PhotoDeletionPreviewProps) { if (compact) { return ( - - - Delete Photo - +
+ + Delete Photo + {photo.deletion_reason && ( + - {photo.deletion_reason} + )} +
); } return ( -
-
- - Deleting Photo +
+
+ + Photo Deletion Request
-
- {photo.title +
+ {photo.url && ( + {photo.title + )} -
- {photo.title &&
{photo.title}
} - {photo.caption &&
{photo.caption}
} - {photo.entity_type && photo.entity_name && ( -
- From: {photo.entity_type} - {photo.entity_name} +
+ {photo.title && ( +
+ Title: +
{photo.title}
)} + + {photo.caption && ( +
+ Caption: +
{photo.caption}
+
+ )} + + {photo.entity_type && photo.entity_name && ( +
+ From Entity: +
+ {photo.entity_type.replace('_', ' ')} - {photo.entity_name} +
+
+ )} + {photo.deletion_reason && ( -
- Reason: {photo.deletion_reason} +
+ Deletion Reason: +

{photo.deletion_reason}

)}
diff --git a/src/components/moderation/SubmissionChangesDisplay.tsx b/src/components/moderation/SubmissionChangesDisplay.tsx index a221d2ff..1e93e0f1 100644 --- a/src/components/moderation/SubmissionChangesDisplay.tsx +++ b/src/components/moderation/SubmissionChangesDisplay.tsx @@ -85,6 +85,33 @@ export function SubmissionChangesDisplay({ ); if (view === 'summary') { + // Special compact display for photo deletions + if (item.item_type === 'photo_delete') { + return ( +
+
+ {getEntityIcon()} + {changes.entityName} + {getActionBadge()} +
+ + {changes.photoChanges.length > 0 && changes.photoChanges[0].type === 'deleted' && ( + + )} +
+ ); + } + return (
@@ -146,7 +173,34 @@ export function SubmissionChangesDisplay({ ); } - // Detailed view + // Detailed view - special handling for photo deletions + if (item.item_type === 'photo_delete') { + return ( +
+
+ {getEntityIcon()} +

{changes.entityName}

+ {getActionBadge()} +
+ + {changes.photoChanges.length > 0 && changes.photoChanges[0].type === 'deleted' && ( + + )} +
+ ); + } + + // Detailed view for other items return (
diff --git a/src/lib/submissionChangeDetection.ts b/src/lib/submissionChangeDetection.ts index 8c225d80..1675a8cc 100644 --- a/src/lib/submissionChangeDetection.ts +++ b/src/lib/submissionChangeDetection.ts @@ -136,10 +136,13 @@ export async function detectChanges( const itemData = item.item_data || {}; const originalData = item.original_data || {}; - // Determine action type - const action: 'create' | 'edit' | 'delete' = - !originalData || Object.keys(originalData).length === 0 ? 'create' : - itemData.deleted ? 'delete' : 'edit'; + // Determine action type - special handling for photo_delete + let action: 'create' | 'edit' | 'delete' = 'edit'; + if (item.item_type === 'photo_delete' || itemData.action === 'delete' || itemData.deleted) { + action = 'delete'; + } else if (!originalData || Object.keys(originalData).length === 0) { + action = 'create'; + } const fieldChanges: FieldChange[] = []; const imageChanges: ImageChange[] = []; @@ -269,22 +272,32 @@ export async function detectChanges( const entityId = itemData.entity_id; if (entityType === 'park') { - const { data } = await supabase.from('parks').select('name').eq('id', entityId).single(); + const { data } = await supabase.from('parks').select('name').eq('id', entityId).maybeSingle(); if (data?.name) entityName = `${data.name} (${formatEntityType(entityType)})`; } else if (entityType === 'ride') { - const { data } = await supabase.from('rides').select('name').eq('id', entityId).single(); + const { data } = await supabase.from('rides').select('name').eq('id', entityId).maybeSingle(); if (data?.name) entityName = `${data.name} (${formatEntityType(entityType)})`; } else if (entityType === 'ride_model') { - const { data } = await supabase.from('ride_models').select('name').eq('id', entityId).single(); + const { data } = await supabase.from('ride_models').select('name').eq('id', entityId).maybeSingle(); if (data?.name) entityName = `${data.name} (${formatEntityType(entityType)})`; } else if (['manufacturer', 'operator', 'designer', 'property_owner'].includes(entityType)) { - const { data } = await supabase.from('companies').select('name').eq('id', entityId).single(); + const { data } = await supabase.from('companies').select('name').eq('id', entityId).maybeSingle(); if (data?.name) entityName = `${data.name} (${formatEntityType(entityType)})`; } } catch (err) { - console.error('Error fetching entity name:', err); + console.error('Error fetching entity name for photo operation:', err); } } + + // Add debugging warning if critical data is missing + if (!itemData.entity_name && item.item_type === 'photo_delete') { + console.warn(`[Photo Delete] Missing entity_name for photo_delete item`, { + item_type: item.item_type, + has_entity_type: !!itemData.entity_type, + has_entity_id: !!itemData.entity_id, + has_cloudflare_url: !!itemData.cloudflare_image_url + }); + } } else { // For regular entities, use name field entityName = itemData.name || originalData?.name || 'Unknown'; diff --git a/supabase/migrations/20251006182226_6c75308d-dc6d-4942-a793-45ddb48ad7a9.sql b/supabase/migrations/20251006182226_6c75308d-dc6d-4942-a793-45ddb48ad7a9.sql new file mode 100644 index 00000000..d14082d6 --- /dev/null +++ b/supabase/migrations/20251006182226_6c75308d-dc6d-4942-a793-45ddb48ad7a9.sql @@ -0,0 +1,53 @@ +-- Phase 1: Fix existing photo_delete submissions with missing entity_name + +-- Create a function to backfill missing entity names for photo_delete submissions +CREATE OR REPLACE FUNCTION backfill_photo_delete_entity_names() +RETURNS void +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path TO 'public' +AS $$ +DECLARE + item_record RECORD; + entity_name_value TEXT; +BEGIN + -- Find all photo_delete submission_items missing entity_name + FOR item_record IN + SELECT id, item_data + FROM submission_items + WHERE item_type = 'photo_delete' + AND item_data->>'entity_name' IS NULL + AND item_data->>'entity_id' IS NOT NULL + AND item_data->>'entity_type' IS NOT NULL + LOOP + -- Fetch entity name based on entity_type + CASE item_record.item_data->>'entity_type' + WHEN 'park' THEN + SELECT name INTO entity_name_value FROM parks WHERE id = (item_record.item_data->>'entity_id')::uuid; + WHEN 'ride' THEN + SELECT name INTO entity_name_value FROM rides WHERE id = (item_record.item_data->>'entity_id')::uuid; + WHEN 'ride_model' THEN + SELECT name INTO entity_name_value FROM ride_models WHERE id = (item_record.item_data->>'entity_id')::uuid; + WHEN 'manufacturer', 'operator', 'designer', 'property_owner' THEN + SELECT name INTO entity_name_value FROM companies WHERE id = (item_record.item_data->>'entity_id')::uuid; + ELSE + entity_name_value := NULL; + END CASE; + + -- Update the item_data if we found a name + IF entity_name_value IS NOT NULL THEN + UPDATE submission_items + SET item_data = item_data || jsonb_build_object('entity_name', entity_name_value) + WHERE id = item_record.id; + + RAISE NOTICE 'Updated submission_item % with entity_name: %', item_record.id, entity_name_value; + END IF; + END LOOP; +END; +$$; + +-- Run the backfill function +SELECT backfill_photo_delete_entity_names(); + +-- Drop the function after use (optional, but keeps things clean) +DROP FUNCTION IF EXISTS backfill_photo_delete_entity_names(); \ No newline at end of file