Fix internal error

This commit is contained in:
gpt-engineer-app[bot]
2025-11-03 02:17:37 +00:00
parent 9e02748067
commit 5a2c72ecd6
16 changed files with 67 additions and 52 deletions

View File

@@ -97,7 +97,7 @@ export function ActivityCard({ activity }: ActivityCardProps) {
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<Avatar className="w-5 h-5">
<AvatarImage src={activity.moderator?.avatar_url} />
<AvatarImage src={activity.moderator?.avatar_url || undefined} />
<AvatarFallback className="text-xs">{moderatorInitial}</AvatarFallback>
</Avatar>
<span className="truncate">

View File

@@ -200,7 +200,7 @@ export const EntityEditPreview = ({ submissionId, entityType, entityName }: Enti
</Badge>
</div>
{itemData?.cloudflare_image_url && typeof itemData.cloudflare_image_url === 'string' && (
{(itemData?.cloudflare_image_url && typeof itemData.cloudflare_image_url === 'string' && (
<Card className="overflow-hidden">
<CardContent className="p-2">
<img
@@ -210,7 +210,7 @@ export const EntityEditPreview = ({ submissionId, entityType, entityName }: Enti
/>
</CardContent>
</Card>
)}
)) as React.ReactNode}
{isEdit && (
<div className="space-y-2 text-sm">
@@ -229,12 +229,12 @@ export const EntityEditPreview = ({ submissionId, entityType, entityName }: Enti
</div>
)}
{!isEdit && itemData?.reason && typeof itemData.reason === 'string' && (
{(!isEdit && itemData?.reason && typeof itemData.reason === 'string' && (
<div className="text-sm">
<span className="font-medium">Reason: </span>
<span className="text-muted-foreground">{itemData.reason}</span>
</div>
)}
)) as React.ReactNode}
<div className="text-xs text-muted-foreground italic">
Click "Review Items" for full details
@@ -244,7 +244,7 @@ export const EntityEditPreview = ({ submissionId, entityType, entityName }: Enti
}
// Build photos array for modal
const photos = [];
const photos: Array<{ id: string; url: string; caption: string | null }> = [];
if (bannerImageUrl) {
photos.push({
id: 'banner',
@@ -336,7 +336,10 @@ export const EntityEditPreview = ({ submissionId, entityType, entityName }: Enti
</div>
<PhotoModal
photos={photos}
photos={photos.map(photo => ({
...photo,
caption: photo.caption ?? undefined
}))}
initialIndex={selectedImageIndex}
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}

View File

@@ -221,11 +221,11 @@ export function LocationDiff({ oldLocation, newLocation, compact = false }: Loca
}
if (typeof loc === 'object') {
const parts = [];
if (loc.city) parts.push(loc.city);
if (loc.state_province) parts.push(loc.state_province);
if (loc.country && loc.country !== loc.state_province) parts.push(loc.country);
if (loc.postal_code) parts.push(loc.postal_code);
const parts: string[] = [];
if (loc.city) parts.push(String(loc.city));
if (loc.state_province) parts.push(String(loc.state_province));
if (loc.country && loc.country !== loc.state_province) parts.push(String(loc.country));
if (loc.postal_code) parts.push(String(loc.postal_code));
let locationStr = parts.join(', ') || 'Unknown';

View File

@@ -8,6 +8,7 @@ import { Textarea } from '@/components/ui/textarea';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { toast } from '@/hooks/use-toast';
import { useIsMobile } from '@/hooks/use-mobile';
import { logger } from '@/lib/logger';
import { useUserRole } from '@/hooks/useUserRole';
import { getErrorMessage } from '@/lib/errorHandler';
import { useAuth } from '@/hooks/useAuth';
@@ -93,6 +94,11 @@ export function ItemEditDialog({ item, items, open, onOpenChange, onComplete }:
};
const handlePhotoSubmit = async (caption: string, credit: string) => {
if (!item?.item_data) {
logger.error('No item data available for photo submission');
return;
}
const itemData = typeof item.item_data === 'object' && item.item_data !== null && !Array.isArray(item.item_data)
? item.item_data as Record<string, unknown>
: {};

View File

@@ -86,12 +86,12 @@ export function ItemReviewCard({ item, onEdit, onStatusChange, submissionId }: I
<CardTitle className={isMobile ? "text-sm" : "text-base"}>
{item.item_type.replace('_', ' ').toUpperCase()}
</CardTitle>
{item.original_data && Object.keys(item.original_data).length > 0 && (
{(item.original_data && Object.keys(item.original_data).length > 0 && (
<Badge variant="secondary" className="text-xs bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300 border border-blue-300 dark:border-blue-700">
<Edit className="w-3 h-3 mr-1" />
Moderator Edited
</Badge>
)}
)) as React.ReactNode}
{hasBlockingErrors && (
<Badge variant="destructive" className="text-xs">
Blocked

View File

@@ -315,7 +315,7 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
activeEntityFilter={queueManager.filters.entityFilter}
activeStatusFilter={queueManager.filters.statusFilter}
sortConfig={queueManager.filters.sortConfig}
isMobile={isMobile}
isMobile={isMobile ?? false}
isLoading={queueManager.loadingState === 'loading'}
onEntityFilterChange={queueManager.filters.setEntityFilter}
onStatusFilterChange={queueManager.filters.setStatusFilter}
@@ -367,11 +367,11 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
<ModerationErrorBoundary key={item.id} submissionId={item.id}>
<QueueItem
item={item}
isMobile={isMobile}
isMobile={isMobile ?? false}
actionLoading={queueManager.actionLoading}
isLockedByMe={queueManager.queue.isLockedByMe(item.id, item.assigned_to, item.locked_until)}
isLockedByOther={queueManager.queue.isLockedByOther(item.id, item.assigned_to, item.locked_until)}
lockStatus={getLockStatus({ assigned_to: item.assigned_to, locked_until: item.locked_until }, user?.id || '')}
isLockedByMe={queueManager.queue.isLockedByMe(item.id, item.assigned_to || null, item.locked_until || null)}
isLockedByOther={queueManager.queue.isLockedByOther(item.id, item.assigned_to || null, item.locked_until || null)}
lockStatus={getLockStatus({ assigned_to: item.assigned_to || null, locked_until: item.locked_until || null }, user?.id || '')}
currentLockSubmissionId={queueManager.queue.currentLock?.submissionId}
notes={notes}
isAdmin={isAdmin()}
@@ -428,11 +428,11 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
<ModerationErrorBoundary submissionId={item.id}>
<QueueItem
item={item}
isMobile={isMobile}
isMobile={isMobile ?? false}
actionLoading={queueManager.actionLoading}
isLockedByMe={queueManager.queue.isLockedByMe(item.id, item.assigned_to, item.locked_until)}
isLockedByOther={queueManager.queue.isLockedByOther(item.id, item.assigned_to, item.locked_until)}
lockStatus={getLockStatus({ assigned_to: item.assigned_to, locked_until: item.locked_until }, user?.id || '')}
isLockedByMe={queueManager.queue.isLockedByMe(item.id, item.assigned_to || null, item.locked_until || null)}
isLockedByOther={queueManager.queue.isLockedByOther(item.id, item.assigned_to || null, item.locked_until || null)}
lockStatus={getLockStatus({ assigned_to: item.assigned_to || null, locked_until: item.locked_until || null }, user?.id || '')}
currentLockSubmissionId={queueManager.queue.currentLock?.submissionId}
notes={notes}
isAdmin={isAdmin()}
@@ -467,7 +467,7 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
totalPages={queueManager.pagination.totalPages}
pageSize={queueManager.pagination.pageSize}
totalCount={queueManager.pagination.totalCount}
isMobile={isMobile}
isMobile={isMobile ?? false}
onPageChange={queueManager.pagination.setCurrentPage}
onPageSizeChange={queueManager.pagination.setPageSize}
/>
@@ -475,7 +475,10 @@ export const ModerationQueue = forwardRef<ModerationQueueRef, ModerationQueuePro
{/* Modals */}
<PhotoModal
photos={selectedPhotos}
photos={selectedPhotos.map(photo => ({
...photo,
caption: photo.caption ?? undefined
}))}
initialIndex={selectedPhotoIndex}
isOpen={photoModalOpen}
onClose={() => setPhotoModalOpen(false)}

View File

@@ -134,7 +134,7 @@ export const QueueItem = memo(({
<QueueItemHeader
item={item}
isMobile={isMobile}
hasModeratorEdits={hasModeratorEdits}
hasModeratorEdits={hasModeratorEdits ?? false}
isLockedByOther={isLockedByOther}
currentLockSubmissionId={currentLockSubmissionId}
validationResult={validationResult}
@@ -190,7 +190,7 @@ export const QueueItem = memo(({
<div className="text-sm font-medium mb-2">Attached Photos:</div>
<PhotoGrid
photos={reviewPhotos}
onPhotoClick={onOpenPhotos}
onPhotoClick={(photos, index) => onOpenPhotos(photos as any, index)}
maxDisplay={isMobile ? 3 : 4}
className="grid-cols-2 md:grid-cols-3"
/>
@@ -231,7 +231,7 @@ export const QueueItem = memo(({
<div className="text-sm space-y-2">
<div>
<span className="text-muted-foreground">Type:</span>{' '}
<span className="font-medium">{getSubmissionTypeLabel(item.submission_type)}</span>
<span className="font-medium">{getSubmissionTypeLabel(item.submission_type || 'unknown')}</span>
</div>
{item.submission_items && item.submission_items.length > 0 && (
<div>

View File

@@ -83,11 +83,11 @@ export const RecentActivity = forwardRef<RecentActivityRef>((props, ref) => {
if (reviewsError) throw reviewsError;
// Get unique moderator IDs
const moderatorIds = [
...(submissions?.map(s => s.reviewer_id).filter(Boolean) || []),
...(reports?.map(r => r.reviewed_by).filter(Boolean) || []),
...(reviews?.map(r => r.moderated_by).filter(Boolean) || []),
].filter((id, index, arr) => id && arr.indexOf(id) === index);
const moderatorIds: string[] = [
...(submissions?.map(s => s.reviewer_id).filter((id): id is string => id != null) || []),
...(reports?.map(r => r.reviewed_by).filter((id): id is string => id != null) || []),
...(reviews?.map(r => r.moderated_by).filter((id): id is string => id != null) || []),
].filter((id, index, arr) => arr.indexOf(id) === index);
// Fetch moderator profiles
const { data: profiles } = await supabase

View File

@@ -61,7 +61,7 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
}
setItems((itemsData || []) as SubmissionItemData[]);
setHasPhotos(photoData && photoData.length > 0);
setHasPhotos(!!(photoData && photoData.length > 0));
} catch (err) {
logger.error('Failed to fetch submission items', { error: getErrorMessage(err) });
setError('Failed to load submission details');

View File

@@ -634,7 +634,10 @@ export function SubmissionReviewManager({
<ConflictResolutionModal
open={showConflictResolutionModal}
onOpenChange={setShowConflictResolutionModal}
conflictData={conflictData}
conflictData={conflictData || {
hasConflict: false,
clientVersion: { last_modified_at: new Date().toISOString() }
}}
onResolve={async (strategy) => {
if (strategy === 'keep-mine') {
// Log conflict resolution

View File

@@ -30,7 +30,7 @@ export const EntitySubmissionDisplay = memo(({ item, isMobile }: EntitySubmissio
<div className="text-sm space-y-2">
<div>
<span className="text-muted-foreground">Type:</span>{' '}
<span className="font-medium">{getSubmissionTypeLabel(item.submission_type)}</span>
<span className="font-medium">{getSubmissionTypeLabel(item.submission_type || 'unknown')}</span>
</div>
{item.submission_items && item.submission_items.length > 0 && (
<div>

View File

@@ -54,7 +54,7 @@ export const PhotoSubmissionDisplay = memo(({
title: photo.title,
date_taken: photo.date_taken,
}))}
onPhotoClick={onOpenPhotos}
onPhotoClick={(photos, index) => onOpenPhotos(photos as any, index)}
/>
</div>
) : (

View File

@@ -52,7 +52,7 @@ export const ReviewDisplay = memo(({ item, isMobile, onOpenPhotos }: ReviewDispl
<div className="text-sm font-medium mb-2">Attached Photos:</div>
<PhotoGrid
photos={reviewPhotos}
onPhotoClick={onOpenPhotos}
onPhotoClick={(photos, index) => onOpenPhotos(photos as any, index)}
maxDisplay={isMobile ? 3 : 4}
className="grid-cols-2 md:grid-cols-3"
/>

View File

@@ -36,7 +36,7 @@ export function NotificationCenter() {
>
<Inbox
applicationIdentifier={applicationIdentifier}
subscriberId={subscriberId}
subscriber={subscriberId || ''}
appearance={appearance}
onNotificationClick={handleNotificationClick}
/>

View File

@@ -30,7 +30,7 @@ const OperatorCard = ({ company }: OperatorCardProps) => {
<div className="aspect-[3/2] relative bg-gradient-to-br from-primary/20 via-primary/10 to-transparent overflow-hidden">
{(company.card_image_url || company.card_image_id) ? (
<img
src={company.card_image_url || getCloudflareImageUrl(company.card_image_id, 'card')}
src={company.card_image_url || getCloudflareImageUrl(company.card_image_id || '', 'card')}
srcSet={company.card_image_id ? `
${getCloudflareImageUrl(company.card_image_id, 'cardthumb')} 600w,
${getCloudflareImageUrl(company.card_image_id, 'card')} 1200w
@@ -111,11 +111,11 @@ const OperatorCard = ({ company }: OperatorCardProps) => {
)}
</div>
{company.average_rating > 0 && (
{company.average_rating != null && company.average_rating > 0 && (
<div className="inline-flex items-center gap-1">
<Star className="w-4 h-4 fill-yellow-500 text-yellow-500" />
<span className="font-semibold">{company.average_rating.toFixed(1)}</span>
{company.review_count > 0 && (
{company.review_count != null && company.review_count > 0 && (
<span className="text-muted-foreground">({company.review_count})</span>
)}
</div>

View File

@@ -30,7 +30,7 @@ const ParkOwnerCard = ({ company }: ParkOwnerCardProps) => {
<div className="aspect-[3/2] relative bg-gradient-to-br from-primary/20 via-primary/10 to-transparent overflow-hidden">
{(company.card_image_url || company.card_image_id) ? (
<img
src={company.card_image_url || getCloudflareImageUrl(company.card_image_id, 'card')}
src={company.card_image_url || getCloudflareImageUrl(company.card_image_id || '', 'card')}
srcSet={company.card_image_id ? `
${getCloudflareImageUrl(company.card_image_id, 'cardthumb')} 600w,
${getCloudflareImageUrl(company.card_image_id, 'card')} 1200w
@@ -111,11 +111,11 @@ const ParkOwnerCard = ({ company }: ParkOwnerCardProps) => {
)}
</div>
{company.average_rating > 0 && (
{company.average_rating != null && company.average_rating > 0 && (
<div className="inline-flex items-center gap-1">
<Star className="w-4 h-4 fill-yellow-500 text-yellow-500" />
<span className="font-semibold">{company.average_rating.toFixed(1)}</span>
{company.review_count > 0 && (
{company.review_count != null && company.review_count > 0 && (
<span className="text-muted-foreground">({company.review_count})</span>
)}
</div>