diff --git a/src/components/admin/ParkForm.tsx b/src/components/admin/ParkForm.tsx index d06ce6d9..0c3e0e22 100644 --- a/src/components/admin/ParkForm.tsx +++ b/src/components/admin/ParkForm.tsx @@ -15,6 +15,7 @@ import { DatePicker } from '@/components/ui/date-picker'; import { FlexibleDateInput, type DatePrecision } from '@/components/ui/flexible-date-input'; import { SlugField } from '@/components/ui/slug-field'; import { toast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; import { MapPin, Save, X, Plus } from 'lucide-react'; import { toDateOnly } from '@/lib/dateUtils'; import { Badge } from '@/components/ui/badge'; @@ -192,10 +193,11 @@ export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }: ? "The park information has been updated successfully." : "The new park has been created successfully." }); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to save park information.", + description: errorMsg, variant: "destructive" }); } finally { diff --git a/src/components/admin/RideForm.tsx b/src/components/admin/RideForm.tsx index 52b16a18..c83adf3b 100644 --- a/src/components/admin/RideForm.tsx +++ b/src/components/admin/RideForm.tsx @@ -20,6 +20,7 @@ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } f import { Combobox } from '@/components/ui/combobox'; import { SlugField } from '@/components/ui/slug-field'; import { toast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; import { Plus, Zap, Save, X } from 'lucide-react'; import { toDateOnly } from '@/lib/dateUtils'; import { useUnitPreferences } from '@/hooks/useUnitPreferences'; @@ -263,10 +264,11 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }: ? "Ride, manufacturer, and model submitted for review" : "Ride submitted for review" }); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to save ride information.", + description: errorMsg, variant: "destructive" }); } finally { diff --git a/src/components/auth/AuthButtons.tsx b/src/components/auth/AuthButtons.tsx index 07c69d01..23bb47d0 100644 --- a/src/components/auth/AuthButtons.tsx +++ b/src/components/auth/AuthButtons.tsx @@ -8,6 +8,7 @@ import { useAuth } from '@/hooks/useAuth'; import { useProfile } from '@/hooks/useProfile'; import { useToast } from '@/hooks/use-toast'; import { useAuthModal } from '@/hooks/useAuthModal'; +import { getErrorMessage } from '@/lib/errorHandler'; export function AuthButtons() { const { user, loading: authLoading, signOut } = useAuth(); @@ -25,11 +26,12 @@ export function AuthButtons() { description: "You've been signed out successfully." }); navigate('/'); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ variant: "destructive", title: "Error signing out", - description: error.message + description: errorMsg }); } finally { setLoggingOut(false); diff --git a/src/components/moderation/ConflictResolutionDialog.tsx b/src/components/moderation/ConflictResolutionDialog.tsx index 485922fe..130184be 100644 --- a/src/components/moderation/ConflictResolutionDialog.tsx +++ b/src/components/moderation/ConflictResolutionDialog.tsx @@ -8,6 +8,7 @@ import { AlertCircle } from 'lucide-react'; import { type DependencyConflict, type SubmissionItemWithDeps } from '@/lib/submissionItemsService'; import { useToast } from '@/hooks/use-toast'; import { useAuth } from '@/hooks/useAuth'; +import { getErrorMessage } from '@/lib/errorHandler'; interface ConflictResolutionDialogProps { open: boolean; @@ -67,10 +68,11 @@ export function ConflictResolutionDialog({ onResolve(); onOpenChange(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: 'Error', - description: error.message || 'Failed to resolve conflicts', + description: errorMsg, variant: 'destructive', }); } diff --git a/src/components/moderation/ItemEditDialog.tsx b/src/components/moderation/ItemEditDialog.tsx index d1f65dbf..4efdf5b0 100644 --- a/src/components/moderation/ItemEditDialog.tsx +++ b/src/components/moderation/ItemEditDialog.tsx @@ -8,6 +8,7 @@ import { Textarea } from '@/components/ui/textarea'; import { toast } from '@/hooks/use-toast'; import { useIsMobile } from '@/hooks/use-mobile'; import { useUserRole } from '@/hooks/useUserRole'; +import { getErrorMessage } from '@/lib/errorHandler'; import { useAuth } from '@/hooks/useAuth'; import { editSubmissionItem, type SubmissionItemWithDeps } from '@/lib/submissionItemsService'; import { ParkForm } from '@/components/admin/ParkForm'; @@ -58,10 +59,11 @@ export function ItemEditDialog({ item, open, onOpenChange, onComplete }: ItemEdi onComplete(); onOpenChange(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: 'Error', - description: error.message || 'Failed to save changes', + description: errorMsg, variant: 'destructive', }); } finally { diff --git a/src/components/moderation/PhotoSubmissionDisplay.tsx b/src/components/moderation/PhotoSubmissionDisplay.tsx index be1d872c..51bc8d91 100644 --- a/src/components/moderation/PhotoSubmissionDisplay.tsx +++ b/src/components/moderation/PhotoSubmissionDisplay.tsx @@ -3,6 +3,7 @@ import { supabase } from '@/integrations/supabase/client'; import { PhotoGrid } from '@/components/common/PhotoGrid'; import type { PhotoSubmissionItem } from '@/types/photo-submissions'; import type { PhotoItem } from '@/types/photos'; +import { getErrorMessage } from '@/lib/errorHandler'; interface PhotoSubmissionDisplayProps { submissionId: string; @@ -81,10 +82,11 @@ export function PhotoSubmissionDisplay({ submissionId }: PhotoSubmissionDisplayP setPhotos(data || []); console.log(`✅ Successfully loaded ${data?.length || 0} photos`); - } catch (error: any) { - console.error('❌ PhotoSubmissionDisplay error:', error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error('❌ PhotoSubmissionDisplay error:', errorMsg); setPhotos([]); - setError(error.message || 'Failed to load photos'); + setError(errorMsg); } finally { setLoading(false); } diff --git a/src/components/moderation/ReassignDialog.tsx b/src/components/moderation/ReassignDialog.tsx index 6375ae2a..cb0c2548 100644 --- a/src/components/moderation/ReassignDialog.tsx +++ b/src/components/moderation/ReassignDialog.tsx @@ -19,6 +19,7 @@ import { } from '@/components/ui/select'; import { supabase } from '@/integrations/supabase/client'; import { useToast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; interface Moderator { user_id: string; @@ -87,8 +88,9 @@ export function ReassignDialog({ }); setModerators(moderatorsList); - } catch (error: any) { - console.error('Error fetching moderators:', error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error('Error fetching moderators:', errorMsg); toast({ title: 'Error', description: 'Failed to load moderators list', diff --git a/src/components/moderation/RecentActivity.tsx b/src/components/moderation/RecentActivity.tsx index 9b6a91de..e2e69fa3 100644 --- a/src/components/moderation/RecentActivity.tsx +++ b/src/components/moderation/RecentActivity.tsx @@ -2,6 +2,7 @@ import { useState, useEffect, forwardRef, useImperativeHandle } from 'react'; import { supabase } from '@/integrations/supabase/client'; import { useAuth } from '@/hooks/useAuth'; import { useToast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; import { ActivityCard } from './ActivityCard'; import { Skeleton } from '@/components/ui/skeleton'; import { Activity as ActivityIcon } from 'lucide-react'; @@ -150,8 +151,9 @@ export const RecentActivity = forwardRef((props, ref) => { // Full replacement for non-silent refreshes or 'replace' strategy setActivities(recentActivities); } - } catch (error: any) { - console.error('Error fetching recent activity:', error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error('Error fetching recent activity:', errorMsg); toast({ title: "Error", description: "Failed to load recent activity", diff --git a/src/components/profile/UserBlockButton.tsx b/src/components/profile/UserBlockButton.tsx index 5c78b21c..ffd6ccfc 100644 --- a/src/components/profile/UserBlockButton.tsx +++ b/src/components/profile/UserBlockButton.tsx @@ -7,6 +7,7 @@ import { UserX } from 'lucide-react'; import { supabase } from '@/integrations/supabase/client'; import { useAuth } from '@/hooks/useAuth'; import { useToast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; interface UserBlockButtonProps { targetUserId: string; @@ -42,8 +43,9 @@ export function UserBlockButton({ targetUserId, targetUsername, variant = 'outli }); setReason(''); - } catch (error: any) { - console.error('Error blocking user:', error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error('Error blocking user:', errorMsg); toast({ title: 'Error', description: 'Failed to block user', diff --git a/src/components/settings/DeletionStatusBanner.tsx b/src/components/settings/DeletionStatusBanner.tsx index 4c594b8a..46898d19 100644 --- a/src/components/settings/DeletionStatusBanner.tsx +++ b/src/components/settings/DeletionStatusBanner.tsx @@ -4,6 +4,7 @@ import { supabase } from '@/integrations/supabase/client'; import { useToast } from '@/hooks/use-toast'; import { AlertTriangle, Loader2 } from 'lucide-react'; import { useState } from 'react'; +import { getErrorMessage } from '@/lib/errorHandler'; interface DeletionStatusBannerProps { scheduledDate: string; @@ -37,11 +38,12 @@ export function DeletionStatusBanner({ scheduledDate, onCancelled }: DeletionSta }); onCancelled(); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ variant: 'destructive', title: 'Error', - description: error.message || 'Failed to cancel deletion', + description: errorMsg, }); } finally { setLoading(false); diff --git a/src/components/settings/EmailChangeDialog.tsx b/src/components/settings/EmailChangeDialog.tsx index ffa45095..178446b4 100644 --- a/src/components/settings/EmailChangeDialog.tsx +++ b/src/components/settings/EmailChangeDialog.tsx @@ -20,7 +20,7 @@ import { } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; -import { handleError, handleSuccess, AppError } from '@/lib/errorHandler'; +import { handleError, handleSuccess, AppError, getErrorMessage } from '@/lib/errorHandler'; import { logger } from '@/lib/logger'; import { supabase } from '@/integrations/supabase/client'; import { Loader2, Mail, CheckCircle2, AlertCircle } from 'lucide-react'; @@ -185,13 +185,12 @@ export function EmailChangeDialog({ open, onOpenChange, currentEmail, userId }: ); setStep('success'); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); logger.error('Email change failed', { userId, action: 'email_change', - error: error instanceof Error ? error.message : String(error), - errorCode: error.code, - errorStatus: error.status + error: errorMsg, }); if (error.message?.includes('rate limit') || error.status === 429) { diff --git a/src/components/timeline/EntityTimelineManager.tsx b/src/components/timeline/EntityTimelineManager.tsx index 058e01ad..0b124acb 100644 --- a/src/components/timeline/EntityTimelineManager.tsx +++ b/src/components/timeline/EntityTimelineManager.tsx @@ -9,6 +9,7 @@ import { useQuery } from '@tanstack/react-query'; import { supabase } from '@/integrations/supabase/client'; import { useAuth } from '@/hooks/useAuth'; import { toast } from 'sonner'; +import { getErrorMessage } from '@/lib/errorHandler'; import { deleteTimelineEvent } from '@/lib/entitySubmissionHelpers'; import type { EntityType, TimelineEvent } from '@/types/timeline'; @@ -113,10 +114,11 @@ export function EntityTimelineManager({ toast.success('Event deleted', { description: 'Your timeline event has been deleted successfully.' }); - } catch (error: any) { - console.error('Delete error:', error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error('Delete error:', errorMsg); toast.error('Failed to delete event', { - description: error.message || 'Please try again.' + description: errorMsg }); } }; diff --git a/src/components/timeline/TimelineEventEditorDialog.tsx b/src/components/timeline/TimelineEventEditorDialog.tsx index 1f97317a..8ac8f992 100644 --- a/src/components/timeline/TimelineEventEditorDialog.tsx +++ b/src/components/timeline/TimelineEventEditorDialog.tsx @@ -46,6 +46,7 @@ import { Loader2, Trash } from 'lucide-react'; import { useAuth } from '@/hooks/useAuth'; import { useToast } from '@/hooks/use-toast'; import { submitTimelineEvent, submitTimelineEventUpdate, deleteTimelineEvent } from '@/lib/entitySubmissionHelpers'; +import { getErrorMessage } from '@/lib/errorHandler'; import type { EntityType, TimelineEventFormData, @@ -195,11 +196,12 @@ export function TimelineEventEditorDialog({ onOpenChange(false); setShowDeleteConfirm(false); form.reset(); - } catch (error: any) { - console.error('Delete error:', error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error('Delete error:', errorMsg); toast({ title: 'Failed to delete event', - description: error.message || 'Please try again.', + description: errorMsg, variant: 'destructive', }); } finally { diff --git a/src/components/upload/PhotoUpload.tsx b/src/components/upload/PhotoUpload.tsx index c0dc44a3..c6d2a369 100644 --- a/src/components/upload/PhotoUpload.tsx +++ b/src/components/upload/PhotoUpload.tsx @@ -13,6 +13,7 @@ import { FileImage } from 'lucide-react'; import { cn } from '@/lib/utils'; +import { getErrorMessage } from '@/lib/errorHandler'; import { supabase } from '@/integrations/supabase/client'; interface PhotoUploadProps { @@ -266,11 +267,11 @@ export function PhotoUpload({ } setUploadProgress(100); - } catch (error: any) { + } catch (error) { previewUrls.forEach(url => revokeObjectUrl(url)); - const errorMessage = error.message || 'Upload failed'; - setError(errorMessage); - onError?.(errorMessage); + const errorMsg = getErrorMessage(error); + setError(errorMsg); + onError?.(errorMsg); } finally { setUploading(false); setUploadProgress(0); diff --git a/src/lib/conflictResolutionService.ts b/src/lib/conflictResolutionService.ts index 975f55d9..0ce30483 100644 --- a/src/lib/conflictResolutionService.ts +++ b/src/lib/conflictResolutionService.ts @@ -1,4 +1,4 @@ -import { supabase } from '@/integrations/supabase/client'; +import { getErrorMessage } from '@/lib/errorHandler'; import { updateSubmissionItem, type SubmissionItemWithDeps, type DependencyConflict } from './submissionItemsService'; export interface ResolutionResult { @@ -83,11 +83,12 @@ export async function resolveConflicts( success: true, updatedSelections, }; - } catch (error: any) { - console.error('Conflict resolution error:', error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error('Conflict resolution error:', errorMsg); return { success: false, - error: error.message || 'Failed to resolve conflicts', + error: errorMsg, }; } } diff --git a/src/lib/entityValidationSchemas.ts b/src/lib/entityValidationSchemas.ts index 96808e18..ad241c28 100644 --- a/src/lib/entityValidationSchemas.ts +++ b/src/lib/entityValidationSchemas.ts @@ -346,40 +346,29 @@ async function checkSlugUniqueness( try { console.log(`Checking slug uniqueness for "${slug}" in ${tableName}, excludeId: ${excludeId}`); - // Type-safe queries for each table - type ValidTableName = 'parks' | 'rides' | 'companies' | 'ride_models' | 'photos'; + // Query with explicit table name - use simple approach to avoid type instantiation issues + let result; - // Validate table name - const validTables: ValidTableName[] = ['parks', 'rides', 'companies', 'ride_models', 'photos']; - if (!validTables.includes(tableName as ValidTableName)) { - console.error(`Invalid table name: ${tableName}`); - return true; // Assume unique on invalid table - } - - // Query with explicit table name - let data, error; - if (tableName === 'parks') { - const result = await supabase.from('parks').select('id').eq('slug', slug).limit(1); - data = result.data; - error = result.error; - } else if (tableName === 'rides') { - const result = await supabase.from('rides').select('id').eq('slug', slug).limit(1); - data = result.data; - error = result.error; - } else if (tableName === 'companies') { - const result = await supabase.from('companies').select('id').eq('slug', slug).limit(1); - data = result.data; - error = result.error; - } else if (tableName === 'ride_models') { - const result = await supabase.from('ride_models').select('id').eq('slug', slug).limit(1); - data = result.data; - error = result.error; - } else { - const result = await supabase.from('photos').select('id').eq('slug', slug).limit(1); - data = result.data; - error = result.error; + switch (tableName) { + case 'parks': + result = await supabase.from('parks').select('id').eq('slug', slug).limit(1); + break; + case 'rides': + result = await supabase.from('rides').select('id').eq('slug', slug).limit(1); + break; + case 'companies': + result = await supabase.from('companies').select('id').eq('slug', slug).limit(1); + break; + case 'ride_models': + result = await supabase.from('ride_models').select('id').eq('slug', slug).limit(1); + break; + default: + console.error(`Invalid table name: ${tableName}`); + return true; // Assume unique on invalid table } + const { data, error } = result; + if (error) { console.error(`Slug uniqueness check failed for ${entityType}:`, error); return true; // Assume unique on error to avoid blocking diff --git a/src/lib/identityService.ts b/src/lib/identityService.ts index 6211659a..b4e56cf9 100644 --- a/src/lib/identityService.ts +++ b/src/lib/identityService.ts @@ -23,10 +23,11 @@ export async function getUserIdentities(): Promise { if (error) throw error; return (data?.identities || []) as UserIdentity[]; - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); logger.error('Failed to get user identities', { action: 'get_identities', - error: error.message + error: errorMsg }); return []; } @@ -127,15 +128,16 @@ export async function disconnectIdentity( } return { success: true }; - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); logger.error('Failed to disconnect identity', { action: 'identity_disconnect', provider, - error: error.message + error: errorMsg }); return { success: false, - error: error.message || 'Failed to disconnect identity' + error: errorMsg }; } } @@ -159,15 +161,16 @@ export async function connectIdentity( if (error) throw error; return { success: true }; - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); logger.error('Failed to connect identity', { action: 'identity_connect', provider, - error: error.message + error: errorMsg }); return { success: false, - error: error.message || `Failed to connect ${provider} account` + error: errorMsg }; } } @@ -229,14 +232,15 @@ export async function addPasswordToAccount(): Promise { needsEmailConfirmation: true, email: userEmail }; - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); logger.error('Failed to initiate password setup', { action: 'password_setup', - error: error.message + error: errorMsg }); return { success: false, - error: error.message || 'Failed to send password reset email' + error: errorMsg }; } } diff --git a/src/lib/submissionItemsService.ts b/src/lib/submissionItemsService.ts index e4530121..481b47fb 100644 --- a/src/lib/submissionItemsService.ts +++ b/src/lib/submissionItemsService.ts @@ -224,16 +224,17 @@ export async function approveSubmissionItems( // Add to dependency map for child items dependencyMap.set(item.id, entityId); - } catch (error: any) { - console.error(`Error approving ${item.item_type} item ${item.id}:`, error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error(`Error approving ${item.item_type} item ${item.id}:`, errorMsg); // Update item with error status await updateSubmissionItem(item.id, { status: 'rejected', - rejection_reason: `Failed to create entity: ${error.message}`, + rejection_reason: `Failed to create entity: ${errorMsg}`, }); - throw new Error(`Failed to approve ${item.item_type}: ${error.message}`); + throw new Error(`Failed to approve ${item.item_type}: ${errorMsg}`); } } } diff --git a/src/pages/AuthCallback.tsx b/src/pages/AuthCallback.tsx index 4723475e..1ebbf5cd 100644 --- a/src/pages/AuthCallback.tsx +++ b/src/pages/AuthCallback.tsx @@ -10,6 +10,7 @@ import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/com import { Label } from '@/components/ui/label'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; +import { getErrorMessage } from '@/lib/errorHandler'; export default function AuthCallback() { const navigate = useNavigate(); @@ -124,14 +125,15 @@ export default function AuthCallback() { navigate('/'); }, 500); - } catch (error: any) { - console.error('[AuthCallback] Error:', error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error('[AuthCallback] Error:', errorMsg); setStatus('error'); toast({ variant: 'destructive', title: 'Sign in error', - description: error.message || 'An error occurred during sign in. Please try again.', + description: errorMsg, }); // Redirect to auth page after error @@ -183,12 +185,13 @@ export default function AuthCallback() { navigate('/auth'); }, 1500); - } catch (error: any) { - console.error('[AuthCallback] Password reset error:', error); + } catch (error) { + const errorMsg = getErrorMessage(error); + console.error('[AuthCallback] Password reset error:', errorMsg); toast({ variant: 'destructive', title: 'Failed to set password', - description: error.message || 'Please try again.', + description: errorMsg, }); setSettingPassword(false); } diff --git a/src/pages/DesignerDetail.tsx b/src/pages/DesignerDetail.tsx index ee8e55ea..99ad467a 100644 --- a/src/pages/DesignerDetail.tsx +++ b/src/pages/DesignerDetail.tsx @@ -15,6 +15,7 @@ import { DesignerPhotoGallery } from '@/components/companies/DesignerPhotoGaller 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'; @@ -109,10 +110,11 @@ export default function DesignerDetail() { }); setIsEditModalOpen(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to submit edit.", + description: errorMsg, variant: "destructive" }); } diff --git a/src/pages/Designers.tsx b/src/pages/Designers.tsx index bed717b8..9835983c 100644 --- a/src/pages/Designers.tsx +++ b/src/pages/Designers.tsx @@ -16,6 +16,7 @@ import { useUserRole } from '@/hooks/useUserRole'; import { toast } from '@/hooks/use-toast'; import { submitCompanyCreation } from '@/lib/companyHelpers'; import { useAuthModal } from '@/hooks/useAuthModal'; +import { getErrorMessage } from '@/lib/errorHandler'; export default function Designers() { const navigate = useNavigate(); @@ -36,8 +37,9 @@ export default function Designers() { description: "Your submission has been sent for review." }); setIsCreateModalOpen(false); - } catch (error: any) { - toast({ title: "Error", description: error.message || "Failed to submit designer.", variant: "destructive" }); + } catch (error) { + const errorMsg = getErrorMessage(error); + toast({ title: "Error", description: errorMsg, variant: "destructive" }); } }; diff --git a/src/pages/ManufacturerDetail.tsx b/src/pages/ManufacturerDetail.tsx index 9b8c9939..9b2bded3 100644 --- a/src/pages/ManufacturerDetail.tsx +++ b/src/pages/ManufacturerDetail.tsx @@ -16,6 +16,7 @@ import { ManufacturerPhotoGallery } from '@/components/companies/ManufacturerPho 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'; @@ -119,10 +120,11 @@ export default function ManufacturerDetail() { }); setIsEditModalOpen(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to submit edit.", + description: errorMsg, variant: "destructive" }); } diff --git a/src/pages/Manufacturers.tsx b/src/pages/Manufacturers.tsx index 53e451b9..49a7bc9e 100644 --- a/src/pages/Manufacturers.tsx +++ b/src/pages/Manufacturers.tsx @@ -16,6 +16,7 @@ import { useUserRole } from '@/hooks/useUserRole'; import { toast } from '@/hooks/use-toast'; import { submitCompanyCreation } from '@/lib/companyHelpers'; import { useAuthModal } from '@/hooks/useAuthModal'; +import { getErrorMessage } from '@/lib/errorHandler'; export default function Manufacturers() { const navigate = useNavigate(); @@ -80,10 +81,11 @@ export default function Manufacturers() { }); setIsCreateModalOpen(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to submit manufacturer.", + description: errorMsg, variant: "destructive" }); } diff --git a/src/pages/OperatorDetail.tsx b/src/pages/OperatorDetail.tsx index f8995008..e289e314 100644 --- a/src/pages/OperatorDetail.tsx +++ b/src/pages/OperatorDetail.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 OperatorDetail() { }); setIsEditModalOpen(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to submit edit.", + description: errorMsg, variant: "destructive" }); } diff --git a/src/pages/Operators.tsx b/src/pages/Operators.tsx index 726e6b07..fcb40932 100644 --- a/src/pages/Operators.tsx +++ b/src/pages/Operators.tsx @@ -17,6 +17,7 @@ import { useUserRole } from '@/hooks/useUserRole'; import { toast } from '@/hooks/use-toast'; import { submitCompanyCreation } from '@/lib/companyHelpers'; import { useAuthModal } from '@/hooks/useAuthModal'; +import { getErrorMessage } from '@/lib/errorHandler'; const Operators = () => { const navigate = useNavigate(); @@ -73,10 +74,11 @@ const Operators = () => { }); setIsCreateModalOpen(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to submit operator.", + description: errorMsg, variant: "destructive" }); } diff --git a/src/pages/ParkDetail.tsx b/src/pages/ParkDetail.tsx index 75229d05..3afdddb2 100644 --- a/src/pages/ParkDetail.tsx +++ b/src/pages/ParkDetail.tsx @@ -20,6 +20,7 @@ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } f import { RideForm } from '@/components/admin/RideForm'; import { ParkForm } from '@/components/admin/ParkForm'; import { toast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; import { useUserRole } from '@/hooks/useUserRole'; import { Edit } from 'lucide-react'; import { VersionIndicator } from '@/components/versioning/VersionIndicator'; @@ -149,10 +150,11 @@ export default function ParkDetail() { }); setIsAddRideModalOpen(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Submission Failed", - description: error.message || "Failed to submit ride for review.", + description: errorMsg, variant: "destructive" }); } @@ -175,10 +177,11 @@ export default function ParkDetail() { }); setIsEditParkModalOpen(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to submit park edit.", + description: errorMsg, variant: "destructive" }); } diff --git a/src/pages/ParkOwners.tsx b/src/pages/ParkOwners.tsx index 57646e15..f31ea7c4 100644 --- a/src/pages/ParkOwners.tsx +++ b/src/pages/ParkOwners.tsx @@ -17,6 +17,7 @@ import { useUserRole } from '@/hooks/useUserRole'; import { toast } from '@/hooks/use-toast'; import { submitCompanyCreation } from '@/lib/companyHelpers'; import { useAuthModal } from '@/hooks/useAuthModal'; +import { getErrorMessage } from '@/lib/errorHandler'; const ParkOwners = () => { const navigate = useNavigate(); @@ -73,10 +74,11 @@ const ParkOwners = () => { }); setIsCreateModalOpen(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Error", - description: error.message || "Failed to submit property owner.", + description: errorMsg, variant: "destructive" }); } diff --git a/src/pages/ParkRides.tsx b/src/pages/ParkRides.tsx index 7f188cc5..14e1258c 100644 --- a/src/pages/ParkRides.tsx +++ b/src/pages/ParkRides.tsx @@ -14,6 +14,7 @@ import { RideSubmissionData } from '@/types/submission-data'; import { supabase } from '@/integrations/supabase/client'; import { useAuth } from '@/hooks/useAuth'; import { toast } from '@/hooks/use-toast'; +import { getErrorMessage } from '@/lib/errorHandler'; import { useAuthModal } from '@/hooks/useAuthModal'; export default function ParkRides() { @@ -130,10 +131,11 @@ export default function ParkRides() { }); setIsCreateModalOpen(false); - } catch (error: any) { + } catch (error) { + const errorMsg = getErrorMessage(error); toast({ title: "Submission Failed", - description: error.message || "Failed to submit ride.", + description: errorMsg, variant: "destructive" }); } diff --git a/supabase/migrations/20251017143529_5f0a665e-30c5-4fb9-8e58-935b13ad5171.sql b/supabase/migrations/20251017143529_5f0a665e-30c5-4fb9-8e58-935b13ad5171.sql new file mode 100644 index 00000000..7e4360f3 --- /dev/null +++ b/supabase/migrations/20251017143529_5f0a665e-30c5-4fb9-8e58-935b13ad5171.sql @@ -0,0 +1,27 @@ +-- Add check constraints to enforce metric-only units in statistics tables +-- This ensures data integrity and compliance with the custom knowledge requirement: +-- "Unit Conversion Rules: Storage: Always metric in DB (km/h, m, cm, kg)" + +-- Add constraint to ride_coaster_stats table +ALTER TABLE ride_coaster_stats +ADD CONSTRAINT ride_coaster_stats_metric_unit_check +CHECK ( + unit IS NULL OR + unit IN ('km/h', 'm', 'cm', 'kg', 'g', 'G', 'celsius', 'seconds', 'minutes', 'hours', 'count', '%') +); + +-- Add constraint to ride_technical_specifications table +ALTER TABLE ride_technical_specifications +ADD CONSTRAINT ride_tech_specs_metric_unit_check +CHECK ( + unit IS NULL OR + unit IN ('km/h', 'm', 'cm', 'kg', 'g', 'G', 'celsius', 'seconds', 'minutes', 'hours', 'count', '%') +); + +-- Add constraint to ride_model_technical_specifications table +ALTER TABLE ride_model_technical_specifications +ADD CONSTRAINT ride_model_tech_specs_metric_unit_check +CHECK ( + unit IS NULL OR + unit IN ('km/h', 'm', 'cm', 'kg', 'g', 'G', 'celsius', 'seconds', 'minutes', 'hours', 'count', '%') +); \ No newline at end of file