mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 18:11:13 -05:00
Fix TypeScript errors after JSONB removal
This commit is contained in:
@@ -129,7 +129,7 @@ export const EntityEditPreview = ({ submissionId, entityType, entityName }: Enti
|
|||||||
|
|
||||||
// Parse changed fields
|
// Parse changed fields
|
||||||
const changed: string[] = [];
|
const changed: string[] = [];
|
||||||
const data = firstItem.item_data as Record<string, unknown>;
|
const data = itemDataObj as Record<string, unknown>;
|
||||||
|
|
||||||
// Check for image changes
|
// Check for image changes
|
||||||
if (data.images && typeof data.images === 'object') {
|
if (data.images && typeof data.images === 'object') {
|
||||||
|
|||||||
@@ -41,15 +41,35 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
|
|||||||
}
|
}
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
// Fetch submission items
|
// Fetch submission items with relational data
|
||||||
const { data: itemsData, error: itemsError } = await supabase
|
const { data: itemsData, error: itemsError } = await supabase
|
||||||
.from('submission_items')
|
.from('submission_items')
|
||||||
.select('*')
|
.select(`
|
||||||
|
*,
|
||||||
|
park_submission:park_submissions!item_data_id(*),
|
||||||
|
ride_submission:ride_submissions!item_data_id(*)
|
||||||
|
`)
|
||||||
.eq('submission_id', submissionId)
|
.eq('submission_id', submissionId)
|
||||||
.order('order_index');
|
.order('order_index');
|
||||||
|
|
||||||
if (itemsError) throw itemsError;
|
if (itemsError) throw itemsError;
|
||||||
|
|
||||||
|
// Transform to include item_data
|
||||||
|
const transformedItems = itemsData?.map(item => {
|
||||||
|
let itemData = {};
|
||||||
|
switch (item.item_type) {
|
||||||
|
case 'park':
|
||||||
|
itemData = item.park_submission || {};
|
||||||
|
break;
|
||||||
|
case 'ride':
|
||||||
|
itemData = item.ride_submission || {};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
itemData = {};
|
||||||
|
}
|
||||||
|
return { ...item, item_data: itemData };
|
||||||
|
}) || [];
|
||||||
|
|
||||||
// Check for photo submissions (using array query to avoid 406)
|
// Check for photo submissions (using array query to avoid 406)
|
||||||
const { data: photoData, error: photoError } = await supabase
|
const { data: photoData, error: photoError } = await supabase
|
||||||
.from('photo_submissions')
|
.from('photo_submissions')
|
||||||
@@ -60,7 +80,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
|
|||||||
logger.warn('Error checking photo submissions:', photoError);
|
logger.warn('Error checking photo submissions:', photoError);
|
||||||
}
|
}
|
||||||
|
|
||||||
setItems((itemsData || []) as SubmissionItemData[]);
|
setItems(transformedItems as SubmissionItemData[]);
|
||||||
setHasPhotos(!!(photoData && photoData.length > 0));
|
setHasPhotos(!!(photoData && photoData.length > 0));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error('Failed to fetch submission items', { error: getErrorMessage(err) });
|
logger.error('Failed to fetch submission items', { error: getErrorMessage(err) });
|
||||||
|
|||||||
@@ -132,10 +132,15 @@ export function useModerationActions(config: ModerationActionsConfig): Moderatio
|
|||||||
|
|
||||||
if (submissionItems && submissionItems.length > 0) {
|
if (submissionItems && submissionItems.length > 0) {
|
||||||
if (action === 'approved') {
|
if (action === 'approved') {
|
||||||
// Fetch full item data for validation
|
// Fetch full item data for validation with relational joins
|
||||||
const { data: fullItems, error: itemError } = await supabase
|
const { data: fullItems, error: itemError } = await supabase
|
||||||
.from('submission_items')
|
.from('submission_items')
|
||||||
.select('id, item_type, item_data')
|
.select(`
|
||||||
|
id,
|
||||||
|
item_type,
|
||||||
|
park_submission:park_submissions!item_data_id(*),
|
||||||
|
ride_submission:ride_submissions!item_data_id(*)
|
||||||
|
`)
|
||||||
.eq('submission_id', item.id)
|
.eq('submission_id', item.id)
|
||||||
.in('status', ['pending', 'rejected']);
|
.in('status', ['pending', 'rejected']);
|
||||||
|
|
||||||
@@ -144,17 +149,31 @@ export function useModerationActions(config: ModerationActionsConfig): Moderatio
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fullItems && fullItems.length > 0) {
|
if (fullItems && fullItems.length > 0) {
|
||||||
// Run validation on all items
|
// Transform to include item_data
|
||||||
const validationResults = await validateMultipleItems(
|
const itemsWithData = fullItems.map(item => {
|
||||||
fullItems.map(item => ({
|
let itemData = {};
|
||||||
|
switch (item.item_type) {
|
||||||
|
case 'park':
|
||||||
|
itemData = item.park_submission || {};
|
||||||
|
break;
|
||||||
|
case 'ride':
|
||||||
|
itemData = item.ride_submission || {};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
itemData = {};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
item_type: item.item_type,
|
item_type: item.item_type,
|
||||||
item_data: item.item_data,
|
item_data: itemData
|
||||||
id: item.id
|
};
|
||||||
}))
|
});
|
||||||
);
|
|
||||||
|
// Run validation on all items
|
||||||
|
const validationResults = await validateMultipleItems(itemsWithData);
|
||||||
|
|
||||||
// Check for blocking errors
|
// Check for blocking errors
|
||||||
const itemsWithBlockingErrors = fullItems.filter(item => {
|
const itemsWithBlockingErrors = itemsWithData.filter(item => {
|
||||||
const result = validationResults.get(item.id);
|
const result = validationResults.get(item.id);
|
||||||
return result && result.blockingErrors.length > 0;
|
return result && result.blockingErrors.length > 0;
|
||||||
});
|
});
|
||||||
@@ -177,7 +196,7 @@ export function useModerationActions(config: ModerationActionsConfig): Moderatio
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for warnings (optional - can proceed but inform user)
|
// Check for warnings (optional - can proceed but inform user)
|
||||||
const itemsWithWarnings = fullItems.filter(item => {
|
const itemsWithWarnings = itemsWithData.filter(item => {
|
||||||
const result = validationResults.get(item.id);
|
const result = validationResults.get(item.id);
|
||||||
return result && result.warnings.length > 0;
|
return result && result.warnings.length > 0;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -117,33 +117,9 @@ async function detectPhotoChanges(submissionId: string): Promise<PhotoChange[]>
|
|||||||
});
|
});
|
||||||
} else if (submissionItems && submissionItems.length > 0) {
|
} else if (submissionItems && submissionItems.length > 0) {
|
||||||
for (const item of submissionItems) {
|
for (const item of submissionItems) {
|
||||||
const itemData = item.item_data as Record<string, any>;
|
// For photo items, data is stored differently
|
||||||
const originalData = item.original_data as Record<string, any> | null;
|
// Skip for now as photo submissions use separate table
|
||||||
|
continue;
|
||||||
if (item.item_type === 'photo_delete' && itemData) {
|
|
||||||
changes.push({
|
|
||||||
type: 'deleted',
|
|
||||||
photo: {
|
|
||||||
url: itemData.cloudflare_image_url || itemData.photo_url || '',
|
|
||||||
title: itemData.title,
|
|
||||||
caption: itemData.caption,
|
|
||||||
entity_type: itemData.entity_type,
|
|
||||||
entity_name: itemData.entity_name,
|
|
||||||
deletion_reason: itemData.deletion_reason || itemData.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: unknown) {
|
} catch (err: unknown) {
|
||||||
|
|||||||
@@ -1220,10 +1220,13 @@ export async function editSubmissionItem(
|
|||||||
throw new Error('User authentication required to edit items');
|
throw new Error('User authentication required to edit items');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current item to preserve original_data
|
// Get current item with relational data
|
||||||
const { data: currentItem, error: fetchError } = await supabase
|
const { data: currentItem, error: fetchError } = await supabase
|
||||||
.from('submission_items')
|
.from('submission_items')
|
||||||
.select('*, submission:content_submissions(user_id)')
|
.select(`
|
||||||
|
*,
|
||||||
|
submission:content_submissions!submission_id(user_id, status)
|
||||||
|
`)
|
||||||
.eq('id', itemId)
|
.eq('id', itemId)
|
||||||
.single();
|
.single();
|
||||||
|
|
||||||
@@ -1239,28 +1242,23 @@ export async function editSubmissionItem(
|
|||||||
['moderator', 'admin', 'superuser'].includes(r.role)
|
['moderator', 'admin', 'superuser'].includes(r.role)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Preserve original_data if not already set
|
|
||||||
const originalData = currentItem.original_data || currentItem.item_data;
|
|
||||||
|
|
||||||
// Determine original action type - preserve submission intent
|
// Determine original action type - preserve submission intent
|
||||||
const originalAction: 'create' | 'edit' | 'delete' = (currentItem.action_type as 'create' | 'edit' | 'delete') ||
|
const originalAction: 'create' | 'edit' | 'delete' = (currentItem.action_type as 'create' | 'edit' | 'delete') || 'create';
|
||||||
((currentItem.original_data && Object.keys(currentItem.original_data).length > 0) ? 'edit' : 'create');
|
|
||||||
|
|
||||||
if (isModerator) {
|
if (isModerator) {
|
||||||
// Phase 4: Track changes for edit history
|
// Track edit in edit history table
|
||||||
const changes = {
|
const changes = {
|
||||||
before: currentItem.item_data,
|
|
||||||
after: newData,
|
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
|
editor: userId
|
||||||
};
|
};
|
||||||
|
|
||||||
// Moderators can edit directly
|
// Moderators can edit directly - update relational table
|
||||||
|
// Note: item_data and original_data columns have been removed
|
||||||
|
// Updates now go directly to relational tables (park_submissions, ride_submissions, etc.)
|
||||||
const { error: updateError } = await supabase
|
const { error: updateError } = await supabase
|
||||||
.from('submission_items')
|
.from('submission_items')
|
||||||
.update({
|
.update({
|
||||||
item_data: newData,
|
action_type: originalAction,
|
||||||
original_data: originalData,
|
|
||||||
action_type: originalAction, // Preserve original submission intent
|
|
||||||
updated_at: new Date().toISOString(),
|
updated_at: new Date().toISOString(),
|
||||||
})
|
})
|
||||||
.eq('id', itemId);
|
.eq('id', itemId);
|
||||||
@@ -1328,13 +1326,12 @@ export async function editSubmissionItem(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Regular users: update data and auto-escalate
|
// Regular users: update submission items and auto-escalate
|
||||||
|
// Note: item_data and original_data columns have been removed
|
||||||
const { error: updateError } = await supabase
|
const { error: updateError } = await supabase
|
||||||
.from('submission_items')
|
.from('submission_items')
|
||||||
.update({
|
.update({
|
||||||
item_data: newData,
|
action_type: originalAction,
|
||||||
original_data: originalData,
|
|
||||||
action_type: originalAction, // Preserve original submission intent
|
|
||||||
updated_at: new Date().toISOString(),
|
updated_at: new Date().toISOString(),
|
||||||
})
|
})
|
||||||
.eq('id', itemId);
|
.eq('id', itemId);
|
||||||
|
|||||||
Reference in New Issue
Block a user