Implement Phase 3C error logging

This commit is contained in:
gpt-engineer-app[bot]
2025-11-04 19:39:55 +00:00
parent 162d288cb0
commit a9334c7a3a
13 changed files with 179 additions and 210 deletions

View File

@@ -2,8 +2,7 @@ import { useState, useEffect } from 'react';
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { ComboboxOption } from '@/components/ui/combobox'; import { ComboboxOption } from '@/components/ui/combobox';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { logger } from '@/lib/logger'; import { handleNonCriticalError } from '@/lib/errorHandler';
import { getErrorMessage } from '@/lib/errorHandler';
export function useCountries() { export function useCountries() {
const [countries, setCountries] = useState<ComboboxOption[]>([]); const [countries, setCountries] = useState<ComboboxOption[]>([]);
@@ -31,8 +30,7 @@ export function useCountries() {
})) }))
); );
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleNonCriticalError(error, { action: 'Fetch countries' });
logger.error('Failed to fetch countries', { error: errorMsg });
toast.error('Failed to load countries', { toast.error('Failed to load countries', {
description: 'Please refresh the page and try again.', description: 'Please refresh the page and try again.',
}); });
@@ -80,8 +78,10 @@ export function useStatesProvinces(country?: string) {
})) }))
); );
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleNonCriticalError(error, {
logger.error('Failed to fetch states/provinces', { country, error: errorMsg }); action: 'Fetch states/provinces',
metadata: { country },
});
toast.error('Failed to load states/provinces', { toast.error('Failed to load states/provinces', {
description: 'Please refresh the page and try again.', description: 'Please refresh the page and try again.',
}); });
@@ -120,8 +120,7 @@ export function useManufacturers() {
})) }))
); );
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleNonCriticalError(error, { action: 'Fetch manufacturers' });
logger.error('Failed to fetch manufacturers', { error: errorMsg });
toast.error('Failed to load manufacturers', { toast.error('Failed to load manufacturers', {
description: 'Please refresh the page and try again.', description: 'Please refresh the page and try again.',
}); });
@@ -165,8 +164,10 @@ export function useRideModels(manufacturerId?: string) {
})) }))
); );
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleNonCriticalError(error, {
logger.error('Failed to fetch ride models', { manufacturerId, error: errorMsg }); action: 'Fetch ride models',
metadata: { manufacturerId },
});
toast.error('Failed to load ride models', { toast.error('Failed to load ride models', {
description: 'Please refresh the page and try again.', description: 'Please refresh the page and try again.',
}); });
@@ -208,8 +209,7 @@ export function useCompanyHeadquarters() {
})) }))
); );
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleNonCriticalError(error, { action: 'Fetch headquarters' });
logger.error('Failed to fetch headquarters', { error: errorMsg });
toast.error('Failed to load headquarters', { toast.error('Failed to load headquarters', {
description: 'Please refresh the page and try again.', description: 'Please refresh the page and try again.',
}); });
@@ -248,8 +248,7 @@ export function useOperators() {
})) }))
); );
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleNonCriticalError(error, { action: 'Fetch operators' });
logger.error('Failed to fetch operators', { error: errorMsg });
toast.error('Failed to load operators', { toast.error('Failed to load operators', {
description: 'Please refresh the page and try again.', description: 'Please refresh the page and try again.',
}); });
@@ -288,8 +287,7 @@ export function usePropertyOwners() {
})) }))
); );
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleNonCriticalError(error, { action: 'Fetch property owners' });
logger.error('Failed to fetch property owners', { error: errorMsg });
toast.error('Failed to load property owners', { toast.error('Failed to load property owners', {
description: 'Please refresh the page and try again.', description: 'Please refresh the page and try again.',
}); });

View File

@@ -57,7 +57,7 @@ export function useBanCheck() {
navigate('/'); navigate('/');
} }
} catch (error) { } catch (error) {
logger.error('Ban check error', { error, userId: user.id }); // Silent - ban check failure is non-critical, user proceeds normally
} finally { } finally {
setLoading(false); setLoading(false);
} }

View File

