mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-28 02:47:04 -05:00
Compare commits
3 Commits
6e64b80106
...
9bf5ea322e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bf5ea322e | ||
|
|
3d646ec6f7 | ||
|
|
e74c2acbd4 |
@@ -4,7 +4,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Search, Edit, MapPin, Loader2, X } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { handleNonCriticalError } from '@/lib/errorHandler';
|
||||
|
||||
interface LocationResult {
|
||||
place_id: number;
|
||||
@@ -65,7 +65,10 @@ export function HeadquartersLocationInput({
|
||||
setShowResults(true);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error searching locations', { error });
|
||||
handleNonCriticalError(error, {
|
||||
action: 'Search headquarters locations',
|
||||
metadata: { query: searchQuery }
|
||||
});
|
||||
} finally {
|
||||
setIsSearching(false);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import { useSuperuserGuard } from '@/hooks/useSuperuserGuard';
|
||||
import { IntegrationTestRunner as TestRunner, allTestSuites, type TestResult } from '@/lib/integrationTests';
|
||||
import { Play, Square, Download, ChevronDown, CheckCircle2, XCircle, Clock, SkipForward } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { handleError } from '@/lib/errorHandler';
|
||||
|
||||
export function IntegrationTestRunner() {
|
||||
const superuserGuard = useSuperuserGuard();
|
||||
@@ -67,8 +67,11 @@ export function IntegrationTestRunner() {
|
||||
} else {
|
||||
toast.success(`All ${summary.passed} tests passed!`);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Test run error', { error });
|
||||
} catch (error: unknown) {
|
||||
handleError(error, {
|
||||
action: 'Run integration tests',
|
||||
metadata: { suitesCount: suitesToRun.length }
|
||||
});
|
||||
toast.error('Test run failed');
|
||||
} finally {
|
||||
setIsRunning(false);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { MapPin, Loader2, X } from 'lucide-react';
|
||||
import { ParkLocationMap } from '@/components/maps/ParkLocationMap';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { handleNonCriticalError } from '@/lib/errorHandler';
|
||||
|
||||
interface LocationResult {
|
||||
place_id: number;
|
||||
@@ -102,7 +102,6 @@ export function LocationSearch({ onLocationSelect, initialLocationId, className
|
||||
// Check if response is OK and content-type is JSON
|
||||
if (!response.ok) {
|
||||
const errorMsg = `Location search failed (${response.status}). Please try again.`;
|
||||
logger.error('OpenStreetMap API error', { status: response.status });
|
||||
setSearchError(errorMsg);
|
||||
setResults([]);
|
||||
setShowResults(false);
|
||||
@@ -112,7 +111,6 @@ export function LocationSearch({ onLocationSelect, initialLocationId, className
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (!contentType || !contentType.includes('application/json')) {
|
||||
const errorMsg = 'Invalid response from location service. Please try again.';
|
||||
logger.error('Invalid response format from OpenStreetMap', { contentType });
|
||||
setSearchError(errorMsg);
|
||||
setResults([]);
|
||||
setShowResults(false);
|
||||
@@ -123,8 +121,11 @@ export function LocationSearch({ onLocationSelect, initialLocationId, className
|
||||
setResults(data);
|
||||
setShowResults(true);
|
||||
setSearchError(null);
|
||||
} catch {
|
||||
logger.error('Location search failed', { query: searchQuery });
|
||||
} catch (error: unknown) {
|
||||
handleNonCriticalError(error, {
|
||||
action: 'Search locations',
|
||||
metadata: { query: searchQuery }
|
||||
});
|
||||
setSearchError('Failed to search locations. Please check your connection.');
|
||||
setResults([]);
|
||||
setShowResults(false);
|
||||
|
||||
@@ -35,8 +35,7 @@ import { getCloudflareImageUrl } from '@/lib/cloudflareImageUtils';
|
||||
import { useAutoSave } from '@/hooks/useAutoSave';
|
||||
import { CheckCircle2, Loader2, AlertCircle } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { handleError } from '@/lib/errorHandler';
|
||||
|
||||
interface MarkdownEditorProps {
|
||||
value: string;
|
||||
@@ -157,7 +156,10 @@ export function MarkdownEditor({
|
||||
|
||||
return imageUrl;
|
||||
} catch (error: unknown) {
|
||||
logger.error('Image upload failed', { error: getErrorMessage(error) });
|
||||
handleError(error, {
|
||||
action: 'Upload markdown image',
|
||||
metadata: { fileName: file.name }
|
||||
});
|
||||
throw new Error(error instanceof Error ? error.message : 'Failed to upload image');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@
|
||||
import { AlertTriangle, CheckCircle, RefreshCw, Loader2 } from 'lucide-react';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { format } from 'date-fns';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { handleNonCriticalError } from '@/lib/errorHandler';
|
||||
|
||||
interface DuplicateStats {
|
||||
date: string | null;
|
||||
@@ -86,8 +86,10 @@ export function NotificationDebugPanel() {
|
||||
profiles: profileMap.get(dup.user_id)
|
||||
})));
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to load notification debug data', { error });
|
||||
} catch (error: unknown) {
|
||||
handleNonCriticalError(error, {
|
||||
action: 'Load notification debug data'
|
||||
});
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ import {
|
||||
SubmissionWorkflowDetails
|
||||
} from '@/lib/systemActivityService';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
export interface SystemActivityLogRef {
|
||||
refresh: () => Promise<void>;
|
||||
@@ -194,7 +193,7 @@ export const SystemActivityLog = forwardRef<SystemActivityLogRef, SystemActivity
|
||||
});
|
||||
setActivities(data);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to load system activities', { error: getErrorMessage(error) });
|
||||
// Activity load failed - display empty list
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
setIsRefreshing(false);
|
||||
|
||||
@@ -15,7 +15,7 @@ import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { Beaker, CheckCircle, ChevronDown, Trash2, AlertTriangle } from 'lucide-react';
|
||||
import { clearTestData, getTestDataStats } from '@/lib/testDataGenerator';
|
||||
import { TestDataTracker } from '@/lib/integrationTests/TestDataTracker';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { handleNonCriticalError } from '@/lib/errorHandler';
|
||||
import { useMFAStepUp } from '@/contexts/MFAStepUpContext';
|
||||
import { isMFACancelledError } from '@/lib/aalErrorDetection';
|
||||
|
||||
@@ -94,7 +94,9 @@ export function TestDataGenerator(): React.JSX.Element {
|
||||
const data = await getTestDataStats();
|
||||
setStats(data);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to load test data stats', { error: getErrorMessage(error) });
|
||||
handleNonCriticalError(error, {
|
||||
action: 'Load test data stats'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Loader2, Trash2, CheckCircle, AlertCircle } from 'lucide-react';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { format } from 'date-fns';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { handleNonCriticalError } from '@/lib/errorHandler';
|
||||
|
||||
export function VersionCleanupSettings() {
|
||||
const [retentionDays, setRetentionDays] = useState(90);
|
||||
@@ -52,8 +52,10 @@ export function VersionCleanupSettings() {
|
||||
: String(cleanup.setting_value);
|
||||
setLastCleanup(cleanupValue);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to load settings', { error });
|
||||
} catch (error: unknown) {
|
||||
handleNonCriticalError(error, {
|
||||
action: 'Load version cleanup settings'
|
||||
});
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'Failed to load cleanup settings',
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Label } from '@/components/ui/label';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
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 { useAuth } from '@/hooks/useAuth';
|
||||
import { useRequireMFA } from '@/hooks/useRequireMFA';
|
||||
@@ -51,10 +51,10 @@ export function TOTPSetup() {
|
||||
}));
|
||||
setFactors(totpFactors);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to fetch TOTP factors', {
|
||||
handleNonCriticalError(error, {
|
||||
action: 'Fetch TOTP factors',
|
||||
userId: user?.id,
|
||||
action: 'fetch_totp_factors',
|
||||
error: getErrorMessage(error)
|
||||
metadata: { context: 'initial_load' }
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -76,11 +76,6 @@ export function TOTPSetup() {
|
||||
setFactorId(data.id);
|
||||
setEnrolling(true);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to start TOTP enrollment', {
|
||||
userId: user?.id,
|
||||
action: 'totp_enroll_start',
|
||||
error: getErrorMessage(error)
|
||||
});
|
||||
handleError(
|
||||
new AppError(
|
||||
getErrorMessage(error) || 'Failed to start TOTP enrollment',
|
||||
@@ -148,13 +143,6 @@ export function TOTPSetup() {
|
||||
}, 2000);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
logger.error('TOTP verification failed', {
|
||||
userId: user?.id,
|
||||
action: 'totp_verify',
|
||||
error: getErrorMessage(error),
|
||||
factorId
|
||||
});
|
||||
|
||||
handleError(
|
||||
new AppError(
|
||||
getErrorMessage(error) || 'Invalid verification code. Please try again.',
|
||||
|
||||
@@ -148,13 +148,7 @@ export function ContactForm() {
|
||||
setCaptchaToken('');
|
||||
setCaptchaKey((prev) => prev + 1);
|
||||
|
||||
logger.info('Contact form submitted successfully', {
|
||||
submissionId: result?.submissionId,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Failed to submit contact form', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
handleError(error, {
|
||||
action: 'submit_contact_form',
|
||||
metadata: { category: data.category },
|
||||
|
||||
@@ -6,7 +6,6 @@ import { Button } from '@/components/ui/button';
|
||||
import { Park } from '@/types/database';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
export function FeaturedParks() {
|
||||
const [topRatedParks, setTopRatedParks] = useState<Park[]>([]);
|
||||
@@ -44,7 +43,7 @@ export function FeaturedParks() {
|
||||
setTopRatedParks(topRated || []);
|
||||
setMostRidesParks(mostRides || []);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to fetch featured parks', { error: getErrorMessage(error) });
|
||||
// Featured parks fetch failed - display empty sections
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -96,7 +96,11 @@ export function ItemEditDialog({ item, items, open, onOpenChange, onComplete }:
|
||||
|
||||
const handlePhotoSubmit = async (caption: string, credit: string) => {
|
||||
if (!item?.item_data) {
|
||||
logger.error('No item data available for photo submission');
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: 'No photo data available',
|
||||
variant: 'destructive',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { handleError, handleSuccess, getErrorMessage } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { handleError, handleSuccess, handleNonCriticalError, getErrorMessage } from '@/lib/errorHandler';
|
||||
|
||||
interface UserProfile {
|
||||
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(
|
||||
'Success',
|
||||
@@ -211,7 +216,13 @@ export function ProfileManager() {
|
||||
_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.');
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import { useAdminSettings } from '@/hooks/useAdminSettings';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useIsMobile } from '@/hooks/use-mobile';
|
||||
import { smartMergeArray } from '@/lib/smartStateUpdate';
|
||||
import { handleError, handleSuccess } from '@/lib/errorHandler';
|
||||
import { handleError, handleSuccess, handleNonCriticalError } from '@/lib/errorHandler';
|
||||
|
||||
// Type-safe reported content interfaces
|
||||
interface ReportedReview {
|
||||
@@ -383,7 +383,11 @@ export const ReportsQueue = forwardRef<ReportsQueueRef>((props, ref) => {
|
||||
}
|
||||
});
|
||||
} 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 }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@ import { AlertCircle, Loader2 } from 'lucide-react';
|
||||
import { format } from 'date-fns';
|
||||
import type { SubmissionItemData } from '@/types/submissions';
|
||||
import type { ParkSubmissionData, RideSubmissionData, CompanySubmissionData, RideModelSubmissionData } from '@/types/submission-data';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { getErrorMessage, handleNonCriticalError } from '@/lib/errorHandler';
|
||||
import { ModerationErrorBoundary } from '@/components/error/ModerationErrorBoundary';
|
||||
|
||||
interface SubmissionItemsListProps {
|
||||
@@ -71,13 +70,19 @@ export const SubmissionItemsList = memo(function SubmissionItemsList({
|
||||
.eq('submission_id', submissionId);
|
||||
|
||||
if (photoError) {
|
||||
logger.warn('Error checking photo submissions:', photoError);
|
||||
handleNonCriticalError(photoError, {
|
||||
action: 'Check photo submissions',
|
||||
metadata: { submissionId }
|
||||
});
|
||||
}
|
||||
|
||||
setItems(transformedItems as SubmissionItemData[]);
|
||||
setHasPhotos(!!(photoData && photoData.length > 0));
|
||||
} catch (err) {
|
||||
logger.error('Failed to fetch submission items', { error: getErrorMessage(err) });
|
||||
handleNonCriticalError(err, {
|
||||
action: 'Fetch submission items',
|
||||
metadata: { submissionId }
|
||||
});
|
||||
setError('Failed to load submission details');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
|
||||
@@ -439,7 +439,11 @@ export function SubmissionReviewManager({
|
||||
);
|
||||
|
||||
if (error) {
|
||||
logger.error('Edge function failed', { error: getErrorMessage(error) });
|
||||
handleError(error, {
|
||||
action: 'Send escalation notification',
|
||||
userId: user.id,
|
||||
metadata: { submissionId }
|
||||
});
|
||||
// Fallback to direct database update if email fails
|
||||
await escalateSubmission(submissionId, reason, user.id);
|
||||
toast({
|
||||
|
||||
@@ -5,7 +5,7 @@ import { RefreshButton } from '@/components/ui/refresh-button';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
|
||||
import { validateEntityData, ValidationResult } from '@/lib/entityValidationSchemas';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { handleNonCriticalError } from '@/lib/errorHandler';
|
||||
|
||||
import type { SubmissionItemData } from '@/types/moderation';
|
||||
|
||||
@@ -92,10 +92,9 @@ export function ValidationSummary({ item, onValidationChange, compact = false, v
|
||||
setValidationResult(result);
|
||||
onValidationChange?.(result);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Entity validation failed', {
|
||||
action: 'validate_entity',
|
||||
entityType: item.item_type,
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
handleNonCriticalError(error, {
|
||||
action: 'Validate entity',
|
||||
metadata: { entityType: item.item_type }
|
||||
});
|
||||
setValidationResult({
|
||||
isValid: false,
|
||||
|
||||
@@ -9,7 +9,6 @@ import { ParkCard } from './ParkCard';
|
||||
import { Park } from '@/types/database';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
export function ParkGrid() {
|
||||
const [parks, setParks] = useState<Park[]>([]);
|
||||
@@ -43,7 +42,7 @@ export function ParkGrid() {
|
||||
if (error) throw error;
|
||||
setParks(data || []);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to fetch featured parks', { error: getErrorMessage(error) });
|
||||
// Parks fetch failed - display empty grid
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -32,12 +32,6 @@ export function BlockedUsers() {
|
||||
.order('created_at', { ascending: false });
|
||||
|
||||
if (blocksError) {
|
||||
logger.error('Failed to fetch user blocks', {
|
||||
userId: user.id,
|
||||
action: 'fetch_blocked_users',
|
||||
error: blocksError.message,
|
||||
errorCode: blocksError.code
|
||||
});
|
||||
throw blocksError;
|
||||
}
|
||||
|
||||
@@ -54,12 +48,6 @@ export function BlockedUsers() {
|
||||
.in('user_id', blockedIds);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -73,18 +61,7 @@ export function BlockedUsers() {
|
||||
|
||||
setBlockedUsers(blockedUsersWithProfiles as UserBlock[]);
|
||||
|
||||
logger.info('Blocked users fetched successfully', {
|
||||
userId: user.id,
|
||||
action: 'fetch_blocked_users',
|
||||
count: blockedUsersWithProfiles.length
|
||||
});
|
||||
} 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, {
|
||||
action: 'Load blocked users',
|
||||
userId: user.id
|
||||
@@ -104,13 +81,6 @@ export function BlockedUsers() {
|
||||
.eq('id', blockId);
|
||||
|
||||
if (error) {
|
||||
logger.error('Failed to unblock user', {
|
||||
userId: user.id,
|
||||
action: 'unblock_user',
|
||||
targetUserId: blockedUserId,
|
||||
error: error.message,
|
||||
errorCode: error.code
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -128,21 +98,8 @@ export function BlockedUsers() {
|
||||
|
||||
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}`);
|
||||
} 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, {
|
||||
action: 'Unblock user',
|
||||
userId: user.id,
|
||||
|
||||
@@ -15,8 +15,7 @@ import { toast } from '@/hooks/use-toast';
|
||||
import { PhotoUpload } from '@/components/upload/PhotoUpload';
|
||||
import { StarRating } from './StarRating';
|
||||
import { toDateOnly, parseDateOnly } from '@/lib/dateUtils';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { getErrorMessage, handleNonCriticalError } from '@/lib/errorHandler';
|
||||
const reviewSchema = z.object({
|
||||
rating: z.number().min(0.5).max(5).multipleOf(0.5),
|
||||
title: z.string().optional(),
|
||||
@@ -109,7 +108,11 @@ export function ReviewForm({
|
||||
.insert(photoRecords);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@ import { Star, ThumbsUp, Calendar, MapPin } from 'lucide-react';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { ReportButton } from '@/components/moderation/ReportButton';
|
||||
import { StarRating } from './StarRating';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { getErrorMessage, handleNonCriticalError } from '@/lib/errorHandler';
|
||||
|
||||
interface ReviewWithProfile {
|
||||
id: string;
|
||||
@@ -65,7 +64,10 @@ export function ReviewsList({ entityType, entityId, entityName }: ReviewsListPro
|
||||
const { data } = await query;
|
||||
setReviews((data || []) as ReviewWithProfile[]);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to fetch reviews', { error: getErrorMessage(error), entityType, entityId });
|
||||
handleNonCriticalError(error, {
|
||||
action: 'Fetch reviews',
|
||||
metadata: { entityType, entityId }
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ import { Label } from '@/components/ui/label';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useProfile } from '@/hooks/useProfile';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { handleError, handleSuccess, AppError } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { handleError, handleSuccess, handleNonCriticalError, AppError } from '@/lib/errorHandler';
|
||||
import { Download, Activity, BarChart3, AlertCircle, Clock } from 'lucide-react';
|
||||
import type {
|
||||
UserStatistics,
|
||||
@@ -74,18 +73,7 @@ export function DataExportTab() {
|
||||
};
|
||||
|
||||
setStatistics(stats);
|
||||
|
||||
logger.info('User statistics loaded', {
|
||||
userId: user.id,
|
||||
action: 'load_statistics'
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to load statistics', {
|
||||
userId: user.id,
|
||||
action: 'load_statistics',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
|
||||
handleError(error, {
|
||||
action: 'Load statistics',
|
||||
userId: user.id
|
||||
@@ -113,12 +101,6 @@ export function DataExportTab() {
|
||||
.limit(10);
|
||||
|
||||
if (error) {
|
||||
logger.error('Failed to load activity log', {
|
||||
userId: user.id,
|
||||
action: 'load_activity_log',
|
||||
error: error.message,
|
||||
errorCode: error.code
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -146,19 +128,7 @@ export function DataExportTab() {
|
||||
});
|
||||
|
||||
setRecentActivity(activityData);
|
||||
|
||||
logger.info('Activity log loaded', {
|
||||
userId: user.id,
|
||||
action: 'load_activity_log',
|
||||
count: activityData.length
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error loading activity log', {
|
||||
userId: user.id,
|
||||
action: 'load_activity_log',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
|
||||
handleError(error, {
|
||||
action: 'Load activity log',
|
||||
userId: user.id
|
||||
@@ -177,12 +147,6 @@ export function DataExportTab() {
|
||||
// Validate export options
|
||||
const validatedOptions = exportOptionsSchema.parse(exportOptions);
|
||||
|
||||
logger.info('Starting data export', {
|
||||
userId: user.id,
|
||||
action: 'export_data',
|
||||
options: validatedOptions
|
||||
});
|
||||
|
||||
// Call edge function for secure export
|
||||
const { data, error, requestId } = await invokeWithTracking<ExportRequestResult>(
|
||||
'export-user-data',
|
||||
@@ -191,11 +155,6 @@ export function DataExportTab() {
|
||||
);
|
||||
|
||||
if (error) {
|
||||
logger.error('Edge function invocation failed', {
|
||||
userId: user.id,
|
||||
action: 'export_data',
|
||||
error: error.message
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -204,12 +163,6 @@ export function DataExportTab() {
|
||||
setRateLimited(true);
|
||||
setNextAvailableAt(data.next_available_at || null);
|
||||
|
||||
logger.warn('Export rate limited', {
|
||||
userId: user.id,
|
||||
action: 'export_data',
|
||||
nextAvailableAt: data.next_available_at
|
||||
});
|
||||
|
||||
handleError(
|
||||
new AppError(
|
||||
'Rate limited',
|
||||
@@ -237,12 +190,6 @@ export function DataExportTab() {
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
logger.info('Data export completed', {
|
||||
userId: user.id,
|
||||
action: 'export_data',
|
||||
dataSize: JSON.stringify(data.data).length
|
||||
});
|
||||
|
||||
handleSuccess(
|
||||
'Data exported successfully',
|
||||
'Your data has been downloaded as a JSON file.'
|
||||
@@ -251,12 +198,6 @@ export function DataExportTab() {
|
||||
// Refresh activity log to show the export action
|
||||
await loadRecentActivity();
|
||||
} catch (error: unknown) {
|
||||
logger.error('Data export failed', {
|
||||
userId: user.id,
|
||||
action: 'export_data',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
|
||||
handleError(error, {
|
||||
action: 'Export data',
|
||||
userId: user.id
|
||||
|
||||
@@ -14,8 +14,7 @@ import { useAuth } from '@/hooks/useAuth';
|
||||
import { useProfile } from '@/hooks/useProfile';
|
||||
import { useUnitPreferences } from '@/hooks/useUnitPreferences';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { handleError, handleSuccess, AppError } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { handleError, handleSuccess, handleNonCriticalError, AppError } from '@/lib/errorHandler';
|
||||
import { MapPin, Calendar, Accessibility, Ruler } from 'lucide-react';
|
||||
import type { LocationFormData, AccessibilityOptions, ParkOption } from '@/types/location';
|
||||
import {
|
||||
@@ -75,12 +74,6 @@ export function LocationTab() {
|
||||
.order('name');
|
||||
|
||||
if (error) {
|
||||
logger.error('Failed to fetch parks list', {
|
||||
userId: user.id,
|
||||
action: 'fetch_parks',
|
||||
error: error.message,
|
||||
errorCode: error.code
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -103,19 +96,7 @@ export function LocationTab() {
|
||||
.filter((park): park is ParkOption => park !== null);
|
||||
|
||||
setParks(validatedParks);
|
||||
|
||||
logger.info('Parks list loaded', {
|
||||
userId: user.id,
|
||||
action: 'fetch_parks',
|
||||
count: validatedParks.length
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error fetching parks', {
|
||||
userId: user.id,
|
||||
action: 'fetch_parks',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
|
||||
handleError(error, {
|
||||
action: 'Load parks list',
|
||||
userId: user.id
|
||||
@@ -134,12 +115,6 @@ export function LocationTab() {
|
||||
.maybeSingle();
|
||||
|
||||
if (error && error.code !== 'PGRST116') {
|
||||
logger.error('Failed to fetch accessibility preferences', {
|
||||
userId: user.id,
|
||||
action: 'fetch_accessibility_preferences',
|
||||
error: error.message,
|
||||
errorCode: error.code
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -147,18 +122,7 @@ export function LocationTab() {
|
||||
const validated = accessibilityOptionsSchema.parse(data.accessibility_options);
|
||||
setAccessibility(validated);
|
||||
}
|
||||
|
||||
logger.info('Accessibility preferences loaded', {
|
||||
userId: user.id,
|
||||
action: 'fetch_accessibility_preferences'
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error fetching accessibility preferences', {
|
||||
userId: user.id,
|
||||
action: 'fetch_accessibility_preferences',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
|
||||
handleError(error, {
|
||||
action: 'Load accessibility preferences',
|
||||
userId: user.id
|
||||
@@ -198,12 +162,6 @@ export function LocationTab() {
|
||||
.eq('user_id', user.id);
|
||||
|
||||
if (profileError) {
|
||||
logger.error('Failed to update profile', {
|
||||
userId: user.id,
|
||||
action: 'update_profile_location',
|
||||
error: profileError.message,
|
||||
errorCode: profileError.code
|
||||
});
|
||||
throw profileError;
|
||||
}
|
||||
|
||||
@@ -216,12 +174,6 @@ export function LocationTab() {
|
||||
.eq('user_id', user.id);
|
||||
|
||||
if (accessibilityError) {
|
||||
logger.error('Failed to update accessibility preferences', {
|
||||
userId: user.id,
|
||||
action: 'update_accessibility_preferences',
|
||||
error: accessibilityError.message,
|
||||
errorCode: accessibilityError.code
|
||||
});
|
||||
throw accessibilityError;
|
||||
}
|
||||
|
||||
@@ -246,22 +198,11 @@ export function LocationTab() {
|
||||
|
||||
await refreshProfile();
|
||||
|
||||
logger.info('Location and info settings updated', {
|
||||
userId: user.id,
|
||||
action: 'update_location_info'
|
||||
});
|
||||
|
||||
handleSuccess(
|
||||
'Settings saved',
|
||||
'Your location, personal information, accessibility, and unit preferences have been updated.'
|
||||
);
|
||||
} 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) {
|
||||
handleError(
|
||||
new AppError(
|
||||
|
||||
@@ -9,8 +9,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { handleError, handleSuccess, handleInfo } from "@/lib/errorHandler";
|
||||
import { logger } from "@/lib/logger";
|
||||
import { handleError, handleSuccess, handleInfo, handleNonCriticalError } from "@/lib/errorHandler";
|
||||
import { notificationService } from "@/lib/notificationService";
|
||||
import type {
|
||||
NotificationPreferences,
|
||||
@@ -53,18 +52,7 @@ export function NotificationsTab() {
|
||||
setWorkflowPreferences(preferences.workflowPreferences);
|
||||
setFrequencySettings(preferences.frequencySettings);
|
||||
}
|
||||
|
||||
logger.info('Notification preferences loaded', {
|
||||
action: 'load_notification_preferences',
|
||||
userId: user.id
|
||||
});
|
||||
} 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, {
|
||||
action: 'Load notification preferences',
|
||||
userId: user.id
|
||||
@@ -92,20 +80,8 @@ export function NotificationsTab() {
|
||||
if (Object.keys(initialPrefs).length > 0) {
|
||||
setWorkflowPreferences((prev) => ({ ...prev, ...initialPrefs }));
|
||||
}
|
||||
|
||||
logger.info('Notification templates loaded', {
|
||||
action: 'load_notification_templates',
|
||||
userId: user.id,
|
||||
count: templateData.length
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to load notification templates', {
|
||||
action: 'load_notification_templates',
|
||||
userId: user.id,
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
|
||||
handleError(error, {
|
||||
handleNonCriticalError(error, {
|
||||
action: 'Load notification templates',
|
||||
userId: user.id
|
||||
});
|
||||
@@ -130,22 +106,11 @@ export function NotificationsTab() {
|
||||
throw new Error(result.error || 'Failed to save notification preferences');
|
||||
}
|
||||
|
||||
logger.info('Notification preferences saved', {
|
||||
action: 'save_notification_preferences',
|
||||
userId: user.id
|
||||
});
|
||||
|
||||
handleSuccess(
|
||||
'Notification preferences saved',
|
||||
'Your notification settings have been updated successfully.'
|
||||
);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error saving notification preferences', {
|
||||
action: 'save_notification_preferences',
|
||||
userId: user.id,
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
|
||||
handleError(error, {
|
||||
action: 'Save notification preferences',
|
||||
userId: user.id
|
||||
@@ -185,12 +150,6 @@ export function NotificationsTab() {
|
||||
);
|
||||
}
|
||||
} 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, {
|
||||
action: 'Enable push notifications',
|
||||
userId: user?.id
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
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 { supabase } from '@/lib/supabaseClient';
|
||||
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;
|
||||
setHasMFA(hasVerifiedTotp);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to check MFA status', {
|
||||
action: 'check_mfa_status',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
handleNonCriticalError(error, {
|
||||
action: 'Check MFA status',
|
||||
userId,
|
||||
metadata: { context: 'password_change_dialog' }
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -142,13 +143,6 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
|
||||
setCaptchaToken('');
|
||||
setCaptchaKey(prev => prev + 1);
|
||||
|
||||
logger.error('Password authentication failed', {
|
||||
userId,
|
||||
action: 'password_change_auth',
|
||||
error: signInError.message,
|
||||
errorCode: signInError.code
|
||||
});
|
||||
|
||||
throw signInError;
|
||||
}
|
||||
|
||||
@@ -169,18 +163,6 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
|
||||
await updatePasswordWithNonce(data.newPassword, generatedNonce);
|
||||
}
|
||||
} 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 errorStatus = isErrorWithCode(error) ? error.status : undefined;
|
||||
|
||||
@@ -238,12 +220,6 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
|
||||
});
|
||||
|
||||
if (challengeError) {
|
||||
logger.error('MFA challenge creation failed', {
|
||||
userId,
|
||||
action: 'password_change_mfa_challenge',
|
||||
error: challengeError.message,
|
||||
errorCode: challengeError.code
|
||||
});
|
||||
throw challengeError;
|
||||
}
|
||||
|
||||
@@ -255,24 +231,12 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
|
||||
});
|
||||
|
||||
if (verifyError) {
|
||||
logger.error('MFA verification failed', {
|
||||
userId,
|
||||
action: 'password_change_mfa',
|
||||
error: verifyError.message,
|
||||
errorCode: verifyError.code
|
||||
});
|
||||
throw verifyError;
|
||||
}
|
||||
|
||||
// TOTP verified, now update password
|
||||
await updatePasswordWithNonce(newPassword, nonce);
|
||||
} catch (error: unknown) {
|
||||
logger.error('MFA verification failed', {
|
||||
userId,
|
||||
action: 'password_change_mfa',
|
||||
error: getErrorMessage(error)
|
||||
});
|
||||
|
||||
handleError(
|
||||
new AppError(
|
||||
getErrorMessage(error) || 'Invalid authentication code',
|
||||
@@ -325,10 +289,10 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
|
||||
user.id
|
||||
);
|
||||
} catch (notifError) {
|
||||
logger.error('Failed to send password change notification', {
|
||||
handleNonCriticalError(notifError, {
|
||||
action: 'Send password change notification',
|
||||
userId: user!.id,
|
||||
action: 'password_change_notification',
|
||||
error: getErrorMessage(notifError)
|
||||
metadata: { context: 'post_password_change' }
|
||||
});
|
||||
// Don't fail the password update if notification fails
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { handleError, handleSuccess, AppError } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { useProfile } from '@/hooks/useProfile';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
@@ -50,12 +49,6 @@ export function PrivacyTab() {
|
||||
.maybeSingle();
|
||||
|
||||
if (error && error.code !== 'PGRST116') {
|
||||
logger.error('Failed to fetch privacy preferences', {
|
||||
userId: user.id,
|
||||
action: 'fetch_privacy_preferences',
|
||||
error: error.message,
|
||||
errorCode: error.code
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -72,19 +65,12 @@ export function PrivacyTab() {
|
||||
...parseResult.data
|
||||
});
|
||||
} else {
|
||||
logger.warn('Invalid privacy settings, reinitializing with defaults');
|
||||
await initializePreferences();
|
||||
}
|
||||
} else {
|
||||
await initializePreferences();
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error fetching privacy preferences', {
|
||||
userId: user.id,
|
||||
action: 'fetch_privacy_preferences',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
|
||||
handleError(error, {
|
||||
action: 'Load privacy settings',
|
||||
userId: user.id
|
||||
@@ -104,11 +90,6 @@ export function PrivacyTab() {
|
||||
}]);
|
||||
|
||||
if (error) {
|
||||
logger.error('Failed to initialize privacy preferences', {
|
||||
userId: user.id,
|
||||
action: 'initialize_privacy_preferences',
|
||||
error: error.message
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -121,12 +102,6 @@ export function PrivacyTab() {
|
||||
...DEFAULT_PRIVACY_SETTINGS
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
logger.error('Error initializing privacy preferences', {
|
||||
userId: user.id,
|
||||
action: 'initialize_privacy_preferences',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
|
||||
handleError(error, {
|
||||
action: 'Initialize privacy settings',
|
||||
userId: user.id
|
||||
@@ -154,12 +129,6 @@ export function PrivacyTab() {
|
||||
.eq('user_id', user.id);
|
||||
|
||||
if (profileError) {
|
||||
logger.error('Failed to update profile privacy', {
|
||||
userId: user.id,
|
||||
action: 'update_profile_privacy',
|
||||
error: profileError.message,
|
||||
errorCode: profileError.code
|
||||
});
|
||||
throw profileError;
|
||||
}
|
||||
|
||||
@@ -176,12 +145,6 @@ export function PrivacyTab() {
|
||||
}]);
|
||||
|
||||
if (prefsError) {
|
||||
logger.error('Failed to update privacy preferences', {
|
||||
userId: user.id,
|
||||
action: 'update_privacy_preferences',
|
||||
error: prefsError.message,
|
||||
errorCode: prefsError.code
|
||||
});
|
||||
throw prefsError;
|
||||
}
|
||||
|
||||
@@ -200,22 +163,11 @@ export function PrivacyTab() {
|
||||
await refreshProfile();
|
||||
setPreferences(privacySettings);
|
||||
|
||||
logger.info('Privacy settings updated successfully', {
|
||||
userId: user.id,
|
||||
action: 'update_privacy_settings'
|
||||
});
|
||||
|
||||
handleSuccess(
|
||||
'Privacy settings updated',
|
||||
'Your privacy preferences have been successfully saved.'
|
||||
);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to update privacy settings', {
|
||||
userId: user.id,
|
||||
action: 'update_privacy_settings',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
|
||||
if (error instanceof z.ZodError) {
|
||||
handleError(
|
||||
new AppError(
|
||||
|
||||
@@ -24,7 +24,6 @@ import {
|
||||
import type { UserIdentity, OAuthProvider } from '@/types/identity';
|
||||
import type { AuthSession } from '@/types/auth';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { logger } from '@/lib/logger';
|
||||
import { SessionRevokeConfirmDialog } from './SessionRevokeConfirmDialog';
|
||||
|
||||
export function SecurityTab() {
|
||||
@@ -57,11 +56,6 @@ export function SecurityTab() {
|
||||
const hasEmailProvider = fetchedIdentities.some(i => i.provider === 'email');
|
||||
setHasPassword(hasEmailProvider);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to load identities', {
|
||||
userId: user?.id,
|
||||
action: 'load_identities',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
handleError(error, { action: 'Load connected accounts', userId: user?.id });
|
||||
} finally {
|
||||
setLoadingIdentities(false);
|
||||
@@ -159,11 +153,6 @@ export function SecurityTab() {
|
||||
|
||||
setSessions((data as AuthSession[]) || []);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to fetch sessions', {
|
||||
userId: user.id,
|
||||
action: 'fetch_sessions',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
handleError(error, {
|
||||
action: 'Load active sessions',
|
||||
userId: user.id
|
||||
@@ -190,12 +179,6 @@ export function SecurityTab() {
|
||||
const { error } = await supabase.rpc('revoke_my_session', { session_id: sessionToRevoke.id });
|
||||
|
||||
if (error) {
|
||||
logger.error('Failed to revoke session', {
|
||||
userId: user?.id,
|
||||
action: 'revoke_session',
|
||||
sessionId: sessionToRevoke.id,
|
||||
error: error.message
|
||||
});
|
||||
handleError(error, { action: 'Revoke session', userId: user?.id });
|
||||
} else {
|
||||
handleSuccess('Success', 'Session revoked successfully');
|
||||
|
||||
@@ -15,7 +15,6 @@ import { toast } from '@/hooks/use-toast';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
export interface UploadedImage {
|
||||
url: string;
|
||||
@@ -71,8 +70,8 @@ export function EntityMultiImageUploader({
|
||||
if (image.isLocal && image.url.startsWith('blob:')) {
|
||||
try {
|
||||
URL.revokeObjectURL(image.url);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to revoke object URL', { error: getErrorMessage(error) });
|
||||
} catch {
|
||||
// Silent cleanup failure - non-critical
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -18,7 +18,6 @@ import { supabase } from '@/lib/supabaseClient';
|
||||
import { EntityPhotoGalleryProps } from '@/types/submissions';
|
||||
import { useUserRole } from '@/hooks/useUserRole';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
interface Photo {
|
||||
id: string;
|
||||
@@ -74,7 +73,7 @@ export function EntityPhotoGallery({
|
||||
|
||||
setPhotos(mappedPhotos);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to fetch photos', { error: getErrorMessage(error), entityId, entityType });
|
||||
// Photo fetch failed - display empty gallery
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import { useToast } from '@/hooks/use-toast';
|
||||
import { Trash2, Pencil } from 'lucide-react';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
interface Photo {
|
||||
id: string;
|
||||
@@ -127,8 +126,8 @@ export function PhotoManagementDialog({
|
||||
const { data } = await supabase.from('companies').select('name').eq('id', entityId).single();
|
||||
if (data?.name) entityName = data.name;
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('Failed to fetch entity name', { error: getErrorMessage(err), entityType, entityId });
|
||||
} catch {
|
||||
// Failed to fetch entity name - use default
|
||||
}
|
||||
|
||||
// Create content submission
|
||||
|
||||
@@ -17,7 +17,6 @@ import { getErrorMessage } from '@/lib/errorHandler';
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { logger } from '@/lib/logger';
|
||||
|
||||
interface PhotoUploadProps {
|
||||
onUploadComplete?: (urls: string[], imageId?: string) => void;
|
||||
@@ -71,8 +70,8 @@ export function PhotoUpload({
|
||||
objectUrlsRef.current.forEach(url => {
|
||||
try {
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to revoke object URL', { error: getErrorMessage(error) });
|
||||
} catch {
|
||||
// Silent cleanup failure - non-critical
|
||||
}
|
||||
});
|
||||
objectUrlsRef.current.clear();
|
||||
@@ -90,8 +89,8 @@ export function PhotoUpload({
|
||||
try {
|
||||
URL.revokeObjectURL(url);
|
||||
objectUrlsRef.current.delete(url);
|
||||
} catch (error: unknown) {
|
||||
logger.error('Failed to revoke object URL', { error: getErrorMessage(error) });
|
||||
} catch {
|
||||
// Silent cleanup failure - non-critical
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -194,8 +193,8 @@ export function PhotoUpload({
|
||||
};
|
||||
}
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
logger.error('Status poll error', { error: getErrorMessage(error) });
|
||||
} catch {
|
||||
// Status poll error - will retry
|
||||
}
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
@@ -249,8 +248,8 @@ export function PhotoUpload({
|
||||
undefined,
|
||||
'DELETE'
|
||||
);
|
||||
} catch (deleteError) {
|
||||
logger.warn('Failed to delete old avatar');
|
||||
} catch {
|
||||
// Old avatar deletion failed - non-critical
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +338,6 @@ export function PhotoUpload({
|
||||
alt="Avatar"
|
||||
className="w-24 h-24 rounded-full object-cover border-2 border-border"
|
||||
onError={(e) => {
|
||||
logger.warn('Failed to load avatar image');
|
||||
e.currentTarget.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSIjZjNmNGY2Ii8+CjxwYXRoIGQ9Im0xNSAxMi0zLTMtMy4wMDEgM0w2IDlsNi02aDZ2NloiIGZpbGw9IiM5Y2EzYWYiLz4KPC9zdmc+';
|
||||
}}
|
||||
/>
|
||||
@@ -487,7 +485,6 @@ export function PhotoUpload({
|
||||
alt={image.filename}
|
||||
className="w-full aspect-square object-cover rounded-lg border"
|
||||
onError={(e) => {
|
||||
logger.warn('Failed to load thumbnail image');
|
||||
e.currentTarget.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSIjZjNmNGY2Ii8+CjxwYXRoIGQ9Im0xNSAxMi0zLTMtMy4wMDEgM0w2IDlsNi02aDZ2NloiIGZpbGw9IiM5Y2EzYWYiLz4KPC9zdmc+';
|
||||
}}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user