mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 17:31:12 -05:00
Fix submission display issues
This commit is contained in:
@@ -1518,20 +1518,39 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
|
|||||||
item.submission_type === 'operator' ||
|
item.submission_type === 'operator' ||
|
||||||
item.submission_type === 'property_owner' ||
|
item.submission_type === 'property_owner' ||
|
||||||
item.submission_type === 'park' ||
|
item.submission_type === 'park' ||
|
||||||
item.submission_type === 'ride') ? (
|
item.submission_type === 'ride' ||
|
||||||
|
item.submission_type === 'ride_model' ||
|
||||||
|
item.submission_type === 'photo_delete' ||
|
||||||
|
item.submission_type === 'photo_edit') ? (
|
||||||
<SubmissionItemsList
|
<SubmissionItemsList
|
||||||
submissionId={item.id}
|
submissionId={item.id}
|
||||||
view="detailed"
|
view="detailed"
|
||||||
showImages={true}
|
showImages={true}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div className="rounded-md border border-amber-300 dark:border-amber-700 bg-amber-50 dark:bg-amber-950 p-4">
|
||||||
<div className="text-sm text-muted-foreground mb-2">
|
<div className="flex items-center gap-2 mb-2">
|
||||||
Type: {item.submission_type}
|
<AlertTriangle className="h-4 w-4 text-amber-600" />
|
||||||
|
<span className="font-medium text-amber-900 dark:text-amber-100">
|
||||||
|
Unknown Submission Type
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<pre className="text-sm whitespace-pre-wrap">
|
<div className="text-sm text-amber-800 dark:text-amber-200 mb-2">
|
||||||
|
Type: <code className="bg-amber-100 dark:bg-amber-900 px-1 py-0.5 rounded">{item.submission_type}</code>
|
||||||
|
</div>
|
||||||
|
{item.content?.action && (
|
||||||
|
<div className="text-sm text-amber-800 dark:text-amber-200 mb-2">
|
||||||
|
Action: <span className="font-medium capitalize">{item.content.action}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<details className="text-sm">
|
||||||
|
<summary className="cursor-pointer text-amber-700 dark:text-amber-300 hover:text-amber-900 dark:hover:text-amber-100">
|
||||||
|
View raw data (for developers)
|
||||||
|
</summary>
|
||||||
|
<pre className="mt-2 text-xs whitespace-pre-wrap bg-amber-100 dark:bg-amber-900 p-2 rounded overflow-x-auto">
|
||||||
{JSON.stringify(item.content, null, 2)}
|
{JSON.stringify(item.content, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
|
</details>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -118,6 +118,9 @@ interface PhotoDeletionPreviewProps {
|
|||||||
url: string;
|
url: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
caption?: string;
|
caption?: string;
|
||||||
|
entity_type?: string;
|
||||||
|
entity_name?: string;
|
||||||
|
deletion_reason?: string;
|
||||||
};
|
};
|
||||||
compact?: boolean;
|
compact?: boolean;
|
||||||
}
|
}
|
||||||
@@ -147,13 +150,21 @@ export function PhotoDeletionPreview({ photo, compact = false }: PhotoDeletionPr
|
|||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{(photo.title || photo.caption) && (
|
<div className="flex-1 text-sm space-y-2">
|
||||||
<div className="flex-1 text-sm">
|
|
||||||
{photo.title && <div className="font-medium">{photo.title}</div>}
|
{photo.title && <div className="font-medium">{photo.title}</div>}
|
||||||
{photo.caption && <div className="text-muted-foreground">{photo.caption}</div>}
|
{photo.caption && <div className="text-muted-foreground">{photo.caption}</div>}
|
||||||
|
{photo.entity_type && photo.entity_name && (
|
||||||
|
<div className="text-xs text-muted-foreground">
|
||||||
|
From: <span className="capitalize">{photo.entity_type}</span> - {photo.entity_name}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{photo.deletion_reason && (
|
||||||
|
<div className="text-xs p-2 bg-destructive/5 rounded border border-destructive/20">
|
||||||
|
<span className="font-medium">Reason:</span> {photo.deletion_reason}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,11 +54,14 @@ export function SubmissionChangesDisplay({
|
|||||||
switch (item.item_type) {
|
switch (item.item_type) {
|
||||||
case 'park': return <Building2 className={iconClass} />;
|
case 'park': return <Building2 className={iconClass} />;
|
||||||
case 'ride': return <Train className={iconClass} />;
|
case 'ride': return <Train className={iconClass} />;
|
||||||
|
case 'ride_model': return <Train className={iconClass} />;
|
||||||
case 'manufacturer':
|
case 'manufacturer':
|
||||||
case 'operator':
|
case 'operator':
|
||||||
case 'property_owner':
|
case 'property_owner':
|
||||||
case 'designer': return <Building className={iconClass} />;
|
case 'designer': return <Building className={iconClass} />;
|
||||||
case 'photo': return <ImageIcon className={iconClass} />;
|
case 'photo':
|
||||||
|
case 'photo_edit':
|
||||||
|
case 'photo_delete': return <ImageIcon className={iconClass} />;
|
||||||
default: return <MapPin className={iconClass} />;
|
default: return <MapPin className={iconClass} />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ export interface PhotoChange {
|
|||||||
newCaption?: string;
|
newCaption?: string;
|
||||||
oldTitle?: string;
|
oldTitle?: string;
|
||||||
newTitle?: string;
|
newTitle?: string;
|
||||||
|
entity_type?: string;
|
||||||
|
entity_name?: string;
|
||||||
|
deletion_reason?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,8 +54,8 @@ async function detectPhotoChanges(submissionId: string): Promise<PhotoChange[]>
|
|||||||
const changes: PhotoChange[] = [];
|
const changes: PhotoChange[] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Fetch photo submission with items - use array query to avoid 406 errors
|
// First check for photo submission items (photo additions)
|
||||||
const { data: photoSubmissions, error } = await supabase
|
const { data: photoSubmissions, error: photoError } = await supabase
|
||||||
.from('photo_submissions')
|
.from('photo_submissions')
|
||||||
.select(`
|
.select(`
|
||||||
*,
|
*,
|
||||||
@@ -60,15 +63,11 @@ async function detectPhotoChanges(submissionId: string): Promise<PhotoChange[]>
|
|||||||
`)
|
`)
|
||||||
.eq('submission_id', submissionId);
|
.eq('submission_id', submissionId);
|
||||||
|
|
||||||
if (error) {
|
if (photoError) {
|
||||||
console.error('Error fetching photo submissions:', error);
|
console.error('Error fetching photo submissions:', photoError);
|
||||||
return changes;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
const photoSubmission = photoSubmissions?.[0];
|
const photoSubmission = photoSubmissions?.[0];
|
||||||
if (photoSubmission?.items && photoSubmission.items.length > 0) {
|
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({
|
changes.push({
|
||||||
type: 'added',
|
type: 'added',
|
||||||
photos: photoSubmission.items.map((item: any) => ({
|
photos: photoSubmission.items.map((item: any) => ({
|
||||||
@@ -78,6 +77,48 @@ async function detectPhotoChanges(submissionId: string): Promise<PhotoChange[]>
|
|||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for photo edits and deletions in submission_items
|
||||||
|
const { data: submissionItems, error: itemsError } = await supabase
|
||||||
|
.from('submission_items')
|
||||||
|
.select('*')
|
||||||
|
.eq('submission_id', submissionId)
|
||||||
|
.in('item_type', ['photo_edit', 'photo_delete']);
|
||||||
|
|
||||||
|
if (itemsError) {
|
||||||
|
console.error('Error fetching submission items for photos:', itemsError);
|
||||||
|
} else if (submissionItems && submissionItems.length > 0) {
|
||||||
|
for (const item of submissionItems) {
|
||||||
|
const itemData = item.item_data as Record<string, any>;
|
||||||
|
const originalData = item.original_data as Record<string, any> | null;
|
||||||
|
|
||||||
|
if (item.item_type === 'photo_delete' && itemData) {
|
||||||
|
changes.push({
|
||||||
|
type: 'deleted',
|
||||||
|
photo: {
|
||||||
|
url: itemData.photo_url || itemData.cloudflare_image_url || '',
|
||||||
|
title: itemData.title,
|
||||||
|
caption: itemData.caption,
|
||||||
|
entity_type: itemData.entity_type,
|
||||||
|
entity_name: itemData.entity_name,
|
||||||
|
deletion_reason: itemData.deletion_reason
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (item.item_type === 'photo_edit' && itemData && originalData) {
|
||||||
|
changes.push({
|
||||||
|
type: 'edited',
|
||||||
|
photo: {
|
||||||
|
url: itemData.photo_url || itemData.cloudflare_image_url || '',
|
||||||
|
title: itemData.title,
|
||||||
|
caption: itemData.caption,
|
||||||
|
oldTitle: originalData.title,
|
||||||
|
oldCaption: originalData.caption
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error detecting photo changes:', err);
|
console.error('Error detecting photo changes:', err);
|
||||||
}
|
}
|
||||||
@@ -420,6 +461,14 @@ export function formatFieldValue(value: any): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle enum-like strings (snake_case or kebab-case) - capitalize and replace separators
|
||||||
|
if (typeof value === 'string' && (value.includes('_') || value.includes('-'))) {
|
||||||
|
return value
|
||||||
|
.split(/[_-]/)
|
||||||
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
||||||
|
.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof value === 'number') return value.toLocaleString();
|
if (typeof value === 'number') return value.toLocaleString();
|
||||||
return String(value);
|
return String(value);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user