@@ -1,7 +1,7 @@
import { useState, useEffect, useRef, useCallback } from 'react'; import { useState, useEffect, useRef, useCallback } from 'react';
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { getErrorMessage, handleNonCriticalError } from '@/lib/errorHandler'; import { getErrorMessage, handleNonCriticalError, handleError } from '@/lib/errorHandler';
import type { EntityType, EntityVersion } from '@/types/versioning'; import type { EntityType, EntityVersion } from '@/types/versioning';
import { logger } from '@/lib/logger'; import { logger } from '@/lib/logger';
@@ -117,11 +117,13 @@ export function useEntityVersions(entityType: EntityType, entityId: string) {
setLoading(false); setLoading(false);
} }
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleNonCriticalError(error, {
logger.error('Failed to fetch versions', { entityType, entityId, error: errorMsg }); action: 'Fetch entity versions',
metadata: { entityType, entityId },
});
if (isMountedRef.current && currentRequestId === requestCounterRef.current) { if (isMountedRef.current && currentRequestId === requestCounterRef.current) {
toast.error(errorMsg); toast.error(getErrorMessage(error));
setLoading(false); setLoading(false);
} }
} }
@@ -149,10 +151,12 @@ export function useEntityVersions(entityType: EntityType, entityId: string) {
return data; return data;
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleNonCriticalError(error, {
logger.error('Failed to compare versions', { entityType, fromVersionId, toVersionId, error: errorMsg }); action: 'Compare entity versions',
metadata: { entityType, fromVersionId, toVersionId },
});
if (isMountedRef.current) { if (isMountedRef.current) {
toast.error(errorMsg); toast.error(getErrorMessage(error));
} }
return null; return null;
} }
@@ -187,11 +191,13 @@ export function useEntityVersions(entityType: EntityType, entityId: string) {
} }
return data; return data;
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleError(error, {
logger.error('Failed to rollback version', { entityType, entityId, targetVersionId, error: errorMsg }); action: 'Rollback entity version',
metadata: { entityType, entityId, targetVersionId },
});
if (isMountedRef.current) { if (isMountedRef.current) {
toast.error('Failed to restore version', { toast.error('Failed to restore version', {
description: errorMsg description: getErrorMessage(error)
}); });
} }
return null; return null;

View File

