diff --git a/src/components/admin/HeadquartersLocationInput.tsx b/src/components/admin/HeadquartersLocationInput.tsx index 124657d8..1aeffcaa 100644 --- a/src/components/admin/HeadquartersLocationInput.tsx +++ b/src/components/admin/HeadquartersLocationInput.tsx @@ -4,7 +4,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Search, Edit, MapPin, Loader2, X } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; interface LocationResult { place_id: number; @@ -65,7 +65,10 @@ export function HeadquartersLocationInput({ setShowResults(true); } } catch (error) { - logger.error('Error searching locations', { error }); + handleNonCriticalError(error, { + action: 'Search headquarters locations', + metadata: { query: searchQuery } + }); } finally { setIsSearching(false); } diff --git a/src/components/admin/IntegrationTestRunner.tsx b/src/components/admin/IntegrationTestRunner.tsx index 7ff586bd..19a72e79 100644 --- a/src/components/admin/IntegrationTestRunner.tsx +++ b/src/components/admin/IntegrationTestRunner.tsx @@ -17,7 +17,7 @@ import { useSuperuserGuard } from '@/hooks/useSuperuserGuard'; import { IntegrationTestRunner as TestRunner, allTestSuites, type TestResult } from '@/lib/integrationTests'; import { Play, Square, Download, ChevronDown, CheckCircle2, XCircle, Clock, SkipForward } from 'lucide-react'; import { toast } from 'sonner'; -import { logger } from '@/lib/logger'; +import { handleError } from '@/lib/errorHandler'; export function IntegrationTestRunner() { const superuserGuard = useSuperuserGuard(); @@ -67,8 +67,11 @@ export function IntegrationTestRunner() { } else { toast.success(`All ${summary.passed} tests passed!`); } - } catch (error) { - logger.error('Test run error', { error }); + } catch (error: unknown) { + handleError(error, { + action: 'Run integration tests', + metadata: { suitesCount: suitesToRun.length } + }); toast.error('Test run failed'); } finally { setIsRunning(false); diff --git a/src/components/admin/LocationSearch.tsx b/src/components/admin/LocationSearch.tsx index 4285d8d6..160dd5ee 100644 --- a/src/components/admin/LocationSearch.tsx +++ b/src/components/admin/LocationSearch.tsx @@ -6,7 +6,7 @@ import { Button } from '@/components/ui/button'; import { Card } from '@/components/ui/card'; import { MapPin, Loader2, X } from 'lucide-react'; import { ParkLocationMap } from '@/components/maps/ParkLocationMap'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; interface LocationResult { place_id: number; @@ -102,7 +102,6 @@ export function LocationSearch({ onLocationSelect, initialLocationId, className // Check if response is OK and content-type is JSON if (!response.ok) { const errorMsg = `Location search failed (${response.status}). Please try again.`; - logger.error('OpenStreetMap API error', { status: response.status }); setSearchError(errorMsg); setResults([]); setShowResults(false); @@ -112,7 +111,6 @@ export function LocationSearch({ onLocationSelect, initialLocationId, className const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { const errorMsg = 'Invalid response from location service. Please try again.'; - logger.error('Invalid response format from OpenStreetMap', { contentType }); setSearchError(errorMsg); setResults([]); setShowResults(false); @@ -123,8 +121,11 @@ export function LocationSearch({ onLocationSelect, initialLocationId, className setResults(data); setShowResults(true); setSearchError(null); - } catch { - logger.error('Location search failed', { query: searchQuery }); + } catch (error: unknown) { + handleNonCriticalError(error, { + action: 'Search locations', + metadata: { query: searchQuery } + }); setSearchError('Failed to search locations. Please check your connection.'); setResults([]); setShowResults(false); diff --git a/src/components/admin/MarkdownEditor.tsx b/src/components/admin/MarkdownEditor.tsx index 854db1a4..a92086a9 100644 --- a/src/components/admin/MarkdownEditor.tsx +++ b/src/components/admin/MarkdownEditor.tsx @@ -35,8 +35,7 @@ import { getCloudflareImageUrl } from '@/lib/cloudflareImageUtils'; import { useAutoSave } from '@/hooks/useAutoSave'; import { CheckCircle2, Loader2, AlertCircle } from 'lucide-react'; import { cn } from '@/lib/utils'; -import { getErrorMessage } from '@/lib/errorHandler'; -import { logger } from '@/lib/logger'; +import { handleError } from '@/lib/errorHandler'; interface MarkdownEditorProps { value: string; @@ -157,7 +156,10 @@ export function MarkdownEditor({ return imageUrl; } catch (error: unknown) { - logger.error('Image upload failed', { error: getErrorMessage(error) }); + handleError(error, { + action: 'Upload markdown image', + metadata: { fileName: file.name } + }); throw new Error(error instanceof Error ? error.message : 'Failed to upload image'); } } diff --git a/src/components/admin/NotificationDebugPanel.tsx b/src/components/admin/NotificationDebugPanel.tsx index e53bd1b7..ebcd9cad 100644 --- a/src/components/admin/NotificationDebugPanel.tsx +++ b/src/components/admin/NotificationDebugPanel.tsx @@ -7,7 +7,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@ import { AlertTriangle, CheckCircle, RefreshCw, Loader2 } from 'lucide-react'; import { supabase } from '@/lib/supabaseClient'; import { format } from 'date-fns'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; interface DuplicateStats { date: string | null; @@ -86,8 +86,10 @@ export function NotificationDebugPanel() { profiles: profileMap.get(dup.user_id) }))); } - } catch (error) { - logger.error('Failed to load notification debug data', { error }); + } catch (error: unknown) { + handleNonCriticalError(error, { + action: 'Load notification debug data' + }); } finally { setIsLoading(false); } diff --git a/src/components/admin/SystemActivityLog.tsx b/src/components/admin/SystemActivityLog.tsx index 30898acf..f7b7df09 100644 --- a/src/components/admin/SystemActivityLog.tsx +++ b/src/components/admin/SystemActivityLog.tsx @@ -50,7 +50,6 @@ import { SubmissionWorkflowDetails } from '@/lib/systemActivityService'; import { getErrorMessage } from '@/lib/errorHandler'; -import { logger } from '@/lib/logger'; export interface SystemActivityLogRef { refresh: () => Promise; @@ -194,7 +193,7 @@ export const SystemActivityLog = forwardRef([]); @@ -44,7 +43,7 @@ export function FeaturedParks() { setTopRatedParks(topRated || []); setMostRidesParks(mostRides || []); } catch (error: unknown) { - logger.error('Failed to fetch featured parks', { error: getErrorMessage(error) }); + // Featured parks fetch failed - display empty sections } finally { setLoading(false); } diff --git a/src/components/moderation/ItemEditDialog.tsx b/src/components/moderation/ItemEditDialog.tsx index d3948762..2dcc23f6 100644 --- a/src/components/moderation/ItemEditDialog.tsx +++ b/src/components/moderation/ItemEditDialog.tsx @@ -96,7 +96,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'); + toast({ + title: 'Error', + description: 'No photo data available', + variant: 'destructive', + }); return; } diff --git a/src/components/moderation/SubmissionItemsList.tsx b/src/components/moderation/SubmissionItemsList.tsx index 25d56356..30cf75f3 100644 --- a/src/components/moderation/SubmissionItemsList.tsx +++ b/src/components/moderation/SubmissionItemsList.tsx @@ -13,8 +13,7 @@ import { AlertCircle, Loader2 } from 'lucide-react'; import { format } from 'date-fns'; import type { SubmissionItemData } from '@/types/submissions'; import type { ParkSubmissionData, RideSubmissionData, CompanySubmissionData, RideModelSubmissionData } from '@/types/submission-data'; -import { logger } from '@/lib/logger'; -import { getErrorMessage } from '@/lib/errorHandler'; +import { getErrorMessage, handleNonCriticalError } from '@/lib/errorHandler'; import { ModerationErrorBoundary } from '@/components/error/ModerationErrorBoundary'; interface SubmissionItemsListProps { @@ -71,13 +70,19 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({ .eq('submission_id', submissionId); if (photoError) { - logger.warn('Error checking photo submissions:', photoError); + handleNonCriticalError(photoError, { + action: 'Check photo submissions', + metadata: { submissionId } + }); } setItems(transformedItems as SubmissionItemData[]); setHasPhotos(!!(photoData && photoData.length > 0)); } catch (err) { - logger.error('Failed to fetch submission items', { error: getErrorMessage(err) }); + handleNonCriticalError(err, { + action: 'Fetch submission items', + metadata: { submissionId } + }); setError('Failed to load submission details'); } finally { setLoading(false); diff --git a/src/components/moderation/SubmissionReviewManager.tsx b/src/components/moderation/SubmissionReviewManager.tsx index f1747308..b14a2a04 100644 --- a/src/components/moderation/SubmissionReviewManager.tsx +++ b/src/components/moderation/SubmissionReviewManager.tsx @@ -439,7 +439,11 @@ export function SubmissionReviewManager({ ); if (error) { - logger.error('Edge function failed', { error: getErrorMessage(error) }); + handleError(error, { + action: 'Send escalation notification', + userId: user.id, + metadata: { submissionId } + }); // Fallback to direct database update if email fails await escalateSubmission(submissionId, reason, user.id); toast({ diff --git a/src/components/moderation/ValidationSummary.tsx b/src/components/moderation/ValidationSummary.tsx index f4e20ec2..b9bf6d98 100644 --- a/src/components/moderation/ValidationSummary.tsx +++ b/src/components/moderation/ValidationSummary.tsx @@ -5,7 +5,7 @@ import { RefreshButton } from '@/components/ui/refresh-button'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { validateEntityData, ValidationResult } from '@/lib/entityValidationSchemas'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; import type { SubmissionItemData } from '@/types/moderation'; @@ -92,10 +92,9 @@ export function ValidationSummary({ item, onValidationChange, compact = false, v setValidationResult(result); onValidationChange?.(result); } catch (error: unknown) { - logger.error('Entity validation failed', { - action: 'validate_entity', - entityType: item.item_type, - error: error instanceof Error ? error.message : String(error) + handleNonCriticalError(error, { + action: 'Validate entity', + metadata: { entityType: item.item_type } }); setValidationResult({ isValid: false, diff --git a/src/components/parks/ParkGrid.tsx b/src/components/parks/ParkGrid.tsx index 03245b7d..551a4740 100644 --- a/src/components/parks/ParkGrid.tsx +++ b/src/components/parks/ParkGrid.tsx @@ -9,7 +9,6 @@ import { ParkCard } from './ParkCard'; import { Park } from '@/types/database'; import { supabase } from '@/lib/supabaseClient'; import { getErrorMessage } from '@/lib/errorHandler'; -import { logger } from '@/lib/logger'; export function ParkGrid() { const [parks, setParks] = useState([]); @@ -43,7 +42,7 @@ export function ParkGrid() { if (error) throw error; setParks(data || []); } catch (error: unknown) { - logger.error('Failed to fetch featured parks', { error: getErrorMessage(error) }); + // Parks fetch failed - display empty grid } finally { setLoading(false); } diff --git a/src/components/settings/PrivacyTab.tsx b/src/components/settings/PrivacyTab.tsx index 883e6342..2083f68a 100644 --- a/src/components/settings/PrivacyTab.tsx +++ b/src/components/settings/PrivacyTab.tsx @@ -8,7 +8,6 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Separator } from '@/components/ui/separator'; import { handleError, handleSuccess, AppError } from '@/lib/errorHandler'; -import { logger } from '@/lib/logger'; import { useAuth } from '@/hooks/useAuth'; import { useProfile } from '@/hooks/useProfile'; import { supabase } from '@/lib/supabaseClient'; @@ -50,12 +49,6 @@ export function PrivacyTab() { .maybeSingle(); if (error && error.code !== 'PGRST116') { - logger.error('Failed to fetch privacy preferences', { - userId: user.id, - action: 'fetch_privacy_preferences', - error: error.message, - errorCode: error.code - }); throw error; } @@ -72,19 +65,12 @@ export function PrivacyTab() { ...parseResult.data }); } else { - logger.warn('Invalid privacy settings, reinitializing with defaults'); await initializePreferences(); } } else { await initializePreferences(); } } catch (error: unknown) { - logger.error('Error fetching privacy preferences', { - userId: user.id, - action: 'fetch_privacy_preferences', - error: error instanceof Error ? error.message : String(error) - }); - handleError(error, { action: 'Load privacy settings', userId: user.id @@ -104,11 +90,6 @@ export function PrivacyTab() { }]); if (error) { - logger.error('Failed to initialize privacy preferences', { - userId: user.id, - action: 'initialize_privacy_preferences', - error: error.message - }); throw error; } @@ -121,12 +102,6 @@ export function PrivacyTab() { ...DEFAULT_PRIVACY_SETTINGS }); } catch (error: unknown) { - logger.error('Error initializing privacy preferences', { - userId: user.id, - action: 'initialize_privacy_preferences', - error: error instanceof Error ? error.message : String(error) - }); - handleError(error, { action: 'Initialize privacy settings', userId: user.id @@ -154,12 +129,6 @@ export function PrivacyTab() { .eq('user_id', user.id); if (profileError) { - logger.error('Failed to update profile privacy', { - userId: user.id, - action: 'update_profile_privacy', - error: profileError.message, - errorCode: profileError.code - }); throw profileError; } @@ -176,12 +145,6 @@ export function PrivacyTab() { }]); if (prefsError) { - logger.error('Failed to update privacy preferences', { - userId: user.id, - action: 'update_privacy_preferences', - error: prefsError.message, - errorCode: prefsError.code - }); throw prefsError; } @@ -200,22 +163,11 @@ export function PrivacyTab() { await refreshProfile(); setPreferences(privacySettings); - logger.info('Privacy settings updated successfully', { - userId: user.id, - action: 'update_privacy_settings' - }); - handleSuccess( 'Privacy settings updated', 'Your privacy preferences have been successfully saved.' ); } catch (error: unknown) { - logger.error('Failed to update privacy settings', { - userId: user.id, - action: 'update_privacy_settings', - error: error instanceof Error ? error.message : String(error) - }); - if (error instanceof z.ZodError) { handleError( new AppError( diff --git a/src/components/settings/SecurityTab.tsx b/src/components/settings/SecurityTab.tsx index cf9df01e..62242edc 100644 --- a/src/components/settings/SecurityTab.tsx +++ b/src/components/settings/SecurityTab.tsx @@ -24,7 +24,6 @@ import { import type { UserIdentity, OAuthProvider } from '@/types/identity'; import type { AuthSession } from '@/types/auth'; import { supabase } from '@/lib/supabaseClient'; -import { logger } from '@/lib/logger'; import { SessionRevokeConfirmDialog } from './SessionRevokeConfirmDialog'; export function SecurityTab() { @@ -57,11 +56,6 @@ export function SecurityTab() { const hasEmailProvider = fetchedIdentities.some(i => i.provider === 'email'); setHasPassword(hasEmailProvider); } catch (error: unknown) { - logger.error('Failed to load identities', { - userId: user?.id, - action: 'load_identities', - error: error instanceof Error ? error.message : String(error) - }); handleError(error, { action: 'Load connected accounts', userId: user?.id }); } finally { setLoadingIdentities(false); @@ -159,11 +153,6 @@ export function SecurityTab() { setSessions((data as AuthSession[]) || []); } catch (error: unknown) { - logger.error('Failed to fetch sessions', { - userId: user.id, - action: 'fetch_sessions', - error: error instanceof Error ? error.message : String(error) - }); handleError(error, { action: 'Load active sessions', userId: user.id @@ -190,12 +179,6 @@ export function SecurityTab() { const { error } = await supabase.rpc('revoke_my_session', { session_id: sessionToRevoke.id }); if (error) { - logger.error('Failed to revoke session', { - userId: user?.id, - action: 'revoke_session', - sessionId: sessionToRevoke.id, - error: error.message - }); handleError(error, { action: 'Revoke session', userId: user?.id }); } else { handleSuccess('Success', 'Session revoked successfully'); diff --git a/src/components/upload/EntityMultiImageUploader.tsx b/src/components/upload/EntityMultiImageUploader.tsx index 4a1fe2b4..c355fa9a 100644 --- a/src/components/upload/EntityMultiImageUploader.tsx +++ b/src/components/upload/EntityMultiImageUploader.tsx @@ -15,7 +15,6 @@ import { toast } from '@/hooks/use-toast'; import { Skeleton } from '@/components/ui/skeleton'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { getErrorMessage } from '@/lib/errorHandler'; -import { logger } from '@/lib/logger'; export interface UploadedImage { url: string; @@ -71,8 +70,8 @@ export function EntityMultiImageUploader({ if (image.isLocal && image.url.startsWith('blob:')) { try { URL.revokeObjectURL(image.url); - } catch (error: unknown) { - logger.error('Failed to revoke object URL', { error: getErrorMessage(error) }); + } catch { + // Silent cleanup failure - non-critical } } }); diff --git a/src/components/upload/EntityPhotoGallery.tsx b/src/components/upload/EntityPhotoGallery.tsx index fddc6b04..8ad3d0ad 100644 --- a/src/components/upload/EntityPhotoGallery.tsx +++ b/src/components/upload/EntityPhotoGallery.tsx @@ -18,7 +18,6 @@ import { supabase } from '@/lib/supabaseClient'; import { EntityPhotoGalleryProps } from '@/types/submissions'; import { useUserRole } from '@/hooks/useUserRole'; import { getErrorMessage } from '@/lib/errorHandler'; -import { logger } from '@/lib/logger'; interface Photo { id: string; @@ -74,7 +73,7 @@ export function EntityPhotoGallery({ setPhotos(mappedPhotos); } catch (error: unknown) { - logger.error('Failed to fetch photos', { error: getErrorMessage(error), entityId, entityType }); + // Photo fetch failed - display empty gallery } finally { setLoading(false); } diff --git a/src/components/upload/PhotoManagementDialog.tsx b/src/components/upload/PhotoManagementDialog.tsx index 7365242a..2225742f 100644 --- a/src/components/upload/PhotoManagementDialog.tsx +++ b/src/components/upload/PhotoManagementDialog.tsx @@ -26,7 +26,6 @@ import { useToast } from '@/hooks/use-toast'; import { Trash2, Pencil } from 'lucide-react'; import { Card, CardContent } from '@/components/ui/card'; import { getErrorMessage } from '@/lib/errorHandler'; -import { logger } from '@/lib/logger'; interface Photo { id: string; @@ -127,8 +126,8 @@ export function PhotoManagementDialog({ const { data } = await supabase.from('companies').select('name').eq('id', entityId).single(); if (data?.name) entityName = data.name; } - } catch (err) { - logger.error('Failed to fetch entity name', { error: getErrorMessage(err), entityType, entityId }); + } catch { + // Failed to fetch entity name - use default } // Create content submission diff --git a/src/components/upload/PhotoUpload.tsx b/src/components/upload/PhotoUpload.tsx index 84a08ea1..e9ac2db9 100644 --- a/src/components/upload/PhotoUpload.tsx +++ b/src/components/upload/PhotoUpload.tsx @@ -17,7 +17,6 @@ import { getErrorMessage } from '@/lib/errorHandler'; import { supabase } from '@/lib/supabaseClient'; import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { useAuth } from '@/hooks/useAuth'; -import { logger } from '@/lib/logger'; interface PhotoUploadProps { onUploadComplete?: (urls: string[], imageId?: string) => void; @@ -71,8 +70,8 @@ export function PhotoUpload({ objectUrlsRef.current.forEach(url => { try { URL.revokeObjectURL(url); - } catch (error: unknown) { - logger.error('Failed to revoke object URL', { error: getErrorMessage(error) }); + } catch { + // Silent cleanup failure - non-critical } }); objectUrlsRef.current.clear(); @@ -90,8 +89,8 @@ export function PhotoUpload({ try { URL.revokeObjectURL(url); objectUrlsRef.current.delete(url); - } catch (error: unknown) { - logger.error('Failed to revoke object URL', { error: getErrorMessage(error) }); + } catch { + // Silent cleanup failure - non-critical } } }; @@ -194,8 +193,8 @@ export function PhotoUpload({ }; } } - } catch (error: unknown) { - logger.error('Status poll error', { error: getErrorMessage(error) }); + } catch { + // Status poll error - will retry } await new Promise(resolve => setTimeout(resolve, 500)); @@ -249,8 +248,8 @@ export function PhotoUpload({ undefined, 'DELETE' ); - } catch (deleteError) { - logger.warn('Failed to delete old avatar'); + } catch { + // Old avatar deletion failed - non-critical } } @@ -339,7 +338,6 @@ export function PhotoUpload({ alt="Avatar" className="w-24 h-24 rounded-full object-cover border-2 border-border" onError={(e) => { - logger.warn('Failed to load avatar image'); e.currentTarget.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSIjZjNmNGY2Ii8+CjxwYXRoIGQ9Im0xNSAxMi0zLTMtMy4wMDEgM0w2IDlsNi02aDZ2NloiIGZpbGw9IiM5Y2EzYWYiLz4KPC9zdmc+'; }} /> @@ -487,7 +485,6 @@ export function PhotoUpload({ alt={image.filename} className="w-full aspect-square object-cover rounded-lg border" onError={(e) => { - logger.warn('Failed to load thumbnail image'); e.currentTarget.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSIjZjNmNGY2Ii8+CjxwYXRoIGQ9Im0xNSAxMi0zLTMtMy4wMDEgM0w2IDlsNi02aDZ2NloiIGZpbGw9IiM5Y2EzYWYiLz4KPC9zdmc+'; }} />