From 944e1ba9ff4916dd5f860fc78f6259d878b673ce Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 22:59:40 +0000 Subject: [PATCH] Fix ticket merging implementation --- src/pages/admin/AdminContact.tsx | 19 +++++++ .../functions/merge-contact-tickets/index.ts | 54 ++++++++++++++++++- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/pages/admin/AdminContact.tsx b/src/pages/admin/AdminContact.tsx index 76270569..2982b197 100644 --- a/src/pages/admin/AdminContact.tsx +++ b/src/pages/admin/AdminContact.tsx @@ -507,7 +507,26 @@ export default function AdminContact() { const handleConfirmMerge = () => { if (!primaryTicketId || selectedForMerge.length < 2) return; + // Ensure primary is actually in the selected list + if (!selectedForMerge.includes(primaryTicketId)) { + handleError( + new Error('Primary ticket must be one of the selected tickets'), + { action: 'Merge Tickets' } + ); + return; + } + const mergeIds = selectedForMerge.filter(id => id !== primaryTicketId); + + // Additional validation: ensure we have tickets to merge + if (mergeIds.length === 0) { + handleError( + new Error('No tickets to merge. Please select at least 2 tickets.'), + { action: 'Merge Tickets' } + ); + return; + } + mergeTicketsMutation.mutate({ primaryId: primaryTicketId, mergeIds, diff --git a/supabase/functions/merge-contact-tickets/index.ts b/supabase/functions/merge-contact-tickets/index.ts index dbd850df..f8e50cba 100644 --- a/supabase/functions/merge-contact-tickets/index.ts +++ b/supabase/functions/merge-contact-tickets/index.ts @@ -124,6 +124,11 @@ serve(async (req) => { }); // Step 1: Move all email threads to primary ticket + edgeLogger.info('Step 1: Moving email threads', { + requestId: tracking.requestId, + fromTickets: mergeTickets.map(t => t.ticket_number) + }); + const { data: movedThreads, error: moveError } = await supabase .from('contact_email_threads') .update({ submission_id: primaryTicketId }) @@ -134,18 +139,34 @@ serve(async (req) => { const threadsMovedCount = movedThreads?.length || 0; + edgeLogger.info('Threads moved successfully', { + requestId: tracking.requestId, + threadsMovedCount + }); + + if (threadsMovedCount === 0) { + edgeLogger.warn('No email threads found to move', { + requestId: tracking.requestId, + mergeTicketIds + }); + } + // Step 2: Consolidate admin notes + edgeLogger.info('Step 2: Consolidating admin notes', { requestId: tracking.requestId }); + let consolidatedNotes = primaryTicket.admin_notes || ''; for (const ticket of mergeTickets) { if (ticket.admin_notes) { - consolidatedNotes = consolidatedNotes + consolidatedNotes = consolidatedNotes.trim() ? `${consolidatedNotes}\n\n${ticket.admin_notes}` : ticket.admin_notes; } } // Step 3: Recalculate metadata from consolidated threads + edgeLogger.info('Step 3: Recalculating metadata from threads', { requestId: tracking.requestId }); + const { data: threadStats, error: statsError } = await supabase .from('contact_email_threads') .select('direction, created_at') @@ -161,10 +182,19 @@ serve(async (req) => { ?.filter(t => t.direction === 'inbound') .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0]?.created_at; + edgeLogger.info('Metadata recalculated', { + requestId: tracking.requestId, + outboundCount, + lastAdminResponse, + lastUserResponse + }); + // Get merged ticket numbers const mergedTicketNumbers = mergeTickets.map(t => t.ticket_number); // Step 4: Update primary ticket with consolidated data + edgeLogger.info('Step 4: Updating primary ticket', { requestId: tracking.requestId }); + const { error: updateError } = await supabase .from('contact_submissions') .update({ @@ -181,7 +211,14 @@ serve(async (req) => { if (updateError) throw updateError; + edgeLogger.info('Primary ticket updated successfully', { requestId: tracking.requestId }); + // Step 5: Delete merged tickets + edgeLogger.info('Step 5: Deleting merged tickets', { + requestId: tracking.requestId, + ticketsToDelete: mergeTicketIds.length + }); + const { error: deleteError } = await supabase .from('contact_submissions') .delete() @@ -189,8 +226,12 @@ serve(async (req) => { if (deleteError) throw deleteError; + edgeLogger.info('Merged tickets deleted successfully', { requestId: tracking.requestId }); + // Step 6: Audit log - await supabase.from('admin_audit_log').insert({ + edgeLogger.info('Step 6: Creating audit log', { requestId: tracking.requestId }); + + const { error: auditError } = await supabase.from('admin_audit_log').insert({ admin_user_id: user.id, target_user_id: user.id, // No specific target user for this action action: 'merge_contact_tickets', @@ -205,6 +246,15 @@ serve(async (req) => { } }); + if (auditError) { + edgeLogger.warn('Failed to create audit log for merge', { + requestId: tracking.requestId, + error: auditError.message, + primaryTicket: primaryTicket.ticket_number + }); + // Don't throw - merge already succeeded + } + const duration = endRequest(tracking); edgeLogger.info('Merge tickets completed successfully', { requestId: tracking.requestId,