mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-24 05:31:13 -05:00
Refactor: Implement logging and JSONB cleanup
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Analytics } from "@vercel/analytics/react";
|
||||
import { Component, ReactNode } from "react";
|
||||
import { logger } from "@/lib/logger";
|
||||
|
||||
class AnalyticsErrorBoundary extends Component<
|
||||
{ children: ReactNode },
|
||||
@@ -16,7 +17,7 @@ class AnalyticsErrorBoundary extends Component<
|
||||
|
||||
componentDidCatch(error: Error) {
|
||||
// Silently fail - analytics should never break the app
|
||||
console.info('[Analytics] Failed to load, continuing without analytics');
|
||||
logger.info('Analytics failed to load, continuing without analytics', { error: error.message });
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { UserTopList, UserTopListItem, Park, Ride, Company } from "@/types/datab
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { handleError } from "@/lib/errorHandler";
|
||||
|
||||
interface ListDisplayProps {
|
||||
list: UserTopList;
|
||||
@@ -31,7 +32,10 @@ export function ListDisplay({ list }: ListDisplayProps) {
|
||||
.order("position", { ascending: true });
|
||||
|
||||
if (itemsError) {
|
||||
console.error("Error fetching items:", itemsError);
|
||||
handleError(itemsError, {
|
||||
action: 'Fetch List Items',
|
||||
metadata: { listId: list.id }
|
||||
});
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Plus, Trash2, Edit, Eye, EyeOff } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { ListItemEditor } from "./ListItemEditor";
|
||||
import { ListDisplay } from "./ListDisplay";
|
||||
import { handleError } from "@/lib/errorHandler";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -62,8 +63,10 @@ export function UserListManager() {
|
||||
.order("created_at", { ascending: false });
|
||||
|
||||
if (error) {
|
||||
toast.error("Failed to load lists");
|
||||
console.error(error);
|
||||
handleError(error, {
|
||||
action: 'Load User Lists',
|
||||
userId: user.id
|
||||
});
|
||||
} else {
|
||||
// Map Supabase data to UserTopList interface
|
||||
const mappedLists: UserTopList[] = (data || []).map((list: any) => ({
|
||||
@@ -101,8 +104,11 @@ export function UserListManager() {
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
toast.error("Failed to create list");
|
||||
console.error(error);
|
||||
handleError(error, {
|
||||
action: 'Create List',
|
||||
userId: user.id,
|
||||
metadata: { title: newListTitle }
|
||||
});
|
||||
} else {
|
||||
toast.success("List created successfully");
|
||||
const newList: UserTopList = {
|
||||
@@ -132,8 +138,11 @@ export function UserListManager() {
|
||||
.eq("id", listId);
|
||||
|
||||
if (error) {
|
||||
toast.error("Failed to delete list");
|
||||
console.error(error);
|
||||
handleError(error, {
|
||||
action: 'Delete List',
|
||||
userId: user?.id,
|
||||
metadata: { listId }
|
||||
});
|
||||
} else {
|
||||
toast.success("List deleted");
|
||||
setLists(lists.filter(l => l.id !== listId));
|
||||
@@ -147,8 +156,11 @@ export function UserListManager() {
|
||||
.eq("id", list.id);
|
||||
|
||||
if (error) {
|
||||
toast.error("Failed to update list");
|
||||
console.error(error);
|
||||
handleError(error, {
|
||||
action: 'Toggle List Visibility',
|
||||
userId: user?.id,
|
||||
metadata: { listId: list.id }
|
||||
});
|
||||
} else {
|
||||
toast.success(`List is now ${!list.is_public ? "public" : "private"}`);
|
||||
setLists(lists.map(l =>
|
||||
|
||||
@@ -72,7 +72,6 @@ export const QueueItemActions = memo(({
|
||||
() => {
|
||||
// Extra guard against race conditions
|
||||
if (actionLoading === item.id) {
|
||||
console.warn('⚠️ Action already in progress, ignoring duplicate request');
|
||||
return;
|
||||
}
|
||||
onApprove(item, 'approved', notes[item.id]);
|
||||
@@ -84,7 +83,6 @@ export const QueueItemActions = memo(({
|
||||
const handleReject = useDebouncedCallback(
|
||||
() => {
|
||||
if (actionLoading === item.id) {
|
||||
console.warn('⚠️ Action already in progress, ignoring duplicate request');
|
||||
return;
|
||||
}
|
||||
onApprove(item, 'rejected', notes[item.id]);
|
||||
@@ -128,7 +126,6 @@ export const QueueItemActions = memo(({
|
||||
const handleReverseApprove = useDebouncedCallback(
|
||||
() => {
|
||||
if (actionLoading === item.id) {
|
||||
console.warn('⚠️ Action already in progress, ignoring duplicate request');
|
||||
return;
|
||||
}
|
||||
onApprove(item, 'approved', notes[`reverse-${item.id}`]);
|
||||
@@ -140,7 +137,6 @@ export const QueueItemActions = memo(({
|
||||
const handleReverseReject = useDebouncedCallback(
|
||||
() => {
|
||||
if (actionLoading === item.id) {
|
||||
console.warn('⚠️ Action already in progress, ignoring duplicate request');
|
||||
return;
|
||||
}
|
||||
onApprove(item, 'rejected', notes[`reverse-${item.id}`]);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
interface UserAvatarProps {
|
||||
avatarUrl?: string | null;
|
||||
@@ -43,7 +44,7 @@ export function UserAvatar({
|
||||
}, [avatarUrl]);
|
||||
|
||||
const handleImageError = () => {
|
||||
console.warn('[UserAvatar] Image load failed:', imageUrl, 'Retry count:', retryCount);
|
||||
logger.debug('UserAvatar image load failed', { imageUrl, retryCount });
|
||||
|
||||
if (retryCount < MAX_RETRIES && avatarUrl) {
|
||||
// Add cache-busting parameter and retry
|
||||
@@ -52,19 +53,19 @@ export function UserAvatar({
|
||||
? `${avatarUrl}&retry=${retryCount + 1}&t=${Date.now()}`
|
||||
: `${avatarUrl}${cacheBuster}`;
|
||||
|
||||
console.log('[UserAvatar] Retrying with cache buster:', urlWithCacheBuster);
|
||||
logger.debug('UserAvatar retrying with cache buster', { urlWithCacheBuster });
|
||||
setRetryCount(prev => prev + 1);
|
||||
setImageUrl(urlWithCacheBuster);
|
||||
} else {
|
||||
// All retries exhausted, show fallback
|
||||
console.warn('[UserAvatar] All retries exhausted, showing fallback');
|
||||
logger.debug('UserAvatar all retries exhausted, showing fallback');
|
||||
setHasError(true);
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleImageLoad = () => {
|
||||
console.log('[UserAvatar] Image loaded successfully:', imageUrl);
|
||||
logger.debug('UserAvatar image loaded successfully', { imageUrl });
|
||||
setIsLoading(false);
|
||||
setHasError(false);
|
||||
};
|
||||
|
||||
@@ -522,7 +522,6 @@ export function PhotoUpload({
|
||||
alt={`Existing photo ${index + 1}`}
|
||||
className="w-full aspect-square object-cover rounded-lg border"
|
||||
onError={(e) => {
|
||||
console.error('Failed to load existing image:', url);
|
||||
e.currentTarget.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSIjZjNmNGY2Ii8+CjxwYXRoIGQ9Im0xNSAxMi0zLTMtMy4wMDEgM0w2IDlsNi02aDZ2NloiIGZpbGw9IiM5Y2EzYWYiLz4KPC9zdmc+';
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { TechnicalSpecFilter, CoasterStatFilter } from '@/components/search/AdvancedRideFilters';
|
||||
import { useDebounce } from './useDebounce';
|
||||
import { handleError } from '@/lib/errorHandler';
|
||||
|
||||
interface AdvancedSearchOptions {
|
||||
query?: string;
|
||||
@@ -151,7 +152,14 @@ export function useAdvancedRideSearch(options: AdvancedSearchOptions) {
|
||||
|
||||
setResults(filteredResults);
|
||||
} catch (err) {
|
||||
console.error('Advanced search error:', err);
|
||||
handleError(err, {
|
||||
action: 'Advanced Ride Search',
|
||||
metadata: {
|
||||
query: options.query,
|
||||
category: options.category,
|
||||
manufacturer: options.manufacturer
|
||||
}
|
||||
});
|
||||
setError(err instanceof Error ? err.message : 'Search failed');
|
||||
setResults([]);
|
||||
} finally {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useAuth } from '@/hooks/useAuth';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { toast } from '@/hooks/use-toast';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
export function useBanCheck() {
|
||||
const { user } = useAuth();
|
||||
@@ -56,7 +57,7 @@ export function useBanCheck() {
|
||||
navigate('/');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ban check error:', error);
|
||||
logger.error('Ban check error', { error, userId: user.id });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -203,7 +203,6 @@ export function useEntityVersions(entityType: EntityType, entityId: string) {
|
||||
supabase.removeChannel(channelRef.current);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to cleanup realtime subscription', { entityType, entityId, error: getErrorMessage(error) });
|
||||
console.error('Error removing previous channel:', error);
|
||||
} finally {
|
||||
channelRef.current = null;
|
||||
}
|
||||
@@ -236,7 +235,6 @@ export function useEntityVersions(entityType: EntityType, entityId: string) {
|
||||
if (channelRef.current) {
|
||||
supabase.removeChannel(channelRef.current).catch((error) => {
|
||||
logger.error('Failed to cleanup realtime subscription', { entityType, entityId, error: getErrorMessage(error) });
|
||||
console.error('Error removing channel:', error);
|
||||
});
|
||||
channelRef.current = null;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
const STORAGE_KEY = 'queue-filter-panel-collapsed';
|
||||
|
||||
@@ -21,7 +22,7 @@ export function useFilterPanelState(): UseFilterPanelStateReturn {
|
||||
const isMobile = window.innerWidth < 768;
|
||||
return stored ? JSON.parse(stored) : isMobile;
|
||||
} catch (error) {
|
||||
console.error('Error reading filter panel state from localStorage:', error);
|
||||
logger.warn('Error reading filter panel state from localStorage', { error });
|
||||
return window.innerWidth < 768;
|
||||
}
|
||||
});
|
||||
@@ -31,7 +32,7 @@ export function useFilterPanelState(): UseFilterPanelStateReturn {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(isCollapsed));
|
||||
} catch (error) {
|
||||
console.error('Error saving filter panel state to localStorage:', error);
|
||||
logger.warn('Error saving filter panel state to localStorage', { error });
|
||||
}
|
||||
}, [isCollapsed]);
|
||||
|
||||
|
||||
@@ -64,7 +64,6 @@ export function usePhotoSubmissionItems(
|
||||
setPhotos(data || []);
|
||||
} catch (error: unknown) {
|
||||
const errorMsg = getErrorMessage(error);
|
||||
console.error('Error fetching photo submission items:', errorMsg);
|
||||
setError(errorMsg);
|
||||
setPhotos([]);
|
||||
} finally {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { queryKeys } from '@/lib/queryKeys';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
export type UserRole = 'admin' | 'moderator' | 'user' | 'superuser';
|
||||
|
||||
@@ -29,7 +30,7 @@ export function useUserRole() {
|
||||
.eq('user_id', user.id);
|
||||
|
||||
if (error) {
|
||||
console.error('Error fetching user roles:', error);
|
||||
logger.error('Error fetching user roles', { error, userId: user.id });
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -50,7 +51,7 @@ export function useUserRole() {
|
||||
.rpc('get_user_management_permissions', { _user_id: user.id });
|
||||
|
||||
if (error) {
|
||||
console.error('Error fetching user permissions:', error);
|
||||
logger.error('Error fetching user permissions', { error, userId: user.id });
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import type { EntityType, VersionDiff } from '@/types/versioning';
|
||||
import { handleError } from '@/lib/errorHandler';
|
||||
|
||||
/**
|
||||
* Hook to compare two versions of an entity and get the diff
|
||||
@@ -37,7 +38,10 @@ export function useVersionComparison(
|
||||
|
||||
setDiff(data as VersionDiff);
|
||||
} catch (err) {
|
||||
console.error('Error fetching version diff:', err);
|
||||
handleError(err, {
|
||||
action: 'Compare Versions',
|
||||
metadata: { entityType, fromVersionId, toVersionId }
|
||||
});
|
||||
setError(err instanceof Error ? err.message : 'Failed to compare versions');
|
||||
setDiff(null);
|
||||
} finally {
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
/**
|
||||
* Conditional authentication logging utility
|
||||
* Logs are only shown in development mode
|
||||
* Uses structured logger internally
|
||||
*/
|
||||
|
||||
const isDevelopment = import.meta.env.DEV;
|
||||
import { logger } from './logger';
|
||||
|
||||
export const authLog = (...args: any[]) => {
|
||||
if (isDevelopment) {
|
||||
console.log(...args);
|
||||
}
|
||||
export const authLog = (...args: unknown[]) => {
|
||||
logger.info('[Auth]', ...args);
|
||||
};
|
||||
|
||||
export const authWarn = (...args: any[]) => {
|
||||
if (isDevelopment) {
|
||||
console.warn(...args);
|
||||
}
|
||||
export const authWarn = (...args: unknown[]) => {
|
||||
logger.warn('[Auth]', ...args);
|
||||
};
|
||||
|
||||
export const authError = (...args: any[]) => {
|
||||
// Always log errors
|
||||
console.error(...args);
|
||||
export const authError = (...args: unknown[]) => {
|
||||
logger.error('[Auth] Error occurred', { error: args });
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import type { Database } from '@/integrations/supabase/types';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
type TableName = keyof Database['public']['Tables'];
|
||||
|
||||
@@ -78,11 +79,11 @@ export class TestDataTracker {
|
||||
|
||||
if (error) {
|
||||
errors.push({ table, error });
|
||||
console.warn(`Failed to cleanup ${table}:`, error);
|
||||
logger.warn('Failed to cleanup test data table', { table, error });
|
||||
}
|
||||
} catch (err) {
|
||||
errors.push({ table, error: err });
|
||||
console.warn(`Exception cleaning up ${table}:`, err);
|
||||
logger.warn('Exception cleaning up test data table', { table, error: err });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +91,7 @@ export class TestDataTracker {
|
||||
this.entities.clear();
|
||||
|
||||
if (errors.length > 0) {
|
||||
console.warn(`Cleanup completed with ${errors.length} errors:`, errors);
|
||||
logger.warn('Cleanup completed with errors', { errorCount: errors.length, errors });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +117,7 @@ export class TestDataTracker {
|
||||
.eq('is_test_data', true);
|
||||
|
||||
if (error) {
|
||||
console.warn(`Failed to check ${table}:`, error);
|
||||
logger.warn('Failed to check test data table', { table, error });
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -124,7 +125,7 @@ export class TestDataTracker {
|
||||
remaining.push({ table, count });
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(`Exception checking ${table}:`, err);
|
||||
logger.warn('Exception checking test data table', { table, error: err });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,13 +155,13 @@ export class TestDataTracker {
|
||||
.select('id');
|
||||
|
||||
if (error) {
|
||||
console.warn(`Failed to bulk delete from ${table}:`, error);
|
||||
logger.warn('Failed to bulk delete test data', { table, error });
|
||||
totalErrors++;
|
||||
} else if (data) {
|
||||
totalDeleted += data.length;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(`Exception bulk deleting from ${table}:`, err);
|
||||
logger.warn('Exception bulk deleting test data', { table, error: err });
|
||||
totalErrors++;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user