@@ -1,10 +1,9 @@
import { useState, useEffect, useMemo, useCallback } from 'react'; import { useState, useEffect, useMemo, useCallback } from 'react';
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { Park, Ride, Company } from '@/types/database'; import { Park, Ride, Company } from '@/types/database';
import { logger } from '@/lib/logger';
import * as storage from '@/lib/localStorage'; import * as storage from '@/lib/localStorage';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { getErrorMessage } from '@/lib/errorHandler'; import { handleNonCriticalError } from '@/lib/errorHandler';
export interface SearchResult { export interface SearchResult {
id: string; id: string;
@@ -167,11 +166,9 @@ export function useSearch(options: UseSearchOptions = {}) {
setResults(searchResults.slice(0, limit)); setResults(searchResults.slice(0, limit));
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleNonCriticalError(error, {
logger.error('Search failed', { action: 'Search',
query: searchQuery, metadata: { query: searchQuery, types },
types,
error: errorMsg
}); });
toast.error('Search failed', { toast.error('Search failed', {

View File

@@ -3,6 +3,7 @@ import { useAuth } from './useAuth';
import { useRequireMFA } from './useRequireMFA'; import { useRequireMFA } from './useRequireMFA';
import { getSessionAal } from '@/lib/authService'; import { getSessionAal } from '@/lib/authService';
import { logger } from '@/lib/logger'; import { logger } from '@/lib/logger';
import { handleNonCriticalError } from '@/lib/errorHandler';
/** /**
* Phase 3: Session Monitoring Hook * Phase 3: Session Monitoring Hook
@@ -56,10 +57,9 @@ export function useSessionMonitor() {
}, 30000); }, 30000);
} }
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Session monitor check failed', { handleNonCriticalError(error, {
action: 'Session monitor check',
userId: user.id, userId: user.id,
action: 'session_monitor',
error: error instanceof Error ? error.message : String(error)
}); });
} }
}, 60000); }, 60000);

View File

@@ -2,7 +2,7 @@ import { useState, useEffect, useCallback } from 'react';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { useAuth } from '@/hooks/useAuth'; import { useAuth } from '@/hooks/useAuth';
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { logger } from '@/lib/logger'; import { handleNonCriticalError } from '@/lib/errorHandler';
import { UnitPreferences, getMeasurementSystemFromCountry } from '@/lib/units'; import { UnitPreferences, getMeasurementSystemFromCountry } from '@/lib/units';
import type { Json } from '@/integrations/supabase/types'; import type { Json } from '@/integrations/supabase/types';
import * as storage from '@/lib/localStorage'; import * as storage from '@/lib/localStorage';
@@ -42,11 +42,9 @@ export function useUnitPreferences() {
.maybeSingle(); .maybeSingle();
if (error && error.code !== 'PGRST116') { if (error && error.code !== 'PGRST116') {
logger.error('Failed to fetch unit preferences', { handleNonCriticalError(error, {
action: 'Fetch unit preferences',
userId: user.id, userId: user.id,
action: 'fetch_unit_preferences',
error: error.message,
errorCode: error.code
}); });
throw error; throw error;
} }
@@ -71,10 +69,9 @@ export function useUnitPreferences() {
} }
} }
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Error loading unit preferences', { handleNonCriticalError(error, {
action: 'Load unit preferences',
userId: user?.id, userId: user?.id,
action: 'load_unit_preferences',
error: error instanceof Error ? error.message : String(error)
}); });
await autoDetectPreferences(); await autoDetectPreferences();
} finally { } finally {
@@ -106,10 +103,9 @@ export function useUnitPreferences() {
}); });
if (error) { if (error) {
logger.error('Error saving auto-detected preferences', { handleNonCriticalError(error, {
action: 'Save auto-detected preferences',
userId: user.id, userId: user.id,
action: 'save_auto_detected_preferences',
error: error.message
}); });
} }
} else { } else {
@@ -119,10 +115,9 @@ export function useUnitPreferences() {
return newPreferences; return newPreferences;
} }
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Error auto-detecting location', { handleNonCriticalError(error, {
action: 'Auto-detect location',
userId: user?.id, userId: user?.id,
action: 'auto_detect_location',
error: error instanceof Error ? error.message : String(error)
}); });
} }
@@ -144,19 +139,13 @@ export function useUnitPreferences() {
updated_at: new Date().toISOString() updated_at: new Date().toISOString()
}) })
.eq('user_id', user.id); .eq('user_id', user.id);
logger.info('Unit preferences updated', {
userId: user.id,
action: 'update_unit_preferences'
});
} else { } else {
storage.setJSON('unit_preferences', updated); storage.setJSON('unit_preferences', updated);
} }
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Error saving unit preferences', { handleNonCriticalError(error, {
action: 'Save unit preferences',
userId: user?.id, userId: user?.id,
action: 'save_unit_preferences',
error: error instanceof Error ? error.message : String(error)
}); });
setPreferences(preferences); setPreferences(preferences);
throw error; throw error;

View File

@@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query';
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { useAuth } from '@/hooks/useAuth'; import { useAuth } from '@/hooks/useAuth';
import { queryKeys } from '@/lib/queryKeys'; import { queryKeys } from '@/lib/queryKeys';
import { logger } from '@/lib/logger'; import { handleNonCriticalError } from '@/lib/errorHandler';
export type UserRole = 'admin' | 'moderator' | 'user' | 'superuser'; export type UserRole = 'admin' | 'moderator' | 'user' | 'superuser';
@@ -30,7 +30,10 @@ export function useUserRole() {
.eq('user_id', user.id); .eq('user_id', user.id);
if (error) { if (error) {
logger.error('Error fetching user roles', { error, userId: user.id }); handleNonCriticalError(error, {
action: 'Fetch user roles',
userId: user.id,
});
return []; return [];
} }
@@ -51,7 +54,10 @@ export function useUserRole() {
.rpc('get_user_management_permissions', { _user_id: user.id }); .rpc('get_user_management_permissions', { _user_id: user.id });
if (error) { if (error) {
logger.error('Error fetching user permissions', { error, userId: user.id }); handleNonCriticalError(error, {
action: 'Fetch user permissions',
userId: user.id,
});
return null; return null;
} }

View File

@@ -4,7 +4,7 @@
*/ */
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { logger } from './logger'; import { handleNonCriticalError } from './errorHandler';
/** /**
* Write admin audit details to relational table * Write admin audit details to relational table
@@ -27,7 +27,10 @@ export async function writeAdminAuditDetails(
.insert(entries); .insert(entries);
if (error) { if (error) {
logger.error('Failed to write admin audit details', { error, auditLogId }); handleNonCriticalError(error, {
action: 'Write admin audit details',
metadata: { auditLogId },
});
throw error; throw error;
} }
} }
@@ -53,7 +56,10 @@ export async function writeModerationAuditMetadata(
.insert(entries); .insert(entries);
if (error) { if (error) {
logger.error('Failed to write moderation audit metadata', { error, auditLogId }); handleNonCriticalError(error, {
action: 'Write moderation audit metadata',
metadata: { auditLogId },
});
throw error; throw error;
} }
} }
@@ -84,7 +90,10 @@ export async function writeItemChangeFields(
.insert(entries); .insert(entries);
if (error) { if (error) {
logger.error('Failed to write item change fields', { error, editHistoryId }); handleNonCriticalError(error, {
action: 'Write item change fields',
metadata: { editHistoryId },
});
throw error; throw error;
} }
} }
@@ -118,7 +127,10 @@ export async function writeRequestBreadcrumbs(
.insert(entries); .insert(entries);
if (error) { if (error) {
logger.error('Failed to write request breadcrumbs', { error, requestId }); handleNonCriticalError(error, {
action: 'Write request breadcrumbs',
metadata: { requestId },
});
throw error; throw error;
} }
} }
@@ -135,7 +147,10 @@ export async function readAdminAuditDetails(
.eq('audit_log_id', auditLogId); .eq('audit_log_id', auditLogId);
if (error) { if (error) {
logger.error('Failed to read admin audit details', { error, auditLogId }); handleNonCriticalError(error, {
action: 'Read admin audit details',
metadata: { auditLogId },
});
return {}; return {};
} }
@@ -157,7 +172,10 @@ export async function readModerationAuditMetadata(
.eq('audit_log_id', auditLogId); .eq('audit_log_id', auditLogId);
if (error) { if (error) {
logger.error('Failed to read moderation audit metadata', { error, auditLogId }); handleNonCriticalError(error, {
action: 'Read moderation audit metadata',
metadata: { auditLogId },
});
return {}; return {};
} }
@@ -179,7 +197,10 @@ export async function readItemChangeFields(
.eq('edit_history_id', editHistoryId); .eq('edit_history_id', editHistoryId);
if (error) { if (error) {
logger.error('Failed to read item change fields', { error, editHistoryId }); handleNonCriticalError(error, {
action: 'Read item change fields',
metadata: { editHistoryId },
});
return {}; return {};
} }
@@ -218,7 +239,10 @@ export async function writeProfileChangeFields(
.insert(entries); .insert(entries);
if (error) { if (error) {
logger.error('Failed to write profile change fields', { error, auditLogId }); handleNonCriticalError(error, {
action: 'Write profile change fields',
metadata: { auditLogId },
});
throw error; throw error;
} }
} }
@@ -252,7 +276,10 @@ export async function writeConflictDetailFields(
.insert(entries); .insert(entries);
if (error) { if (error) {
logger.error('Failed to write conflict detail fields', { error, conflictResolutionId }); handleNonCriticalError(error, {
action: 'Write conflict detail fields',
metadata: { conflictResolutionId },
});
throw error; throw error;
} }
} }

View File

@@ -14,7 +14,7 @@ import type {
} from '@/types/auth'; } from '@/types/auth';
import { setStepUpRequired, setAuthMethod, clearAllAuthFlags } from './sessionFlags'; import { setStepUpRequired, setAuthMethod, clearAllAuthFlags } from './sessionFlags';
import { logger } from './logger'; import { logger } from './logger';
import { getErrorMessage } from './errorHandler'; import { getErrorMessage, handleNonCriticalError } from './errorHandler';
/** /**
* Extract AAL level from session using Supabase API * Extract AAL level from session using Supabase API
@@ -37,9 +37,8 @@ export async function getSessionAal(session: Session | null): Promise<AALLevel>
}); });
if (error) { if (error) {
logger.error('[AuthService] Error getting AAL', { handleNonCriticalError(error, {
action: 'get_session_aal', action: 'Get session AAL',
error: error.message
}); });
return 'aal1'; return 'aal1';
} }
@@ -48,10 +47,8 @@ export async function getSessionAal(session: Session | null): Promise<AALLevel>
logger.log('[AuthService] Returning AAL', { level }); logger.log('[AuthService] Returning AAL', { level });
return level; return level;
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = getErrorMessage(error); handleNonCriticalError(error, {
logger.error('[AuthService] Exception getting AAL', { action: 'Get session AAL exception',
action: 'get_session_aal',
error: errorMessage
}); });
return 'aal1'; return 'aal1';
} }
@@ -65,9 +62,8 @@ export async function getEnrolledFactors(): Promise<MFAFactor[]> {
const { data, error } = await supabase.auth.mfa.listFactors(); const { data, error } = await supabase.auth.mfa.listFactors();
if (error) { if (error) {
logger.error('[AuthService] Error listing factors', { handleNonCriticalError(error, {
action: 'get_enrolled_factors', action: 'List MFA factors',
error: error.message
}); });
return []; return [];
} }
@@ -83,10 +79,8 @@ export async function getEnrolledFactors(): Promise<MFAFactor[]> {
updated_at: f.updated_at, updated_at: f.updated_at,
})); }));
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = getErrorMessage(error); handleNonCriticalError(error, {
logger.error('[AuthService] Exception listing factors', { action: 'List MFA factors exception',
action: 'get_enrolled_factors',
error: errorMessage
}); });
return []; return [];
} }
@@ -135,21 +129,18 @@ export async function verifyMfaRequired(userId: string): Promise<boolean> {
.in('role', ['admin', 'moderator']); .in('role', ['admin', 'moderator']);
if (error) { if (error) {
logger.error('[AuthService] Error checking roles', { handleNonCriticalError(error, {
action: 'verify_mfa_required', action: 'Verify MFA required',
userId, userId,
error: error.message
}); });
return false; return false;
} }
return (data?.length || 0) > 0; return (data?.length || 0) > 0;
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = getErrorMessage(error); handleNonCriticalError(error, {
logger.error('[AuthService] Exception checking roles', { action: 'Verify MFA required exception',
action: 'verify_mfa_required',
userId, userId,
error: errorMessage
}); });
return false; return false;
} }
@@ -207,15 +198,13 @@ export async function handlePostAuthFlow(
}, },
}; };
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = getErrorMessage(error); handleNonCriticalError(error, {
logger.error('[AuthService] Error in post-auth flow', { action: 'Handle post-auth flow',
action: 'handle_post_auth_flow', metadata: { authMethod },
authMethod,
error: errorMessage
}); });
return { return {
success: false, success: false,
error: errorMessage, error: getErrorMessage(error),
}; };
} }
} }
@@ -234,10 +223,9 @@ export async function verifyMfaUpgrade(session: Session | null): Promise<MFAChal
const currentAal = await getSessionAal(session); const currentAal = await getSessionAal(session);
if (currentAal !== 'aal2') { if (currentAal !== 'aal2') {
logger.error('[AuthService] MFA verification failed', { handleNonCriticalError(new Error('MFA verification failed'), {
action: 'verify_mfa_upgrade', action: 'Verify MFA upgrade',
expectedAal: 'aal2', metadata: { expectedAal: 'aal2', actualAal: currentAal },
actualAal: currentAal
}); });
await logAuthEvent(session.user.id, 'mfa_verification_failed', { await logAuthEvent(session.user.id, 'mfa_verification_failed', {
expected_aal: 'aal2', expected_aal: 'aal2',
@@ -282,20 +270,15 @@ async function logAuthEvent(
}); });
if (error) { if (error) {
logger.error('[AuthService] Error logging auth event', { handleNonCriticalError(error, {
action: 'log_auth_event', action: 'Log auth event',
eventAction: action, metadata: { eventAction: action, userId },
userId,
error: error.message
}); });
} }
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = getErrorMessage(error); handleNonCriticalError(error, {
logger.error('[AuthService] Exception logging auth event', { action: 'Log auth event exception',
action: 'log_auth_event', metadata: { eventAction: action, userId },
eventAction: action,
userId,
error: errorMessage
}); });
} }
} }

View File

@@ -2,8 +2,7 @@ import { supabase } from '@/lib/supabaseClient';
import type { Json } from '@/integrations/supabase/types'; import type { Json } from '@/integrations/supabase/types';
import { uploadPendingImages } from './imageUploadHelper'; import { uploadPendingImages } from './imageUploadHelper';
import { CompanyFormData, TempCompanyData } from '@/types/company'; import { CompanyFormData, TempCompanyData } from '@/types/company';
import { logger } from './logger'; import { handleError } from './errorHandler';
import { getErrorMessage } from './errorHandler';
export type { CompanyFormData, TempCompanyData }; export type { CompanyFormData, TempCompanyData };
@@ -33,10 +32,9 @@ export async function submitCompanyCreation(
uploaded: uploadedImages uploaded: uploadedImages
}; };
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleError(error, {
logger.error('Failed to upload images for company', { action: 'Upload company images',
action: `${companyType}_creation`, metadata: { companyType },
error: errorMsg
}); });
throw new Error('Failed to upload images. Please check your connection and try again.'); throw new Error('Failed to upload images. Please check your connection and try again.');
} }
@@ -120,11 +118,9 @@ export async function submitCompanyUpdate(
uploaded: uploadedImages uploaded: uploadedImages
}; };
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleError(error, {
logger.error('Failed to upload images for company update', { action: 'Upload company images for update',
action: `${existingCompany.company_type}_update`, metadata: { companyType: existingCompany.company_type, companyId },
companyId,
error: errorMsg
}); });
throw new Error('Failed to upload images. Please check your connection and try again.'); throw new Error('Failed to upload images. Please check your connection and try again.');
} }

View File

@@ -1,6 +1,5 @@
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { getErrorMessage } from '@/lib/errorHandler'; import { handleError, handleNonCriticalError } from '@/lib/errorHandler';
import { logger } from '@/lib/logger';
import { updateSubmissionItem, type SubmissionItemWithDeps, type DependencyConflict } from './submissionItemsService'; import { updateSubmissionItem, type SubmissionItemWithDeps, type DependencyConflict } from './submissionItemsService';
export interface ResolutionResult { export interface ResolutionResult {
@@ -86,15 +85,13 @@ export async function resolveConflicts(
updatedSelections, updatedSelections,
}; };
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleError(error, {
logger.error('Conflict resolution error', { action: 'Resolve conflicts',
action: 'resolve_conflicts', metadata: { conflictCount: conflicts.length },
conflictCount: conflicts.length,
error: errorMsg
}); });
return { return {
success: false, success: false,
error: errorMsg, error: error instanceof Error ? error.message : 'Unknown error',
}; };
} }
} }
@@ -236,11 +233,9 @@ export async function findMatchingEntities(
return []; return [];
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleNonCriticalError(error, {
logger.error('Error finding matching entities', { action: 'Find matching entities',
action: 'find_matching_entities', metadata: { itemType },
itemType,
error: errorMsg
}); });
return []; return [];
} }

View File

@@ -1,7 +1,6 @@
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { logger } from '@/lib/logger'; import { handleNonCriticalError } from '@/lib/errorHandler';
import { getErrorMessage } from '@/lib/errorHandler';
interface EmailValidationResult { interface EmailValidationResult {
valid: boolean; valid: boolean;
@@ -22,9 +21,8 @@ export async function validateEmailNotDisposable(email: string): Promise<EmailVa
); );
if (error) { if (error) {
logger.error('Email validation error from backend', { handleNonCriticalError(error, {
action: 'validate_email_backend', action: 'Validate email backend',
error: error.message
}); });
return { return {
valid: false, valid: false,
@@ -34,10 +32,8 @@ export async function validateEmailNotDisposable(email: string): Promise<EmailVa
return data as EmailValidationResult; return data as EmailValidationResult;
} catch (error: unknown) { } catch (error: unknown) {
const errorMsg = getErrorMessage(error); handleNonCriticalError(error, {
logger.error('Email validation error', { action: 'Validate email disposable',
action: 'validate_email_disposable',
error: errorMsg
}); });
return { return {
valid: false, valid: false,

View File

@@ -6,7 +6,7 @@ import type { ProcessedImage } from './supabaseHelpers';
import { extractChangedFields } from './submissionChangeDetection'; import { extractChangedFields } from './submissionChangeDetection';
import type { CompanyDatabaseRecord, TimelineEventDatabaseRecord } from '@/types/company-data'; import type { CompanyDatabaseRecord, TimelineEventDatabaseRecord } from '@/types/company-data';
import { logger } from './logger'; import { logger } from './logger';
import { getErrorMessage } from './errorHandler'; import { handleError } from './errorHandler';
import type { TimelineEventFormData, EntityType } from '@/types/timeline'; import type { TimelineEventFormData, EntityType } from '@/types/timeline';
// ============================================ // ============================================
@@ -345,13 +345,11 @@ async function submitCompositeCreation(
}); });
if (error) { if (error) {
logger.error('Composite submission failed', { handleError(error, {
action: 'composite_submission', action: 'Composite submission',
primaryType: uploadedPrimary.type, metadata: { primaryType: uploadedPrimary.type, dependencyCount: dependencies.length },
dependencyCount: dependencies.length,
error: getErrorMessage(error)
}); });
throw new Error(`Failed to create composite submission: ${getErrorMessage(error)}`); throw new Error(`Failed to create composite submission: ${error instanceof Error ? error.message : 'Unknown error'}`);
} }
return { submitted: true, submissionId: result }; return { submitted: true, submissionId: result };
@@ -440,12 +438,10 @@ export async function submitParkCreation(
uploaded: uploadedImages uploaded: uploadedImages
}; };
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = getErrorMessage(error); handleError(error, {
logger.error('Park image upload failed', { action: 'Upload park images',
action: 'park_creation',
error: errorMessage
}); });
throw new Error(`Failed to upload images: ${errorMessage}`); throw new Error(`Failed to upload images: ${error instanceof Error ? error.message : 'Unknown error'}`);
} }
} }
@@ -751,12 +747,10 @@ export async function submitRideCreation(
uploaded: uploadedImages uploaded: uploadedImages
}; };
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = getErrorMessage(error); handleError(error, {
logger.error('Ride image upload failed', { action: 'Upload ride images',
action: 'ride_creation',
error: errorMessage
}); });
throw new Error(`Failed to upload images: ${errorMessage}`); throw new Error(`Failed to upload images: ${error instanceof Error ? error.message : 'Unknown error'}`);
} }
} }
@@ -972,12 +966,10 @@ export async function submitRideModelCreation(
uploaded: uploadedImages uploaded: uploadedImages
}; };
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = getErrorMessage(error); handleError(error, {
logger.error('Ride model image upload failed', { action: 'Upload ride model images',
action: 'ride_model_creation',
error: errorMessage
}); });
throw new Error(`Failed to upload images: ${errorMessage}`); throw new Error(`Failed to upload images: ${error instanceof Error ? error.message : 'Unknown error'}`);
} }
} }
@@ -1110,12 +1102,10 @@ export async function submitManufacturerCreation(
const uploadedImages = await uploadPendingImages(data.images.uploaded); const uploadedImages = await uploadPendingImages(data.images.uploaded);
processedImages = { ...data.images, uploaded: uploadedImages }; processedImages = { ...data.images, uploaded: uploadedImages };
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = getErrorMessage(error); handleError(error, {
logger.error('Company image upload failed', { action: 'Upload manufacturer images',
action: 'manufacturer_creation',
error: errorMessage
}); });
throw new Error(`Failed to upload images: ${errorMessage}`); throw new Error(`Failed to upload images: ${error instanceof Error ? error.message : 'Unknown error'}`);
} }
} }
@@ -1218,12 +1208,10 @@ export async function submitDesignerCreation(
const uploadedImages = await uploadPendingImages(data.images.uploaded); const uploadedImages = await uploadPendingImages(data.images.uploaded);
processedImages = { ...data.images, uploaded: uploadedImages }; processedImages = { ...data.images, uploaded: uploadedImages };
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = getErrorMessage(error); handleError(error, {
logger.error('Company image upload failed', { action: 'Upload designer images',
action: 'designer_creation',
error: errorMessage
}); });
throw new Error(`Failed to upload images: ${errorMessage}`); throw new Error(`Failed to upload images: ${error instanceof Error ? error.message : 'Unknown error'}`);
} }
} }
@@ -1326,12 +1314,10 @@ export async function submitOperatorCreation(
const uploadedImages = await uploadPendingImages(data.images.uploaded); const uploadedImages = await uploadPendingImages(data.images.uploaded);
processedImages = { ...data.images, uploaded: uploadedImages }; processedImages = { ...data.images, uploaded: uploadedImages };
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = getErrorMessage(error); handleError(error, {
logger.error('Company image upload failed', { action: 'Upload operator images',
action: 'operator_creation',
error: errorMessage
}); });
throw new Error(`Failed to upload images: ${errorMessage}`); throw new Error(`Failed to upload images: ${error instanceof Error ? error.message : 'Unknown error'}`);
} }
} }
@@ -1434,12 +1420,10 @@ export async function submitPropertyOwnerCreation(
const uploadedImages = await uploadPendingImages(data.images.uploaded); const uploadedImages = await uploadPendingImages(data.images.uploaded);
processedImages = { ...data.images, uploaded: uploadedImages }; processedImages = { ...data.images, uploaded: uploadedImages };
} catch (error: unknown) { } catch (error: unknown) {
const errorMessage = getErrorMessage(error); handleError(error, {
logger.error('Company image upload failed', { action: 'Upload property owner images',
action: 'property_owner_creation',
error: errorMessage
}); });
throw new Error(`Failed to upload images: ${errorMessage}`); throw new Error(`Failed to upload images: ${error instanceof Error ? error.message : 'Unknown error'}`);
} }
} }
@@ -1602,11 +1586,9 @@ export async function submitTimelineEvent(
}); });
if (error || !submissionId) { if (error || !submissionId) {
const errorMessage = getErrorMessage(error); handleError(error || new Error('No submission ID returned'), {
logger.error('Timeline event submission failed', { action: 'Submit timeline event',
action: 'create_timeline_event',
userId, userId,
error: errorMessage
}); });
throw new Error('Failed to submit timeline event for review'); throw new Error('Failed to submit timeline event for review');
} }
@@ -1679,11 +1661,9 @@ export async function submitTimelineEventUpdate(
); );
if (rpcError || !result) { if (rpcError || !result) {
const errorMessage = getErrorMessage(rpcError); handleError(rpcError || new Error('No result returned'), {
logger.error('Timeline event update failed', { action: 'Update timeline event',
action: 'update_timeline_event', metadata: { eventId },
eventId,
error: errorMessage
}); });
throw new Error('Failed to submit timeline event update'); throw new Error('Failed to submit timeline event update');
} }
@@ -1707,11 +1687,9 @@ export async function deleteTimelineEvent(
.single(); .single();
if (fetchError) { if (fetchError) {
const errorMessage = getErrorMessage(fetchError); handleError(fetchError, {
logger.error('Timeline event fetch failed', { action: 'Delete timeline event',
action: 'delete_timeline_event', metadata: { eventId },
eventId,
error: errorMessage
}); });
throw new Error('Timeline event not found'); throw new Error('Timeline event not found');
} }
@@ -1736,11 +1714,9 @@ export async function deleteTimelineEvent(
.eq('id', eventId); .eq('id', eventId);
if (deleteError) { if (deleteError) {
const errorMessage = getErrorMessage(deleteError); handleError(deleteError, {
logger.error('Timeline event deletion failed', { action: 'Delete timeline event',
action: 'delete_timeline_event', metadata: { eventId },
eventId,
error: errorMessage
}); });
throw new Error('Failed to delete timeline event'); throw new Error('Failed to delete timeline event');
} }