Refactor: Implement full error logging

This commit is contained in:
gpt-engineer-app[bot]
2025-11-04 19:11:24 +00:00
parent 6e64b80106
commit e74c2acbd4
11 changed files with 48 additions and 186 deletions

View File

@@ -5,7 +5,7 @@ import { Label } from '@/components/ui/label';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Alert, AlertDescription } from '@/components/ui/alert'; import { Alert, AlertDescription } from '@/components/ui/alert';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { handleError, handleSuccess, handleInfo, AppError, getErrorMessage } from '@/lib/errorHandler'; import { handleError, handleSuccess, handleInfo, handleNonCriticalError, AppError, getErrorMessage } from '@/lib/errorHandler';
import { logger } from '@/lib/logger'; import { logger } from '@/lib/logger';
import { useAuth } from '@/hooks/useAuth'; import { useAuth } from '@/hooks/useAuth';
import { useRequireMFA } from '@/hooks/useRequireMFA'; import { useRequireMFA } from '@/hooks/useRequireMFA';
@@ -51,10 +51,10 @@ export function TOTPSetup() {
})); }));
setFactors(totpFactors); setFactors(totpFactors);
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Failed to fetch TOTP factors', { handleNonCriticalError(error, {
action: 'Fetch TOTP factors',
userId: user?.id, userId: user?.id,
action: 'fetch_totp_factors', metadata: { context: 'initial_load' }
error: getErrorMessage(error)
}); });
} }
}; };
@@ -76,11 +76,6 @@ export function TOTPSetup() {
setFactorId(data.id); setFactorId(data.id);
setEnrolling(true); setEnrolling(true);
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Failed to start TOTP enrollment', {
userId: user?.id,
action: 'totp_enroll_start',
error: getErrorMessage(error)
});
handleError( handleError(
new AppError( new AppError(
getErrorMessage(error) || 'Failed to start TOTP enrollment', getErrorMessage(error) || 'Failed to start TOTP enrollment',
@@ -148,13 +143,6 @@ export function TOTPSetup() {
}, 2000); }, 2000);
} }
} catch (error: unknown) { } catch (error: unknown) {
logger.error('TOTP verification failed', {
userId: user?.id,
action: 'totp_verify',
error: getErrorMessage(error),
factorId
});
handleError( handleError(
new AppError( new AppError(
getErrorMessage(error) || 'Invalid verification code. Please try again.', getErrorMessage(error) || 'Invalid verification code. Please try again.',

View File

@@ -148,13 +148,7 @@ export function ContactForm() {
setCaptchaToken(''); setCaptchaToken('');
setCaptchaKey((prev) => prev + 1); setCaptchaKey((prev) => prev + 1);
logger.info('Contact form submitted successfully', {
submissionId: result?.submissionId,
});
} catch (error) { } catch (error) {
logger.error('Failed to submit contact form', {
error: error instanceof Error ? error.message : String(error),
});
handleError(error, { handleError(error, {
action: 'submit_contact_form', action: 'submit_contact_form',
metadata: { category: data.category }, metadata: { category: data.category },

View File

@@ -12,8 +12,7 @@ import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { handleError, handleSuccess, getErrorMessage } from '@/lib/errorHandler'; import { handleError, handleSuccess, handleNonCriticalError, getErrorMessage } from '@/lib/errorHandler';
import { logger } from '@/lib/logger';
interface UserProfile { interface UserProfile {
id: string; id: string;
@@ -131,7 +130,13 @@ export function ProfileManager() {
} }
}); });
if (logError) logger.error('Failed to log admin action', { error: getErrorMessage(logError) }); if (logError) {
handleNonCriticalError(logError, {
action: 'Log admin action (ban/unban)',
userId: user?.id,
metadata: { targetUserId, ban, banReason }
});
}
handleSuccess( handleSuccess(
'Success', 'Success',
@@ -211,7 +216,13 @@ export function ProfileManager() {
_details: { role: newRole, previous_roles: currentRoles } _details: { role: newRole, previous_roles: currentRoles }
}); });
if (logError) logger.error('Failed to log admin action', { error: getErrorMessage(logError) }); if (logError) {
handleNonCriticalError(logError, {
action: 'Log admin action (role change)',
userId: user?.id,
metadata: { targetUserId, newRole, previousRoles: currentRoles }
});
}
handleSuccess('Success', 'User role updated successfully.'); handleSuccess('Success', 'User role updated successfully.');

View File

@@ -23,7 +23,7 @@ import { useAdminSettings } from '@/hooks/useAdminSettings';
import { useAuth } from '@/hooks/useAuth'; import { useAuth } from '@/hooks/useAuth';
import { useIsMobile } from '@/hooks/use-mobile'; import { useIsMobile } from '@/hooks/use-mobile';
import { smartMergeArray } from '@/lib/smartStateUpdate'; import { smartMergeArray } from '@/lib/smartStateUpdate';
import { handleError, handleSuccess } from '@/lib/errorHandler'; import { handleError, handleSuccess, handleNonCriticalError } from '@/lib/errorHandler';
// Type-safe reported content interfaces // Type-safe reported content interfaces
interface ReportedReview { interface ReportedReview {
@@ -383,7 +383,11 @@ export const ReportsQueue = forwardRef<ReportsQueueRef>((props, ref) => {
} }
}); });
} catch (auditError) { } catch (auditError) {
logger.error('Failed to log report action audit', { error: auditError }); handleNonCriticalError(auditError, {
action: 'Log report action audit',
userId: user?.id,
metadata: { reportId, action }
});
} }
} }

