From 4d8f66ed3a7fa0b6588d0b322ff25f26669543dd Mon Sep 17 00:00:00 2001 From: dwindown Date: Sat, 27 Dec 2025 08:46:55 +0700 Subject: [PATCH] Fix meet link creation to use edge function instead of n8n webhook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: 1. AdminConsulting.tsx: Update createMeetLink to call Supabase edge function - Remove dependency on n8n webhook URL - Call create-google-meet-event edge function directly - Use environment variables for Supabase URL and anon key - Improve error handling and user feedback 2. handle-order-paid: Add comprehensive error logging - Log meet response status - Log full response data - Log errors when meet_link update fails - Log error response text when request fails - Better debugging for troubleshooting meet creation issues This fixes: - CORS issues when calling n8n webhook - 404 errors from deleted /webhook-test/create-link endpoint - Manual meet link creation now uses same flow as automatic - Better visibility into meet creation failures via logs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/pages/admin/AdminConsulting.tsx | 49 ++++++++++--------- supabase/functions/handle-order-paid/index.ts | 20 +++++++- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/src/pages/admin/AdminConsulting.tsx b/src/pages/admin/AdminConsulting.tsx index cdb6e4e..f8f765b 100644 --- a/src/pages/admin/AdminConsulting.tsx +++ b/src/pages/admin/AdminConsulting.tsx @@ -177,53 +177,58 @@ export default function AdminConsulting() { const createMeetLink = async () => { if (!selectedSlot) return; - - // Check if n8n webhook is configured - const webhookUrl = settings.integration_n8n_base_url; - if (!webhookUrl) { - toast({ - title: 'Info', - description: 'Webhook URL belum dikonfigurasi di Pengaturan Integrasi. Masukkan link Meet secara manual.', + + // Check if Google Calendar is configured + const calendarId = settings.integration_google_calendar_id; + if (!calendarId) { + toast({ + title: 'Info', + description: 'Google Calendar ID belum dikonfigurasi di Pengaturan > Integrasi', }); return; } setCreatingMeet(true); - + try { - // Call the webhook to create Google Meet link - const response = await fetch(`${webhookUrl}/create-meet`, { + // Call the Supabase edge function to create Google Meet link + const supabaseUrl = import.meta.env.VITE_SUPABASE_URL || 'https://lovable.backoffice.biz.id'; + const response = await fetch(`${supabaseUrl}/functions/v1/create-google-meet-event`, { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${import.meta.env.VITE_SUPABASE_ANON_KEY || ''}`, + }, body: JSON.stringify({ slot_id: selectedSlot.id, date: selectedSlot.date, start_time: selectedSlot.start_time, end_time: selectedSlot.end_time, - topic: selectedSlot.topic_category, + topic: selectedSlot.topic_category || 'Konsultasi', client_name: selectedSlot.profiles?.name || 'Client', - client_email: selectedSlot.profiles?.email, - calendar_id: settings.integration_google_calendar_id, + client_email: selectedSlot.profiles?.email || '', + notes: `Manual creation by admin for slot ${selectedSlot.id}`, }), }); if (!response.ok) { - throw new Error('Webhook request failed'); + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.message || 'Failed to create Meet link'); } const data = await response.json(); - - if (data.meet_link) { + + if (data.success && data.meet_link) { setMeetLink(data.meet_link); toast({ title: 'Berhasil', description: 'Link Google Meet dibuat' }); } else { - throw new Error('No meet_link in response'); + throw new Error(data.message || 'No meet_link in response'); } - } catch (error) { + } catch (error: any) { console.error('Error creating meet link:', error); - toast({ - title: 'Gagal', - description: 'Gagal membuat link Meet. Pastikan webhook sudah dikonfigurasi dengan benar.', + toast({ + title: 'Gagal', + description: error.message || 'Gagal membuat link Meet. Pastikan Google Calendar sudah terintegrasi.', variant: 'destructive', }); } finally { diff --git a/supabase/functions/handle-order-paid/index.ts b/supabase/functions/handle-order-paid/index.ts index 1a79fbb..6a40035 100644 --- a/supabase/functions/handle-order-paid/index.ts +++ b/supabase/functions/handle-order-paid/index.ts @@ -148,20 +148,36 @@ serve(async (req: Request): Promise => { } ); + console.log("[HANDLE-PAID] Meet response status:", meetResponse.status); + if (meetResponse.ok) { const meetData = await meetResponse.json(); + console.log("[HANDLE-PAID] Meet response data:", meetData); + if (meetData.success) { console.log("[HANDLE-PAID] Meet created:", meetData.meet_link); // Update all slots with the same meet link - await supabase + const { error: updateError } = await supabase .from("consulting_slots") .update({ meet_link: meetData.meet_link }) .eq("order_id", order_id); + + if (updateError) { + console.error("[HANDLE-PAID] Failed to update meet_link:", updateError); + } else { + console.log("[HANDLE-PAID] Meet link updated for all slots in order:", order_id); + } + } else { + console.error("[HANDLE-PAID] Meet creation returned success=false:", meetData); } + } else { + const errorText = await meetResponse.text(); + console.error("[HANDLE-PAID] Meet creation failed with status:", meetResponse.status); + console.error("[HANDLE-PAID] Error response:", errorText); } } catch (error) { - console.error("[HANDLE-PAID] Meet creation failed:", error); + console.error("[HANDLE-PAID] Meet creation exception:", error); // Don't fail the entire process } }