Refactor: Implement logging and JSONB cleanup

This commit is contained in:
gpt-engineer-app[bot]
2025-11-03 18:05:58 +00:00
parent b6179372e6
commit e9b9faa3e1
18 changed files with 430 additions and 142 deletions

View File

@@ -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() {

View File

@@ -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;
}

View File

@@ -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 =>

View File

@@ -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}`]);

View File

@@ -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);
};

View File

@@ -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+';
}}
/>