View File

@@ -32,12 +32,6 @@ export function BlockedUsers() {
.order('created_at', { ascending: false }); .order('created_at', { ascending: false });
if (blocksError) { if (blocksError) {
logger.error('Failed to fetch user blocks', {
userId: user.id,
action: 'fetch_blocked_users',
error: blocksError.message,
errorCode: blocksError.code
});
throw blocksError; throw blocksError;
} }
@@ -54,12 +48,6 @@ export function BlockedUsers() {
.in('user_id', blockedIds); .in('user_id', blockedIds);
if (profilesError) { if (profilesError) {
logger.error('Failed to fetch blocked user profiles', {
userId: user.id,
action: 'fetch_blocked_user_profiles',
error: profilesError.message,
errorCode: profilesError.code
});
throw profilesError; throw profilesError;
} }
@@ -73,18 +61,7 @@ export function BlockedUsers() {
setBlockedUsers(blockedUsersWithProfiles as UserBlock[]); setBlockedUsers(blockedUsersWithProfiles as UserBlock[]);
logger.info('Blocked users fetched successfully', {
userId: user.id,
action: 'fetch_blocked_users',
count: blockedUsersWithProfiles.length
});
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Error fetching blocked users', {
userId: user.id,
action: 'fetch_blocked_users',
error: error instanceof Error ? error.message : String(error)
});
handleError(error, { handleError(error, {
action: 'Load blocked users', action: 'Load blocked users',
userId: user.id userId: user.id
@@ -104,13 +81,6 @@ export function BlockedUsers() {
.eq('id', blockId); .eq('id', blockId);
if (error) { if (error) {
logger.error('Failed to unblock user', {
userId: user.id,
action: 'unblock_user',
targetUserId: blockedUserId,
error: error.message,
errorCode: error.code
});
throw error; throw error;
} }
@@ -128,21 +98,8 @@ export function BlockedUsers() {
setBlockedUsers(prev => prev.filter(block => block.id !== blockId)); setBlockedUsers(prev => prev.filter(block => block.id !== blockId));
logger.info('User unblocked successfully', {
userId: user.id,
action: 'unblock_user',
targetUserId: blockedUserId
});
handleSuccess('User unblocked', `You have unblocked @${username}`); handleSuccess('User unblocked', `You have unblocked @${username}`);
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Error unblocking user', {
userId: user.id,
action: 'unblock_user',
targetUserId: blockedUserId,
error: error instanceof Error ? error.message : String(error)
});
handleError(error, { handleError(error, {
action: 'Unblock user', action: 'Unblock user',
userId: user.id, userId: user.id,

View File

@@ -15,8 +15,7 @@ import { toast } from '@/hooks/use-toast';
import { PhotoUpload } from '@/components/upload/PhotoUpload'; import { PhotoUpload } from '@/components/upload/PhotoUpload';
import { StarRating } from './StarRating'; import { StarRating } from './StarRating';
import { toDateOnly, parseDateOnly } from '@/lib/dateUtils'; import { toDateOnly, parseDateOnly } from '@/lib/dateUtils';
import { getErrorMessage } from '@/lib/errorHandler'; import { getErrorMessage, handleNonCriticalError } from '@/lib/errorHandler';
import { logger } from '@/lib/logger';
const reviewSchema = z.object({ const reviewSchema = z.object({
rating: z.number().min(0.5).max(5).multipleOf(0.5), rating: z.number().min(0.5).max(5).multipleOf(0.5),
title: z.string().optional(), title: z.string().optional(),
@@ -109,7 +108,11 @@ export function ReviewForm({
.insert(photoRecords); .insert(photoRecords);
if (photosError) { if (photosError) {
logger.error('Failed to insert review photos', { error: getErrorMessage(photosError) }); handleNonCriticalError(photosError, {
action: 'Insert review photos',
userId: user?.id,
metadata: { reviewId: review.id, photoCount: photos.length }
});
// Don't throw - review is already created // Don't throw - review is already created
} }
} }

View File

@@ -6,8 +6,7 @@ import { Star, ThumbsUp, Calendar, MapPin } from 'lucide-react';
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { ReportButton } from '@/components/moderation/ReportButton'; import { ReportButton } from '@/components/moderation/ReportButton';
import { StarRating } from './StarRating'; import { StarRating } from './StarRating';
import { getErrorMessage } from '@/lib/errorHandler'; import { getErrorMessage, handleNonCriticalError } from '@/lib/errorHandler';
import { logger } from '@/lib/logger';
interface ReviewWithProfile { interface ReviewWithProfile {
id: string; id: string;
@@ -65,7 +64,10 @@ export function ReviewsList({ entityType, entityId, entityName }: ReviewsListPro
const { data } = await query; const { data } = await query;
setReviews((data || []) as ReviewWithProfile[]); setReviews((data || []) as ReviewWithProfile[]);
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Failed to fetch reviews', { error: getErrorMessage(error), entityType, entityId }); handleNonCriticalError(error, {
action: 'Fetch reviews',
metadata: { entityType, entityId }
});
} finally { } finally {
setLoading(false); setLoading(false);
} }

View File

@@ -9,8 +9,7 @@ import { Label } from '@/components/ui/label';
import { useAuth } from '@/hooks/useAuth'; import { useAuth } from '@/hooks/useAuth';
import { useProfile } from '@/hooks/useProfile'; import { useProfile } from '@/hooks/useProfile';
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { handleError, handleSuccess, AppError } from '@/lib/errorHandler'; import { handleError, handleSuccess, handleNonCriticalError, AppError } from '@/lib/errorHandler';
import { logger } from '@/lib/logger';
import { Download, Activity, BarChart3, AlertCircle, Clock } from 'lucide-react'; import { Download, Activity, BarChart3, AlertCircle, Clock } from 'lucide-react';
import type { import type {
UserStatistics, UserStatistics,

View File

@@ -14,8 +14,7 @@ import { useAuth } from '@/hooks/useAuth';
import { useProfile } from '@/hooks/useProfile'; import { useProfile } from '@/hooks/useProfile';
import { useUnitPreferences } from '@/hooks/useUnitPreferences'; import { useUnitPreferences } from '@/hooks/useUnitPreferences';
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { handleError, handleSuccess, AppError } from '@/lib/errorHandler'; import { handleError, handleSuccess, handleNonCriticalError, AppError } from '@/lib/errorHandler';
import { logger } from '@/lib/logger';
import { MapPin, Calendar, Accessibility, Ruler } from 'lucide-react'; import { MapPin, Calendar, Accessibility, Ruler } from 'lucide-react';
import type { LocationFormData, AccessibilityOptions, ParkOption } from '@/types/location'; import type { LocationFormData, AccessibilityOptions, ParkOption } from '@/types/location';
import { import {
@@ -75,12 +74,6 @@ export function LocationTab() {
.order('name'); .order('name');
if (error) { if (error) {
logger.error('Failed to fetch parks list', {
userId: user.id,
action: 'fetch_parks',
error: error.message,
errorCode: error.code
});
throw error; throw error;
} }
@@ -198,12 +191,6 @@ export function LocationTab() {
.eq('user_id', user.id); .eq('user_id', user.id);
if (profileError) { if (profileError) {
logger.error('Failed to update profile', {
userId: user.id,
action: 'update_profile_location',
error: profileError.message,
errorCode: profileError.code
});
throw profileError; throw profileError;
} }
@@ -216,12 +203,6 @@ export function LocationTab() {
.eq('user_id', user.id); .eq('user_id', user.id);
if (accessibilityError) { if (accessibilityError) {
logger.error('Failed to update accessibility preferences', {
userId: user.id,
action: 'update_accessibility_preferences',
error: accessibilityError.message,
errorCode: accessibilityError.code
});
throw accessibilityError; throw accessibilityError;
} }
@@ -246,22 +227,11 @@ export function LocationTab() {
await refreshProfile(); await refreshProfile();
logger.info('Location and info settings updated', {
userId: user.id,
action: 'update_location_info'
});
handleSuccess( handleSuccess(
'Settings saved', 'Settings saved',
'Your location, personal information, accessibility, and unit preferences have been updated.' 'Your location, personal information, accessibility, and unit preferences have been updated.'
); );
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Error saving location settings', {
userId: user.id,
action: 'save_location_settings',
error: error instanceof Error ? error.message : String(error)
});
if (error instanceof z.ZodError) { if (error instanceof z.ZodError) {
handleError( handleError(
new AppError( new AppError(

View File

@@ -9,8 +9,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
import { Separator } from "@/components/ui/separator"; import { Separator } from "@/components/ui/separator";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/components/ui/skeleton";
import { handleError, handleSuccess, handleInfo } from "@/lib/errorHandler"; import { handleError, handleSuccess, handleInfo, handleNonCriticalError } from "@/lib/errorHandler";
import { logger } from "@/lib/logger";
import { notificationService } from "@/lib/notificationService"; import { notificationService } from "@/lib/notificationService";
import type { import type {
NotificationPreferences, NotificationPreferences,
@@ -53,18 +52,7 @@ export function NotificationsTab() {
setWorkflowPreferences(preferences.workflowPreferences); setWorkflowPreferences(preferences.workflowPreferences);
setFrequencySettings(preferences.frequencySettings); setFrequencySettings(preferences.frequencySettings);
} }
logger.info('Notification preferences loaded', {
action: 'load_notification_preferences',
userId: user.id
});
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Failed to load notification preferences', {
action: 'load_notification_preferences',
userId: user.id,
error: error instanceof Error ? error.message : String(error)
});
handleError(error, { handleError(error, {
action: 'Load notification preferences', action: 'Load notification preferences',
userId: user.id userId: user.id
@@ -92,20 +80,8 @@ export function NotificationsTab() {
if (Object.keys(initialPrefs).length > 0) { if (Object.keys(initialPrefs).length > 0) {
setWorkflowPreferences((prev) => ({ ...prev, ...initialPrefs })); setWorkflowPreferences((prev) => ({ ...prev, ...initialPrefs }));
} }
logger.info('Notification templates loaded', {
action: 'load_notification_templates',
userId: user.id,
count: templateData.length
});
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Failed to load notification templates', { handleNonCriticalError(error, {
action: 'load_notification_templates',
userId: user.id,
error: error instanceof Error ? error.message : String(error)
});
handleError(error, {
action: 'Load notification templates', action: 'Load notification templates',
userId: user.id userId: user.id
}); });
@@ -185,12 +161,6 @@ export function NotificationsTab() {
); );
} }
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Error requesting push permission', {
action: 'request_push_permission',
userId: user?.id,
error: error instanceof Error ? error.message : String(error)
});
handleError(error, { handleError(error, {
action: 'Enable push notifications', action: 'Enable push notifications',
userId: user?.id userId: user?.id

View File

@@ -13,7 +13,7 @@ import {
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import { handleError, handleSuccess, AppError, getErrorMessage } from '@/lib/errorHandler'; import { handleError, handleSuccess, handleNonCriticalError, AppError, getErrorMessage } from '@/lib/errorHandler';
import { logger } from '@/lib/logger'; import { logger } from '@/lib/logger';
import { supabase } from '@/lib/supabaseClient'; import { supabase } from '@/lib/supabaseClient';
import { Loader2, Shield, CheckCircle2 } from 'lucide-react'; import { Loader2, Shield, CheckCircle2 } from 'lucide-react';
@@ -82,9 +82,10 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
const hasVerifiedTotp = data?.totp?.some(factor => factor.status === 'verified') || false; const hasVerifiedTotp = data?.totp?.some(factor => factor.status === 'verified') || false;
setHasMFA(hasVerifiedTotp); setHasMFA(hasVerifiedTotp);
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Failed to check MFA status', { handleNonCriticalError(error, {
action: 'check_mfa_status', action: 'Check MFA status',
error: error instanceof Error ? error.message : String(error) userId,
metadata: { context: 'password_change_dialog' }
}); });
} }
}; };
@@ -142,13 +143,6 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
setCaptchaToken(''); setCaptchaToken('');
setCaptchaKey(prev => prev + 1); setCaptchaKey(prev => prev + 1);
logger.error('Password authentication failed', {
userId,
action: 'password_change_auth',
error: signInError.message,
errorCode: signInError.code
});
throw signInError; throw signInError;
} }
@@ -169,18 +163,6 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
await updatePasswordWithNonce(data.newPassword, generatedNonce); await updatePasswordWithNonce(data.newPassword, generatedNonce);
} }
} catch (error: unknown) { } catch (error: unknown) {
const errorDetails = isErrorWithCode(error) ? {
errorCode: error.code,
errorStatus: error.status
} : {};
logger.error('Password change failed', {
userId,
action: 'password_change',
error: getErrorMessage(error),
...errorDetails
});
const errorMessage = getErrorMessage(error); const errorMessage = getErrorMessage(error);
const errorStatus = isErrorWithCode(error) ? error.status : undefined; const errorStatus = isErrorWithCode(error) ? error.status : undefined;
@@ -238,12 +220,6 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
}); });
if (challengeError) { if (challengeError) {
logger.error('MFA challenge creation failed', {
userId,
action: 'password_change_mfa_challenge',
error: challengeError.message,
errorCode: challengeError.code
});
throw challengeError; throw challengeError;
} }
@@ -255,24 +231,12 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
}); });
if (verifyError) { if (verifyError) {
logger.error('MFA verification failed', {
userId,
action: 'password_change_mfa',
error: verifyError.message,
errorCode: verifyError.code
});
throw verifyError; throw verifyError;
} }
// TOTP verified, now update password // TOTP verified, now update password
await updatePasswordWithNonce(newPassword, nonce); await updatePasswordWithNonce(newPassword, nonce);
} catch (error: unknown) { } catch (error: unknown) {
logger.error('MFA verification failed', {
userId,
action: 'password_change_mfa',
error: getErrorMessage(error)
});
handleError( handleError(
new AppError( new AppError(
getErrorMessage(error) || 'Invalid authentication code', getErrorMessage(error) || 'Invalid authentication code',
@@ -325,10 +289,10 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
user.id user.id
); );
} catch (notifError) { } catch (notifError) {
logger.error('Failed to send password change notification', { handleNonCriticalError(notifError, {
action: 'Send password change notification',
userId: user!.id, userId: user!.id,
action: 'password_change_notification', metadata: { context: 'post_password_change' }
error: getErrorMessage(notifError)
}); });
// Don't fail the password update if notification fails // Don't fail the password update if notification fails
} }