feat: Implement plan for bug fixes

This commit is contained in:
gpt-engineer-app[bot]
2025-10-21 13:27:23 +00:00
parent 827f0f8ea5
commit ce6c9d6866
14 changed files with 94 additions and 59 deletions

View File

@@ -30,6 +30,7 @@ import '@mdxeditor/editor/style.css';
import '@/styles/mdx-editor-theme.css'; import '@/styles/mdx-editor-theme.css';
import { useTheme } from '@/components/theme/ThemeProvider'; import { useTheme } from '@/components/theme/ThemeProvider';
import { supabase } from '@/integrations/supabase/client'; import { supabase } from '@/integrations/supabase/client';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { getCloudflareImageUrl } from '@/lib/cloudflareImageUtils'; import { getCloudflareImageUrl } from '@/lib/cloudflareImageUtils';
import { useAutoSave } from '@/hooks/useAutoSave'; import { useAutoSave } from '@/hooks/useAutoSave';
import { CheckCircle2, Loader2, AlertCircle } from 'lucide-react'; import { CheckCircle2, Loader2, AlertCircle } from 'lucide-react';
@@ -140,9 +141,11 @@ export function MarkdownEditor({
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append('file', file);
const { data, error } = await supabase.functions.invoke('upload-image', { const { data, error } = await invokeWithTracking(
body: formData 'upload-image',
}); formData,
undefined
);
if (error) throw error; if (error) throw error;

View File

@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Checkbox } from '@/components/ui/checkbox'; import { Checkbox } from '@/components/ui/checkbox';
@@ -101,15 +102,17 @@ export function TestDataGenerator() {
description: `Generating ${stage}...`, description: `Generating ${stage}...`,
}); });
const { data, error } = await supabase.functions.invoke('seed-test-data', { const { data, error } = await invokeWithTracking(
body: { 'seed-test-data',
{
preset, preset,
fieldDensity, fieldDensity,
entityTypes: selectedEntityTypes, entityTypes: selectedEntityTypes,
stage, stage,
...options ...options
} },
}); (await supabase.auth.getUser()).data.user?.id
);
if (error) throw error; if (error) throw error;

View File

