From a649906b61c1efbe4fedbcc7786a550c654fb57c Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 19:58:20 +0000 Subject: [PATCH] feat: Complete app-wide error coverage --- src/lib/moderation/validation.ts | 9 ++++++--- src/lib/submissionMetadataService.ts | 12 +++++++++--- src/lib/testDataGenerator.ts | 12 +++++++++--- src/lib/versioningUtils.ts | 12 +++++++++--- src/lib/viewTracking.ts | 7 +++++-- src/pages/DesignerDetail.tsx | 12 +++++++++--- src/pages/DesignerRides.tsx | 7 +++++-- src/pages/Designers.tsx | 7 +++++-- src/pages/ForceLogout.tsx | 13 +++++-------- src/pages/ManufacturerDetail.tsx | 12 +++++++++--- src/pages/ManufacturerModels.tsx | 7 +++++-- src/pages/ManufacturerRides.tsx | 7 +++++-- src/pages/Manufacturers.tsx | 7 +++++-- src/pages/OperatorDetail.tsx | 2 +- src/pages/OperatorParks.tsx | 2 +- src/pages/OwnerParks.tsx | 2 +- src/pages/ParkRides.tsx | 3 +-- src/pages/Profile.tsx | 3 +-- src/pages/PropertyOwnerDetail.tsx | 2 +- src/pages/RideModelDetail.tsx | 3 +-- src/pages/RideModelRides.tsx | 3 +-- src/pages/admin/AdminContact.tsx | 24 +++++++++++++++++------- 22 files changed, 111 insertions(+), 57 deletions(-) diff --git a/src/lib/moderation/validation.ts b/src/lib/moderation/validation.ts index 7f322f94..6179f385 100644 --- a/src/lib/moderation/validation.ts +++ b/src/lib/moderation/validation.ts @@ -6,7 +6,7 @@ */ import { z } from 'zod'; -import { logger } from '@/lib/logger'; +import { handleError } from '@/lib/errorHandler'; // Profile schema (matches database JSONB structure) const ProfileSchema = z.object({ @@ -101,8 +101,11 @@ export function validateModerationItems(data: unknown): { const result = ModerationItemArraySchema.safeParse(data); if (!result.success) { - logger.error('❌ Data validation failed', { - errors: result.error.issues.slice(0, 5) // Log first 5 issues + handleError(result.error, { + action: 'Data validation failed', + metadata: { + errors: result.error.issues.slice(0, 5) + } }); return { diff --git a/src/lib/submissionMetadataService.ts b/src/lib/submissionMetadataService.ts index 5a750ce6..2efe10e9 100644 --- a/src/lib/submissionMetadataService.ts +++ b/src/lib/submissionMetadataService.ts @@ -5,7 +5,7 @@ */ import { supabase } from '@/lib/supabaseClient'; -import { logger } from './logger'; +import { handleError, handleNonCriticalError } from './errorHandler'; export interface SubmissionMetadataInsert { submission_id: string; @@ -37,7 +37,10 @@ export async function writeSubmissionMetadata( .insert(entries); if (error) { - logger.error('Failed to write submission metadata', { error, submissionId }); + handleError(error, { + action: 'Write submission metadata', + metadata: { submissionId } + }); throw error; } } @@ -56,7 +59,10 @@ export async function readSubmissionMetadata( .order('display_order'); if (error) { - logger.error('Failed to read submission metadata', { error, submissionId }); + handleNonCriticalError(error, { + action: 'Read submission metadata', + metadata: { submissionId } + }); return {}; } diff --git a/src/lib/testDataGenerator.ts b/src/lib/testDataGenerator.ts index 41088a4c..8b8f9b93 100644 --- a/src/lib/testDataGenerator.ts +++ b/src/lib/testDataGenerator.ts @@ -1,6 +1,6 @@ import { supabase } from '@/lib/supabaseClient'; import type { ParkSubmissionData, RideSubmissionData, CompanySubmissionData, RideModelSubmissionData } from '@/types/submission-data'; -import { logger } from './logger'; +import { handleNonCriticalError } from './errorHandler'; import { randomInt, randomFloat, @@ -352,12 +352,18 @@ export async function clearTestData(): Promise<{ deleted: number }> { .neq('id', '00000000-0000-0000-0000-000000000000'); // Delete all records if (registryError) { - logger.error('Error clearing test data registry', { error: registryError }); + handleNonCriticalError(registryError, { + action: 'Clear test data registry', + metadata: { operation: 'clearTestData' } + }); } return { deleted: submissionCount }; } catch (error: unknown) { - logger.error('Error clearing test data', { error: error instanceof Error ? error.message : String(error) }); + handleNonCriticalError(error, { + action: 'Clear test data', + metadata: { operation: 'clearTestData' } + }); throw error; } } diff --git a/src/lib/versioningUtils.ts b/src/lib/versioningUtils.ts index bf4b0ae5..f12c23f7 100644 --- a/src/lib/versioningUtils.ts +++ b/src/lib/versioningUtils.ts @@ -11,7 +11,7 @@ import { supabase } from '@/lib/supabaseClient'; import type { EntityType } from '@/types/versioning'; import { createTableQuery } from './supabaseHelpers'; -import { logger } from './logger'; +import { handleNonCriticalError } from './errorHandler'; /** * Manually trigger cleanup of old versions for a specific entity type @@ -38,7 +38,10 @@ export async function cleanupVersions( }); if (error) { - logger.error('Version cleanup failed', { error, entityType, keepCount }); + handleNonCriticalError(error, { + action: 'Version cleanup', + metadata: { entityType, keepCount } + }); return 0; } @@ -98,7 +101,10 @@ export async function getVersionStats( const { data, error } = result; if (error || !data) { - logger.error('Failed to fetch version stats', { error, entityType, entityId }); + handleNonCriticalError(error || new Error('No data returned'), { + action: 'Fetch version stats', + metadata: { entityType, entityId } + }); return null; } diff --git a/src/lib/viewTracking.ts b/src/lib/viewTracking.ts index 114deb67..39eb7667 100644 --- a/src/lib/viewTracking.ts +++ b/src/lib/viewTracking.ts @@ -1,5 +1,5 @@ import { supabase } from '@/lib/supabaseClient'; -import { logger } from './logger'; +import { handleNonCriticalError } from './errorHandler'; // Generate anonymous session hash (no PII) function getSessionHash(): string { @@ -41,6 +41,9 @@ export async function trackPageView( }); } catch (error: unknown) { // Fail silently - don't break the page if tracking fails - logger.error('Failed to track page view', { entityType, entityId }); + handleNonCriticalError(error, { + action: 'Track page view', + metadata: { entityType, entityId } + }); } } diff --git a/src/pages/DesignerDetail.tsx b/src/pages/DesignerDetail.tsx index 7388f098..3322d61a 100644 --- a/src/pages/DesignerDetail.tsx +++ b/src/pages/DesignerDetail.tsx @@ -12,7 +12,7 @@ import { ArrowLeft, MapPin, Star, Globe, Calendar, Edit, Ruler } from 'lucide-re import { Company } from '@/types/database'; import { supabase } from '@/lib/supabaseClient'; import { DesignerPhotoGallery } from '@/components/companies/DesignerPhotoGallery'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; // Lazy load admin form const DesignerForm = lazy(() => import('@/components/admin/DesignerForm').then(m => ({ default: m.DesignerForm }))); @@ -82,7 +82,10 @@ export default function DesignerDetail() { fetchStatistics(data.id); } } catch (error) { - logger.error('Error fetching designer', { error }); + handleNonCriticalError(error, { + action: 'Fetch designer', + metadata: { slug } + }); } finally { setLoading(false); } @@ -109,7 +112,10 @@ export default function DesignerDetail() { if (photosError) throw photosError; setTotalPhotos(photosCount || 0); } catch (error) { - logger.error('Error fetching statistics', { error }); + handleNonCriticalError(error, { + action: 'Fetch designer statistics', + metadata: { designerId } + }); } finally { setStatsLoading(false); } diff --git a/src/pages/DesignerRides.tsx b/src/pages/DesignerRides.tsx index da25c5fc..b7d3f4a3 100644 --- a/src/pages/DesignerRides.tsx +++ b/src/pages/DesignerRides.tsx @@ -17,7 +17,7 @@ import { toast } from '@/hooks/use-toast'; import { useAuthModal } from '@/hooks/useAuthModal'; import { useDocumentTitle } from '@/hooks/useDocumentTitle'; import { useOpenGraph } from '@/hooks/useOpenGraph'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; export default function DesignerRides() { const { designerSlug } = useParams<{ designerSlug: string }>(); @@ -91,7 +91,10 @@ export default function DesignerRides() { setRides((ridesData || []) as any); } } catch (error) { - logger.error('Error fetching data', { error }); + handleNonCriticalError(error, { + action: 'Fetch designer rides', + metadata: { designerSlug } + }); } finally { setLoading(false); } diff --git a/src/pages/Designers.tsx b/src/pages/Designers.tsx index 1e93f423..6c9dcf60 100644 --- a/src/pages/Designers.tsx +++ b/src/pages/Designers.tsx @@ -18,7 +18,7 @@ import { DesignerCard } from '@/components/designers/DesignerCard'; import { DesignerListView } from '@/components/designers/DesignerListView'; import { DesignerForm } from '@/components/admin/DesignerForm'; import { useAuth } from '@/hooks/useAuth'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; import { useUserRole } from '@/hooks/useUserRole'; import { toast } from '@/hooks/use-toast'; import { submitCompanyCreation } from '@/lib/companyHelpers'; @@ -89,7 +89,10 @@ export default function Designers() { const { data } = await query; setCompanies(data || []); } catch (error) { - logger.error('Error fetching companies', { error }); + handleNonCriticalError(error, { + action: 'Fetch designers', + metadata: { page: 'designers' } + }); } finally { setLoading(false); } diff --git a/src/pages/ForceLogout.tsx b/src/pages/ForceLogout.tsx index 8c5ae72a..ab845ac8 100644 --- a/src/pages/ForceLogout.tsx +++ b/src/pages/ForceLogout.tsx @@ -3,7 +3,7 @@ import { useNavigate } from "react-router-dom"; import { supabase } from "@/lib/supabaseClient"; import { authStorage } from "@/lib/authStorage"; import { useDocumentTitle } from '@/hooks/useDocumentTitle'; -import { logger } from '@/lib/logger'; +import { handleError } from '@/lib/errorHandler'; /** * ForceLogout - Hidden endpoint for completely clearing auth session @@ -16,26 +16,23 @@ const ForceLogout = () => { useEffect(() => { const performFullLogout = async () => { - logger.info('[ForceLogout] Starting complete auth cleanup'); - try { // 1. Sign out from Supabase - logger.info('[ForceLogout] Signing out from Supabase'); await supabase.auth.signOut(); // 2. Clear all auth-related storage - logger.info('[ForceLogout] Clearing all auth storage'); authStorage.clearAll(); // 3. Brief delay to ensure cleanup completes await new Promise(resolve => setTimeout(resolve, 500)); - logger.info('[ForceLogout] Auth cleanup complete, redirecting to home'); - // 4. Redirect to home page navigate('/', { replace: true }); } catch (error) { - logger.error('[ForceLogout] Error during logout', { error }); + handleError(error, { + action: 'Force logout', + metadata: { operation: 'forceLogout' } + }); // Still redirect even if there's an error navigate('/', { replace: true }); } diff --git a/src/pages/ManufacturerDetail.tsx b/src/pages/ManufacturerDetail.tsx index 93f1a6b6..c2e3f449 100644 --- a/src/pages/ManufacturerDetail.tsx +++ b/src/pages/ManufacturerDetail.tsx @@ -13,7 +13,7 @@ import { ArrowLeft, MapPin, Star, Globe, Calendar, Edit, Factory, FerrisWheel } import { Company } from '@/types/database'; import { supabase } from '@/lib/supabaseClient'; import { ManufacturerPhotoGallery } from '@/components/companies/ManufacturerPhotoGallery'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; // Lazy load admin form const ManufacturerForm = lazy(() => import('@/components/admin/ManufacturerForm').then(m => ({ default: m.ManufacturerForm }))); @@ -83,7 +83,10 @@ export default function ManufacturerDetail() { fetchStatistics(data.id); } } catch (error) { - logger.error('Error fetching manufacturer', { error }); + handleNonCriticalError(error, { + action: 'Fetch manufacturer', + metadata: { slug } + }); } finally { setLoading(false); } @@ -119,7 +122,10 @@ export default function ManufacturerDetail() { if (photosError) throw photosError; setTotalPhotos(photosCount || 0); } catch (error) { - logger.error('Error fetching statistics', { error }); + handleNonCriticalError(error, { + action: 'Fetch manufacturer statistics', + metadata: { manufacturerId } + }); } finally { setStatsLoading(false); } diff --git a/src/pages/ManufacturerModels.tsx b/src/pages/ManufacturerModels.tsx index 47df5947..0fd9da3e 100644 --- a/src/pages/ManufacturerModels.tsx +++ b/src/pages/ManufacturerModels.tsx @@ -17,7 +17,7 @@ import { toast } from '@/hooks/use-toast'; import { useAuthModal } from '@/hooks/useAuthModal'; import { useDocumentTitle } from '@/hooks/useDocumentTitle'; import { useOpenGraph } from '@/hooks/useOpenGraph'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; interface RideModelWithCount extends RideModel { ride_count: number; @@ -86,7 +86,10 @@ export default function ManufacturerModels() { setModels(modelsWithCounts); } } catch (error) { - logger.error('Error fetching data', { error }); + handleNonCriticalError(error, { + action: 'Fetch manufacturer models', + metadata: { manufacturerSlug } + }); } finally { setLoading(false); } diff --git a/src/pages/ManufacturerRides.tsx b/src/pages/ManufacturerRides.tsx index ab5343d6..d5a48997 100644 --- a/src/pages/ManufacturerRides.tsx +++ b/src/pages/ManufacturerRides.tsx @@ -17,7 +17,7 @@ import { toast } from '@/hooks/use-toast'; import { useAuthModal } from '@/hooks/useAuthModal'; import { useDocumentTitle } from '@/hooks/useDocumentTitle'; import { useOpenGraph } from '@/hooks/useOpenGraph'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; export default function ManufacturerRides() { const { manufacturerSlug } = useParams<{ manufacturerSlug: string }>(); @@ -91,7 +91,10 @@ export default function ManufacturerRides() { setRides((ridesData || []) as any); } } catch (error) { - logger.error('Error fetching data', { error }); + handleNonCriticalError(error, { + action: 'Fetch manufacturer rides', + metadata: { manufacturerSlug } + }); } finally { setLoading(false); } diff --git a/src/pages/Manufacturers.tsx b/src/pages/Manufacturers.tsx index 4d7cd319..c38d4713 100644 --- a/src/pages/Manufacturers.tsx +++ b/src/pages/Manufacturers.tsx @@ -18,7 +18,7 @@ import { ManufacturerCard } from '@/components/manufacturers/ManufacturerCard'; import { ManufacturerListView } from '@/components/manufacturers/ManufacturerListView'; import { ManufacturerForm } from '@/components/admin/ManufacturerForm'; import { useAuth } from '@/hooks/useAuth'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; import { useUserRole } from '@/hooks/useUserRole'; import { toast } from '@/hooks/use-toast'; import { submitCompanyCreation } from '@/lib/companyHelpers'; @@ -76,7 +76,10 @@ export default function Manufacturers() { const { data } = await query; setCompanies(data || []); } catch (error) { - logger.error('Error fetching companies', { error }); + handleNonCriticalError(error, { + action: 'Fetch manufacturers', + metadata: { page: 'manufacturers' } + }); } finally { setLoading(false); } diff --git a/src/pages/OperatorDetail.tsx b/src/pages/OperatorDetail.tsx index bbe846e3..bf96fbc2 100644 --- a/src/pages/OperatorDetail.tsx +++ b/src/pages/OperatorDetail.tsx @@ -14,7 +14,7 @@ import { Company, Park } from '@/types/database'; import { supabase } from '@/lib/supabaseClient'; import { OperatorPhotoGallery } from '@/components/companies/OperatorPhotoGallery'; import { ParkCard } from '@/components/parks/ParkCard'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; // Lazy load admin form const OperatorForm = lazy(() => import('@/components/admin/OperatorForm').then(m => ({ default: m.OperatorForm }))); diff --git a/src/pages/OperatorParks.tsx b/src/pages/OperatorParks.tsx index a6a4effd..72321562 100644 --- a/src/pages/OperatorParks.tsx +++ b/src/pages/OperatorParks.tsx @@ -17,7 +17,7 @@ import { Grid3X3, List } from 'lucide-react'; import { FilterState, SortState } from './Parks'; import { useDocumentTitle } from '@/hooks/useDocumentTitle'; import { useOpenGraph } from '@/hooks/useOpenGraph'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; const initialFilters: FilterState = { search: '', diff --git a/src/pages/OwnerParks.tsx b/src/pages/OwnerParks.tsx index e48c4358..64fb7cda 100644 --- a/src/pages/OwnerParks.tsx +++ b/src/pages/OwnerParks.tsx @@ -17,7 +17,7 @@ import { Grid3X3, List } from 'lucide-react'; import { FilterState, SortState } from './Parks'; import { useDocumentTitle } from '@/hooks/useDocumentTitle'; import { useOpenGraph } from '@/hooks/useOpenGraph'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; const initialFilters: FilterState = { search: '', diff --git a/src/pages/ParkRides.tsx b/src/pages/ParkRides.tsx index 733457a9..8e6e3b77 100644 --- a/src/pages/ParkRides.tsx +++ b/src/pages/ParkRides.tsx @@ -14,8 +14,7 @@ import { RideSubmissionData } from '@/types/submission-data'; import { supabase } from '@/lib/supabaseClient'; import { useAuth } from '@/hooks/useAuth'; import { toast } from '@/hooks/use-toast'; -import { getErrorMessage } from '@/lib/errorHandler'; -import { logger } from '@/lib/logger'; +import { getErrorMessage, handleNonCriticalError } from '@/lib/errorHandler'; import { useAuthModal } from '@/hooks/useAuthModal'; import { useDocumentTitle } from '@/hooks/useDocumentTitle'; import { useOpenGraph } from '@/hooks/useOpenGraph'; diff --git a/src/pages/Profile.tsx b/src/pages/Profile.tsx index 005e3bb2..bca61b57 100644 --- a/src/pages/Profile.tsx +++ b/src/pages/Profile.tsx @@ -23,8 +23,7 @@ import { User, MapPin, Calendar, Star, Trophy, Settings, Camera, Edit3, Save, X, import { Profile as ProfileType } from '@/types/database'; import { supabase } from '@/lib/supabaseClient'; import { useToast } from '@/hooks/use-toast'; -import { logger } from '@/lib/logger'; -import { getErrorMessage } from '@/lib/errorHandler'; +import { getErrorMessage, handleNonCriticalError } from '@/lib/errorHandler'; import { PhotoUpload } from '@/components/upload/PhotoUpload'; import { profileEditSchema } from '@/lib/validation'; import { LocationDisplay } from '@/components/profile/LocationDisplay'; diff --git a/src/pages/PropertyOwnerDetail.tsx b/src/pages/PropertyOwnerDetail.tsx index 18b7a2e8..17ac1794 100644 --- a/src/pages/PropertyOwnerDetail.tsx +++ b/src/pages/PropertyOwnerDetail.tsx @@ -14,7 +14,7 @@ import { Company, Park } from '@/types/database'; import { supabase } from '@/lib/supabaseClient'; import { PropertyOwnerPhotoGallery } from '@/components/companies/PropertyOwnerPhotoGallery'; import { ParkCard } from '@/components/parks/ParkCard'; -import { logger } from '@/lib/logger'; +import { handleNonCriticalError } from '@/lib/errorHandler'; // Lazy load admin form const PropertyOwnerForm = lazy(() => import('@/components/admin/PropertyOwnerForm').then(m => ({ default: m.PropertyOwnerForm }))); diff --git a/src/pages/RideModelDetail.tsx b/src/pages/RideModelDetail.tsx index 3e6dcf9d..4f2121c0 100644 --- a/src/pages/RideModelDetail.tsx +++ b/src/pages/RideModelDetail.tsx @@ -15,8 +15,7 @@ import { getCloudflareImageUrl } from '@/lib/cloudflareImageUtils'; import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuth } from '@/hooks/useAuth'; import { toast } from '@/hooks/use-toast'; -import { getErrorMessage } from '@/lib/errorHandler'; -import { logger } from '@/lib/logger'; +import { getErrorMessage, handleNonCriticalError } from '@/lib/errorHandler'; import { ManufacturerPhotoGallery } from '@/components/companies/ManufacturerPhotoGallery'; // Lazy load admin form diff --git a/src/pages/RideModelRides.tsx b/src/pages/RideModelRides.tsx index 8df7ede3..9cc14e4e 100644 --- a/src/pages/RideModelRides.tsx +++ b/src/pages/RideModelRides.tsx @@ -14,8 +14,7 @@ import { RideForm } from '@/components/admin/RideForm'; import { useAuth } from '@/hooks/useAuth'; import { useAuthModal } from '@/hooks/useAuthModal'; import { toast } from '@/hooks/use-toast'; -import { getErrorMessage } from '@/lib/errorHandler'; -import { logger } from '@/lib/logger'; +import { getErrorMessage, handleNonCriticalError } from '@/lib/errorHandler'; import type { Ride, Company, RideModel } from "@/types/database"; import { useDocumentTitle } from '@/hooks/useDocumentTitle'; diff --git a/src/pages/admin/AdminContact.tsx b/src/pages/admin/AdminContact.tsx index a2977f59..2c3432c0 100644 --- a/src/pages/admin/AdminContact.tsx +++ b/src/pages/admin/AdminContact.tsx @@ -75,8 +75,7 @@ import { DialogFooter } from '@/components/ui/dialog'; import { useTheme } from '@/components/theme/ThemeProvider'; import { useUserRole } from '@/hooks/useUserRole'; import { useDocumentTitle } from '@/hooks/useDocumentTitle'; -import { handleError, handleSuccess } from '@/lib/errorHandler'; -import { logger } from '@/lib/logger'; +import { handleError, handleSuccess, handleNonCriticalError } from '@/lib/errorHandler'; import { contactCategories } from '@/lib/contactValidation'; import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { AdminLayout } from '@/components/layout/AdminLayout'; @@ -199,7 +198,10 @@ export default function AdminContact() { const { data, error } = await query; if (error) { - logger.error('Failed to fetch contact submissions', { error: error.message }); + handleNonCriticalError(error, { + action: 'Fetch contact submissions', + metadata: { error: error.message } + }); throw error; } @@ -219,7 +221,10 @@ export default function AdminContact() { .order('created_at', { ascending: true }) .then(({ data, error }) => { if (error) { - logger.error('Failed to fetch email threads', { error }); + handleNonCriticalError(error, { + action: 'Fetch email threads', + metadata: { submissionId: selectedSubmission.id } + }); setEmailThreads([]); } else { setEmailThreads((data as EmailThread[]) || []); @@ -263,7 +268,10 @@ export default function AdminContact() { .eq('id', submissionId); if (statusError) { - logger.error('Failed to update status', { error: statusError }); + handleError(statusError, { + action: 'Update contact status', + metadata: { submissionId, newStatus } + }); throw statusError; } } @@ -465,8 +473,10 @@ export default function AdminContact() { .order('created_at', { ascending: true }) .then(({ data, error }) => { if (error) { - logger.error('Failed to refresh email threads', { error }); - handleError(error, { action: 'Refresh Email Threads' }); + handleError(error, { + action: 'Refresh Email Threads', + metadata: { submissionId: selectedSubmission.id } + }); } else { setEmailThreads((data as EmailThread[]) || []); handleSuccess('Refreshed', 'Email thread updated');