Reconstruct fetchItems function

This commit is contained in:
gpt-engineer-app[bot]
2025-10-06 20:24:46 +00:00
parent 5eba459d0e
commit 1c356ed69e

View File

@@ -120,8 +120,284 @@ export const ModerationQueue = forwardRef<ModerationQueueRef>((props, ref) => {
timestamp: new Date().toISOString()
});
// TODO: Function body was accidentally removed - needs restoration
console.error('fetchItems function body is missing!');
try {
// Set loading states
if (!silent) {
setLoading(true);
} else {
setIsRefreshing(true);
}
// Build base query for content submissions
let submissionsQuery = supabase
.from('content_submissions')
.select(`
id,
submission_type,
status,
content,
created_at,
user_id,
reviewed_at,
reviewer_id,
reviewer_notes,
escalated,
priority,
assigned_to,
locked_until
`)
.order('priority', { ascending: false })
.order('created_at', { ascending: true });
// Apply status filter
if (statusFilter === 'all') {
submissionsQuery = submissionsQuery.in('status', ['pending', 'approved', 'rejected', 'partially_approved']);
} else if (statusFilter === 'pending') {
submissionsQuery = submissionsQuery.in('status', ['pending', 'partially_approved']);
} else {
submissionsQuery = submissionsQuery.eq('status', statusFilter);
}
// Apply entity type filter
if (entityFilter === 'photos') {
submissionsQuery = submissionsQuery.eq('submission_type', 'photo');
} else if (entityFilter === 'submissions') {
submissionsQuery = submissionsQuery.neq('submission_type', 'photo');
}
const { data: submissions, error: submissionsError } = await submissionsQuery;
if (submissionsError) throw submissionsError;
// Get user IDs and fetch user profiles
const userIds = submissions?.map(s => s.user_id).filter(Boolean) || [];
const reviewerIds = submissions?.map(s => s.reviewer_id).filter((id): id is string => !!id) || [];
const allUserIds = [...new Set([...userIds, ...reviewerIds])];
let userProfiles: any[] = [];
if (allUserIds.length > 0) {
const { data: profiles } = await supabase
.from('profiles')
.select('user_id, username, display_name, avatar_url')
.in('user_id', allUserIds);
userProfiles = profiles || [];
}
const userProfileMap = new Map(userProfiles.map(p => [p.user_id, p]));
// Collect entity IDs for bulk fetching
const rideIds = new Set<string>();
const parkIds = new Set<string>();
const companyIds = new Set<string>();
const rideModelIds = new Set<string>();
submissions?.forEach(submission => {
const content = submission.content as any;
if (content && typeof content === 'object') {
if (content.ride_id) rideIds.add(content.ride_id);
if (content.park_id) parkIds.add(content.park_id);
if (content.company_id) companyIds.add(content.company_id);
if (content.entity_id) {
if (submission.submission_type === 'ride') rideIds.add(content.entity_id);
if (submission.submission_type === 'park') parkIds.add(content.entity_id);
if (['manufacturer', 'operator', 'designer', 'property_owner'].includes(submission.submission_type)) {
companyIds.add(content.entity_id);
}
}
if (content.manufacturer_id) companyIds.add(content.manufacturer_id);
if (content.designer_id) companyIds.add(content.designer_id);
if (content.operator_id) companyIds.add(content.operator_id);
if (content.property_owner_id) companyIds.add(content.property_owner_id);
if (content.ride_model_id) rideModelIds.add(content.ride_model_id);
}
});
// Fetch entities only if we don't have them cached or if they're new
const fetchPromises: Promise<{ type: string; data: any[] }>[] = [];
if (rideIds.size > 0) {
const uncachedRideIds = Array.from(rideIds).filter(id => !entityCache.rides.has(id));
if (uncachedRideIds.length > 0) {
fetchPromises.push(
Promise.resolve(
supabase
.from('rides')
.select('id, name, park_id')
.in('id', uncachedRideIds)
).then(({ data }) => ({ type: 'rides', data: data || [] }))
);
}
}
if (parkIds.size > 0) {
const uncachedParkIds = Array.from(parkIds).filter(id => !entityCache.parks.has(id));
if (uncachedParkIds.length > 0) {
fetchPromises.push(
Promise.resolve(
supabase
.from('parks')
.select('id, name')
.in('id', uncachedParkIds)
).then(({ data }) => ({ type: 'parks', data: data || [] }))
);
}
}
if (companyIds.size > 0) {
const uncachedCompanyIds = Array.from(companyIds).filter(id => !entityCache.companies.has(id));
if (uncachedCompanyIds.length > 0) {
fetchPromises.push(
Promise.resolve(
supabase
.from('companies')
.select('id, name')
.in('id', uncachedCompanyIds)
).then(({ data }) => ({ type: 'companies', data: data || [] }))
);
}
}
// Fetch all uncached entities
const entityResults = await Promise.all(fetchPromises);
// Update entity cache
entityResults.forEach(result => {
if (result.type === 'rides') {
result.data.forEach((ride: any) => {
entityCache.rides.set(ride.id, ride);
if (ride.park_id) parkIds.add(ride.park_id);
});
} else if (result.type === 'parks') {
result.data.forEach((park: any) => {
entityCache.parks.set(park.id, park);
});
} else if (result.type === 'companies') {
result.data.forEach((company: any) => {
entityCache.companies.set(company.id, company);
});
}
});
// Helper function to create memo key
const createMemoKey = (submission: any): string => {
return JSON.stringify({
id: submission.id,
status: submission.status,
content: submission.content,
reviewed_at: submission.reviewed_at,
reviewer_notes: submission.reviewer_notes,
});
};
// Map submissions to moderation items with memoization
const moderationItems: ModerationItem[] = submissions?.map(submission => {
const memoKey = createMemoKey(submission);
const existingMemo = submissionMemo.get(submission.id);
// Check if we can reuse the memoized item
if (existingMemo && createMemoKey(existingMemo) === memoKey) {
return existingMemo as ModerationItem;
}
// Resolve entity name
const content = submission.content as any;
let entityName = content?.name || 'Unknown';
let parkName: string | undefined;
if (submission.submission_type === 'ride' && content?.entity_id) {
const ride = entityCache.rides.get(content.entity_id);
if (ride) {
entityName = ride.name;
if (ride.park_id) {
const park = entityCache.parks.get(ride.park_id);
if (park) parkName = park.name;
}
}
} else if (submission.submission_type === 'park' && content?.entity_id) {
const park = entityCache.parks.get(content.entity_id);
if (park) entityName = park.name;
} else if (['manufacturer', 'operator', 'designer', 'property_owner'].includes(submission.submission_type) && content?.entity_id) {
const company = entityCache.companies.get(content.entity_id);
if (company) entityName = company.name;
} else if (content?.ride_id) {
const ride = entityCache.rides.get(content.ride_id);
if (ride) {
entityName = ride.name;
if (ride.park_id) {
const park = entityCache.parks.get(ride.park_id);
if (park) parkName = park.name;
}
}
} else if (content?.park_id) {
const park = entityCache.parks.get(content.park_id);
if (park) parkName = park.name;
}
const userProfile = userProfileMap.get(submission.user_id);
const reviewerProfile = submission.reviewer_id ? userProfileMap.get(submission.reviewer_id) : undefined;
const item: ModerationItem = {
id: submission.id,
type: 'content_submission',
content: submission.content,
created_at: submission.created_at,
user_id: submission.user_id,
status: submission.status,
submission_type: submission.submission_type,
user_profile: userProfile ? {
username: userProfile.username,
display_name: userProfile.display_name,
avatar_url: userProfile.avatar_url,
} : undefined,
entity_name: entityName,
park_name: parkName,
reviewed_at: submission.reviewed_at,
reviewed_by: submission.reviewer_id,
reviewer_notes: submission.reviewer_notes,
reviewer_profile: reviewerProfile,
};
return item;
}) || [];
// Update memoization cache
const newMemoMap = new Map<string, ModerationItem>();
moderationItems.forEach(item => {
newMemoMap.set(item.id, item);
});
setSubmissionMemo(newMemoMap);
// Apply smart merge for state updates
const mergeResult = smartMergeArray(items, moderationItems, {
compareFields: ['status', 'reviewed_at', 'reviewer_notes'],
preserveOrder: silent && preserveInteraction,
addToTop: false,
});
if (!silent || mergeResult.hasChanges) {
setItems(mergeResult.items);
// Track new items for toast notification
if (silent && mergeResult.changes.added.length > 0) {
setNewItemsCount(prev => prev + mergeResult.changes.added.length);
} else if (!silent) {
setNewItemsCount(0);
}
}
} catch (error: any) {
console.error('Error fetching moderation items:', error);
toast({
title: 'Error',
description: error.message || 'Failed to fetch moderation queue',
variant: 'destructive',
});
} finally {
setLoading(false);
setIsRefreshing(false);
setIsInitialLoad(false);
}
};
// Expose refresh method via ref