diff --git a/src/components/admin/NovuMigrationUtility.tsx b/src/components/admin/NovuMigrationUtility.tsx index 7f7ea2b5..733a4392 100644 --- a/src/components/admin/NovuMigrationUtility.tsx +++ b/src/components/admin/NovuMigrationUtility.tsx @@ -6,6 +6,7 @@ import { Progress } from '@/components/ui/progress'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { CheckCircle2, XCircle, AlertCircle, Loader2 } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; interface MigrationResult { userId: string; @@ -71,11 +72,12 @@ export function NovuMigrationUtility() { title: "Migration completed", description: `Successfully migrated ${successCount} users. ${failureCount} failures.`, }); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ variant: "destructive", title: "Migration failed", - description: error.message, + description: errorMsg, }); } finally { setIsRunning(false); diff --git a/src/components/manufacturers/ManufacturerCard.tsx b/src/components/manufacturers/ManufacturerCard.tsx index 04b1518d..76da2c85 100644 --- a/src/components/manufacturers/ManufacturerCard.tsx +++ b/src/components/manufacturers/ManufacturerCard.tsx @@ -66,10 +66,10 @@ export function ManufacturerCard({ company }: ManufacturerCardProps) { {/* Logo Display */}
- {(company.logo_url || (company as any).logo_image_id) ? ( + {company.logo_url ? (
{`${company.name}(null); - const [activeTab, setActiveTab] = useState<'items' | 'dependencies'>('items' as const); + const [activeTab, setActiveTab] = useState<'items' | 'dependencies'>('items'); const [submissionType, setSubmissionType] = useState('submission'); const [showValidationBlockerDialog, setShowValidationBlockerDialog] = useState(false); const [showWarningConfirmDialog, setShowWarningConfirmDialog] = useState(false); diff --git a/src/components/moderation/ValidationSummary.tsx b/src/components/moderation/ValidationSummary.tsx index a3bf3c8e..637a2e2c 100644 --- a/src/components/moderation/ValidationSummary.tsx +++ b/src/components/moderation/ValidationSummary.tsx @@ -30,8 +30,24 @@ export function ValidationSummary({ item, onValidationChange, compact = false }: async function validate() { setIsLoading(true); try { + // Type guard for valid entity types + type ValidEntityType = 'park' | 'ride' | 'manufacturer' | 'operator' | 'designer' | 'property_owner' | 'ride_model' | 'photo'; + const validEntityTypes: ValidEntityType[] = ['park', 'ride', 'manufacturer', 'operator', 'designer', 'property_owner', 'ride_model', 'photo']; + + if (!validEntityTypes.includes(item.item_type as ValidEntityType)) { + setValidationResult({ + isValid: false, + blockingErrors: [{ field: 'item_type', message: `Invalid entity type: ${item.item_type}`, severity: 'blocking' }], + warnings: [], + suggestions: [], + allErrors: [{ field: 'item_type', message: `Invalid entity type: ${item.item_type}`, severity: 'blocking' }], + }); + setIsLoading(false); + return; + } + const result = await validateEntityData( - item.item_type as any, + item.item_type as ValidEntityType, { ...item.item_data, id: item.id } ); diff --git a/src/hooks/moderation/useModerationQueueManager.ts b/src/hooks/moderation/useModerationQueueManager.ts index 6a645eb3..20818cf8 100644 --- a/src/hooks/moderation/useModerationQueueManager.ts +++ b/src/hooks/moderation/useModerationQueueManager.ts @@ -2,6 +2,7 @@ import { useState, useCallback, useRef, useEffect, useMemo } from "react"; import { supabase } from "@/integrations/supabase/client"; import { useToast } from "@/hooks/use-toast"; import { logger } from "@/lib/logger"; +import { getErrorMessage } from "@/lib/errorHandler"; import { MODERATION_CONSTANTS } from "@/lib/moderation/constants"; import type { User } from "@supabase/supabase-js"; import { @@ -375,10 +376,11 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig): description: `The ${item.type} has been ${action}. Version history updated.`, }); - // Refresh stats to update counts - queue.refreshStats(); - } catch (error: any) { - console.error("Error moderating content:", error); + // Refresh stats to update counts + queue.refreshStats(); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error("Error moderating content:", errorMsg); // Revert optimistic update setItems((prev) => { @@ -392,7 +394,7 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig): toast({ title: "Error", - description: error.message || `Failed to ${action} content`, + description: errorMsg || `Failed to ${action} content`, variant: "destructive", }); } finally { @@ -425,8 +427,9 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig): // Refresh stats to update counts queue.refreshStats(); - } catch (error: any) { - console.error("Error deleting submission:", error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error("Error deleting submission:", errorMsg); setItems((prev) => { if (prev.some((i) => i.id === item.id)) return prev; @@ -465,11 +468,12 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig): queue.refreshStats(); setItems((prev) => prev.filter((i) => i.id !== item.id)); - } catch (error: any) { - console.error("Error resetting submission:", error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error("Error resetting submission:", errorMsg); toast({ title: "Reset Failed", - description: error.message, + description: errorMsg, variant: "destructive", }); } finally { @@ -528,11 +532,12 @@ export function useModerationQueueManager(config: ModerationQueueManagerConfig): // Refresh stats to update counts queue.refreshStats(); - } catch (error: any) { - console.error("Error retrying failed items:", error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error("Error retrying failed items:", errorMsg); toast({ title: "Retry Failed", - description: error.message, + description: errorMsg, variant: "destructive", }); } finally { diff --git a/src/hooks/useUnitPreferences.ts b/src/hooks/useUnitPreferences.ts index a2bbbc8d..b3453206 100644 --- a/src/hooks/useUnitPreferences.ts +++ b/src/hooks/useUnitPreferences.ts @@ -11,7 +11,7 @@ function isValidUnitPreferences(obj: unknown): obj is UnitPreferences { typeof obj === 'object' && obj !== null && 'measurement_system' in obj && - ['metric', 'imperial'].includes((obj as any).measurement_system) + (obj.measurement_system === 'metric' || obj.measurement_system === 'imperial') ); } diff --git a/src/lib/moderation/realtime.ts b/src/lib/moderation/realtime.ts index 07854ae8..d766dc99 100644 --- a/src/lib/moderation/realtime.ts +++ b/src/lib/moderation/realtime.ts @@ -6,6 +6,11 @@ import type { ModerationItem, EntityFilter, StatusFilter } from '@/types/moderation'; +interface SubmissionContent { + name?: string; + [key: string]: any; +} + /** * Check if a submission matches the entity filter */ @@ -167,7 +172,7 @@ export function buildModerationItem( display_name: profile.display_name, avatar_url: profile.avatar_url, } : undefined, - entity_name: entityName || (submission.content as any)?.name || 'Unknown', + entity_name: entityName || (submission.content as SubmissionContent)?.name || 'Unknown', park_name: parkName, reviewed_at: submission.reviewed_at || undefined, reviewer_notes: submission.reviewer_notes || undefined, diff --git a/src/lib/submissionItemsService.ts b/src/lib/submissionItemsService.ts index 872132ba..9833c816 100644 --- a/src/lib/submissionItemsService.ts +++ b/src/lib/submissionItemsService.ts @@ -609,8 +609,16 @@ async function createCompany( // Extract image assignments const imageData = extractImageAssignments(resolvedData.images); + // Type guard for company type + type ValidCompanyType = 'manufacturer' | 'designer' | 'operator' | 'property_owner'; + const validCompanyTypes: ValidCompanyType[] = ['manufacturer', 'designer', 'operator', 'property_owner']; + + if (!validCompanyTypes.includes(companyType as ValidCompanyType)) { + throw new Error(`Invalid company type: ${companyType}`); + } + // Transform to database format - const companyData = { ...transformCompanyData(resolvedData, companyType as any), ...imageData }; + const companyData = { ...transformCompanyData(resolvedData, companyType as ValidCompanyType), ...imageData }; const { data: company, error } = await supabase .from('companies') @@ -1062,12 +1070,18 @@ export async function editSubmissionItem( } } + // Type guard for submission with user_id + interface SubmissionWithUser { + user_id: string; + [key: string]: any; + } + // Log admin action await supabase .from('admin_audit_log') .insert({ admin_user_id: userId, - target_user_id: (currentItem.submission as any).user_id, + target_user_id: (currentItem.submission as SubmissionWithUser).user_id, action: 'edit_submission_item', details: { item_id: itemId, diff --git a/src/pages/PropertyOwnerDetail.tsx b/src/pages/PropertyOwnerDetail.tsx index e276512c..2e68408b 100644 --- a/src/pages/PropertyOwnerDetail.tsx +++ b/src/pages/PropertyOwnerDetail.tsx @@ -17,6 +17,7 @@ import { ParkCard } from '@/components/parks/ParkCard'; import { useAuth } from '@/hooks/useAuth'; import { useUserRole } from '@/hooks/useUserRole'; import { toast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; import { submitCompanyUpdate } from '@/lib/companyHelpers'; import { VersionIndicator } from '@/components/versioning/VersionIndicator'; import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs'; @@ -154,10 +155,11 @@ export default function PropertyOwnerDetail() { }); setIsEditModalOpen(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to submit edit.", + description: errorMsg || "Failed to submit edit.", variant: "destructive" }); } diff --git a/src/pages/RideDetail.tsx b/src/pages/RideDetail.tsx index 126c1d6a..620e147e 100644 --- a/src/pages/RideDetail.tsx +++ b/src/pages/RideDetail.tsx @@ -45,6 +45,7 @@ import { RideForm } from '@/components/admin/RideForm'; import { useAuth } from '@/hooks/useAuth'; import { useUserRole } from '@/hooks/useUserRole'; import { toast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; import { VersionIndicator } from '@/components/versioning/VersionIndicator'; import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs'; import { useAuthModal } from '@/hooks/useAuthModal'; @@ -183,10 +184,11 @@ export default function RideDetail() { }); setIsEditModalOpen(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to submit edit.", + description: errorMsg || "Failed to submit edit.", variant: "destructive" }); } diff --git a/src/pages/RideModelDetail.tsx b/src/pages/RideModelDetail.tsx index 04ea3def..ff89fb36 100644 --- a/src/pages/RideModelDetail.tsx +++ b/src/pages/RideModelDetail.tsx @@ -14,6 +14,7 @@ import { getCloudflareImageUrl } from '@/lib/cloudflareImageUtils'; import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuth } from '@/hooks/useAuth'; import { toast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; import { RideModelForm } from '@/components/admin/RideModelForm'; import { ManufacturerPhotoGallery } from '@/components/companies/ManufacturerPhotoGallery'; import { VersionIndicator } from '@/components/versioning/VersionIndicator'; @@ -120,10 +121,11 @@ export default function RideModelDetail() { setIsEditModalOpen(false); fetchData(); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to update ride model.", + description: errorMsg || "Failed to update ride model.", variant: "destructive" }); } diff --git a/src/pages/RideModelRides.tsx b/src/pages/RideModelRides.tsx index 033bbc1c..e5a3ff3d 100644 --- a/src/pages/RideModelRides.tsx +++ b/src/pages/RideModelRides.tsx @@ -14,6 +14,7 @@ import { RideForm } from '@/components/admin/RideForm'; import { useAuth } from '@/hooks/useAuth'; import { useAuthModal } from '@/hooks/useAuthModal'; import { toast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; import type { Ride, Company, RideModel } from "@/types/database"; export default function RideModelRides() { @@ -142,10 +143,11 @@ export default function RideModelRides() { setIsCreateModalOpen(false); fetchData(); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to submit ride.", + description: errorMsg || "Failed to submit ride.", variant: "destructive" }); } diff --git a/src/pages/Rides.tsx b/src/pages/Rides.tsx index 2f2f7671..1db6ba58 100644 --- a/src/pages/Rides.tsx +++ b/src/pages/Rides.tsx @@ -14,6 +14,7 @@ import { supabase } from '@/integrations/supabase/client'; import { useAuth } from '@/hooks/useAuth'; import { useUserRole } from '@/hooks/useUserRole'; import { toast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; import { useAuthModal } from '@/hooks/useAuthModal'; export default function Rides() { @@ -89,10 +90,11 @@ export default function Rides() { }); setIsCreateModalOpen(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Submission Failed", - description: error.message || "Failed to submit ride.", + description: errorMsg || "Failed to submit ride.", variant: "destructive" }); }