@@ -1,5 +1,6 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { supabase } from '@/integrations/supabase/client'; import { supabase } from '@/integrations/supabase/client';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { getSessionAAL } from '@/types/supabase-session'; import { getSessionAAL } from '@/types/supabase-session';
import { getErrorMessage } from '@/lib/errorHandler'; import { getErrorMessage } from '@/lib/errorHandler';
@@ -142,9 +143,11 @@ export function MFARemovalDialog({ open, onOpenChange, factorId, onSuccess }: MF
setLoading(true); setLoading(true);
try { try {
// Phase 3: Call edge function instead of direct unenroll // Phase 3: Call edge function instead of direct unenroll
const { data, error } = await supabase.functions.invoke('mfa-unenroll', { const { data, error, requestId } = await invokeWithTracking(
body: { factorId } 'mfa-unenroll',
}); { factorId },
(await supabase.auth.getUser()).data.user?.id
);
if (error) throw error; if (error) throw error;
if (data?.error) throw new Error(data.error); if (data?.error) throw new Error(data.error);

View File

@@ -1,4 +1,5 @@
import { useReducer } from 'react'; import { useReducer } from 'react';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter } from '@/components/ui/alert-dialog'; import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter } from '@/components/ui/alert-dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
@@ -57,9 +58,11 @@ export function AccountDeletionDialog({ open, onOpenChange, userEmail, onDeletio
dispatch({ type: 'SET_LOADING', payload: true }); dispatch({ type: 'SET_LOADING', payload: true });
try { try {
const { data, error } = await supabase.functions.invoke('request-account-deletion', { const { data, error, requestId } = await invokeWithTracking(
body: {}, 'request-account-deletion',
}); {},
(await supabase.auth.getUser()).data.user?.id
);
if (error) throw error; if (error) throw error;
@@ -88,9 +91,11 @@ export function AccountDeletionDialog({ open, onOpenChange, userEmail, onDeletio
dispatch({ type: 'SET_LOADING', payload: true }); dispatch({ type: 'SET_LOADING', payload: true });
try { try {
const { error } = await supabase.functions.invoke('confirm-account-deletion', { const { error, requestId } = await invokeWithTracking(
body: { confirmation_code: state.confirmationCode }, 'confirm-account-deletion',
}); { confirmation_code: state.confirmationCode },
(await supabase.auth.getUser()).data.user?.id
);
if (error) throw error; if (error) throw error;
@@ -110,9 +115,11 @@ export function AccountDeletionDialog({ open, onOpenChange, userEmail, onDeletio
dispatch({ type: 'SET_LOADING', payload: true }); dispatch({ type: 'SET_LOADING', payload: true });
try { try {
const { error } = await supabase.functions.invoke('resend-deletion-code', { const { error, requestId } = await invokeWithTracking(
body: {}, 'resend-deletion-code',
}); {},
(await supabase.auth.getUser()).data.user?.id
);
if (error) throw error; if (error) throw error;

View File

@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
@@ -172,12 +173,11 @@ export function AccountProfileTab() {
} }
// Call the edge function with explicit authorization header // Call the edge function with explicit authorization header
const { data, error } = await supabase.functions.invoke('cancel-email-change', { const { data, error, requestId } = await invokeWithTracking(
method: 'POST', 'cancel-email-change',
headers: { {},
Authorization: `Bearer ${session.access_token}`, user.id
}, );
});
if (error) { if (error) {
console.error('Edge function error:', error); console.error('Edge function error:', error);

View File

@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Separator } from '@/components/ui/separator'; import { Separator } from '@/components/ui/separator';
@@ -163,11 +164,10 @@ export function DataExportTab() {
}); });
// Call edge function for secure export // Call edge function for secure export
const { data, error } = await supabase.functions.invoke<ExportRequestResult>( const { data, error, requestId } = await invokeWithTracking<ExportRequestResult>(
'export-user-data', 'export-user-data',
{ validatedOptions,
body: validatedOptions user.id
}
); );
if (error) { if (error) {

View File

@@ -1,6 +1,7 @@
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { supabase } from '@/integrations/supabase/client'; import { supabase } from '@/integrations/supabase/client';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { useToast } from '@/hooks/use-toast'; import { useToast } from '@/hooks/use-toast';
import { AlertTriangle, Loader2 } from 'lucide-react'; import { AlertTriangle, Loader2 } from 'lucide-react';
import { useState } from 'react'; import { useState } from 'react';
@@ -26,9 +27,11 @@ export function DeletionStatusBanner({ scheduledDate, onCancelled }: DeletionSta
const handleCancelDeletion = async () => { const handleCancelDeletion = async () => {
setLoading(true); setLoading(true);
try { try {
const { error } = await supabase.functions.invoke('cancel-account-deletion', { const { error, requestId } = await invokeWithTracking(
body: { cancellation_reason: 'User cancelled from settings' }, 'cancel-account-deletion',
}); { cancellation_reason: 'User cancelled from settings' },
(await supabase.auth.getUser()).data.user?.id
);
if (error) throw error; if (error) throw error;

View File

@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod'; import { zodResolver } from '@hookform/resolvers/zod';
import { import {
@@ -302,8 +303,9 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
// Step 4: Send security notification // Step 4: Send security notification
try { try {
await supabase.functions.invoke('trigger-notification', { await invokeWithTracking(
body: { 'trigger-notification',
{
workflowId: 'security-alert', workflowId: 'security-alert',
subscriberId: user.id, subscriberId: user.id,
payload: { payload: {
@@ -311,8 +313,9 @@ export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: Password
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
device: navigator.userAgent.split(' ')[0] device: navigator.userAgent.split(' ')[0]
} }
} },
}); user.id
);
} catch (notifError) { } catch (notifError) {
logger.error('Failed to send password change notification', { logger.error('Failed to send password change notification', {
userId: user!.id, userId: user!.id,

View File

@@ -15,6 +15,8 @@ import {
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { getErrorMessage } from '@/lib/errorHandler'; import { getErrorMessage } from '@/lib/errorHandler';
import { supabase } from '@/integrations/supabase/client'; import { supabase } from '@/integrations/supabase/client';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { useAuth } from '@/hooks/useAuth';
interface PhotoUploadProps { interface PhotoUploadProps {
onUploadComplete?: (urls: string[], imageId?: string) => void; onUploadComplete?: (urls: string[], imageId?: string) => void;
@@ -111,8 +113,9 @@ export function PhotoUpload({
const uploadFile = async (file: File, previewUrl: string): Promise<UploadedImage> => { const uploadFile = async (file: File, previewUrl: string): Promise<UploadedImage> => {
try { try {
const { data: uploadData, error: uploadError } = await supabase.functions.invoke('upload-image', { const { data: uploadData, error: uploadError, requestId } = await invokeWithTracking(
body: { 'upload-image',
{
metadata: { metadata: {
filename: file.name, filename: file.name,
size: file.size, size: file.size,
@@ -120,8 +123,9 @@ export function PhotoUpload({
uploadedAt: new Date().toISOString() uploadedAt: new Date().toISOString()
}, },
variant: isAvatar ? 'avatar' : 'public' variant: isAvatar ? 'avatar' : 'public'
} },
}); undefined
);
if (uploadError) { if (uploadError) {
console.error('Upload URL error:', uploadError); console.error('Upload URL error:', uploadError);
@@ -239,10 +243,12 @@ export function PhotoUpload({
try { try {
if (isAvatar && currentImageId) { if (isAvatar && currentImageId) {
try { try {
await supabase.functions.invoke('upload-image', { await invokeWithTracking(
method: 'DELETE', 'upload-image',
body: { imageId: currentImageId } { imageId: currentImageId },
}); undefined,
'DELETE'
);
} catch (deleteError) { } catch (deleteError) {
console.warn('Failed to delete old avatar:', deleteError); console.warn('Failed to delete old avatar:', deleteError);
} }

View File

@@ -1,4 +1,5 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
@@ -96,9 +97,11 @@ export function UppyPhotoSubmissionUpload({
try { try {
// Get upload URL from edge function // Get upload URL from edge function
const { data: uploadData, error: uploadError } = await supabase.functions.invoke('upload-image', { const { data: uploadData, error: uploadError } = await invokeWithTracking(
body: { metadata: { requireSignedURLs: false }, variant: 'public' } 'upload-image',
}); { metadata: { requireSignedURLs: false }, variant: 'public' },
user?.id
);
if (uploadError) throw uploadError; if (uploadError) throw uploadError;

View File

@@ -1,6 +1,7 @@
import React, { useRef, useState } from 'react'; import React, { useRef, useState } from 'react';
import { supabase } from '@/integrations/supabase/client'; import { supabase } from '@/integrations/supabase/client';
import { useToast } from '@/hooks/use-toast'; import { useToast } from '@/hooks/use-toast';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { Upload, X, Eye, Loader2, CheckCircle } from 'lucide-react'; import { Upload, X, Eye, Loader2, CheckCircle } from 'lucide-react';
@@ -100,9 +101,7 @@ export function UppyPhotoUpload({
setCurrentFileName(file.name); setCurrentFileName(file.name);
// Step 1: Get upload URL from Supabase edge function // Step 1: Get upload URL from Supabase edge function
const urlResponse = await supabase.functions.invoke('upload-image', { const urlResponse = await invokeWithTracking('upload-image', { metadata, variant }, undefined);
body: { metadata, variant },
});
if (urlResponse.error) { if (urlResponse.error) {
throw new Error(`Failed to get upload URL: ${urlResponse.error.message}`); throw new Error(`Failed to get upload URL: ${urlResponse.error.message}`);

View File

@@ -1,4 +1,5 @@
import { useState, useEffect, useCallback } from 'react'; import { useState, useEffect, useCallback } from 'react';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { useAuth } from '@/hooks/useAuth'; import { useAuth } from '@/hooks/useAuth';
import { supabase } from '@/integrations/supabase/client'; import { supabase } from '@/integrations/supabase/client';
import { logger } from '@/lib/logger'; import { logger } from '@/lib/logger';
@@ -82,7 +83,7 @@ export function useUnitPreferences() {
const autoDetectPreferences = useCallback(async () => { const autoDetectPreferences = useCallback(async () => {
try { try {
const response = await supabase.functions.invoke('detect-location'); const response = await invokeWithTracking('detect-location', {}, user?.id);
if (response.data && response.data.measurementSystem) { if (response.data && response.data.measurementSystem) {
const newPreferences: UnitPreferences = { const newPreferences: UnitPreferences = {

View File

@@ -1,4 +1,5 @@
import { supabase } from '@/integrations/supabase/client'; import { supabase } from '@/integrations/supabase/client';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { logger } from '@/lib/logger'; import { logger } from '@/lib/logger';
import { getErrorMessage } from '@/lib/errorHandler'; import { getErrorMessage } from '@/lib/errorHandler';
@@ -14,9 +15,11 @@ interface EmailValidationResult {
*/ */
export async function validateEmailNotDisposable(email: string): Promise<EmailValidationResult> { export async function validateEmailNotDisposable(email: string): Promise<EmailValidationResult> {
try { try {
const { data, error } = await supabase.functions.invoke('validate-email-backend', { const { data, error } = await invokeWithTracking(
body: { email } 'validate-email-backend',
}); { email },
undefined
);
if (error) { if (error) {
logger.error('Email validation error from backend', { logger.error('Email validation error from backend', {

View File

@@ -1,4 +1,5 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { supabase } from '@/integrations/supabase/client'; import { supabase } from '@/integrations/supabase/client';
import { useToast } from '@/hooks/use-toast'; import { useToast } from '@/hooks/use-toast';
@@ -76,11 +77,11 @@ export default function AuthCallback() {
try { try {
console.log('[AuthCallback] Processing OAuth profile...'); console.log('[AuthCallback] Processing OAuth profile...');
const { data, error } = await supabase.functions.invoke('process-oauth-profile', { const { data, error, requestId } = await invokeWithTracking(
headers: { 'process-oauth-profile',
Authorization: `Bearer ${session.access_token}`, {},
}, user.id
}); );
if (error) { if (error) {
console.error('[AuthCallback] Profile processing error:', error); console.error('[AuthCallback] Profile processing error:', error);