From 5501f45a67a744dad5992635e483305e0035a5ba Mon Sep 17 00:00:00 2001 From: 4Ventures <4ventures@MacBook-Air-de-4Ventures.local> Date: Thu, 24 Sep 2026 12:17:46 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20guardar=20OAuth=20Google=20con=20upsert?= =?UTF-8?q?=20real=20(PATCH=20vac=C3=ADo=20no=20insertaba)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit El callback creía haber guardado el token y fallaba al emparejar Drive con «no conectado». Upsert on_conflict=provider + match no bloquea OAuth. Co-authored-by: Cursor --- src/app/api/admin/drive/callback/route.ts | 40 +++++++++++---------- src/components/DriveConnectPanel.tsx | 21 ++++++++--- src/lib/google-drive.ts | 44 +++++++++++------------ 3 files changed, 59 insertions(+), 46 deletions(-) diff --git a/src/app/api/admin/drive/callback/route.ts b/src/app/api/admin/drive/callback/route.ts index d2b76b3..7ec90b3 100644 --- a/src/app/api/admin/drive/callback/route.ts +++ b/src/app/api/admin/drive/callback/route.ts @@ -56,27 +56,31 @@ export async function GET(req: NextRequest) { email, }); - // Auto-match - const headers = serviceHeaders(); + // Auto-match folders (non-fatal: tokens already saved) let linked = 0; let ambiguous = 0; - if (headers) { - const tRes = await fetch( - `${supabaseUrl()}/rest/v1/tenants?select=id,name,slug&order=name.asc`, - { headers, cache: 'no-store' } - ); - if (tRes.ok) { - const tenants = (await tRes.json()) as { - id: string; - name: string; - slug: string; - }[]; - const folders = await listDriveFolders(); - const matches = await matchFoldersToTenants(tenants, folders); - const applied = await applyMatches(matches); - linked = applied.linked; - ambiguous = matches.filter((m) => m.status === 'ambiguous').length; + try { + const headers = serviceHeaders(); + if (headers) { + const tRes = await fetch( + `${supabaseUrl()}/rest/v1/tenants?select=id,name,slug&order=name.asc`, + { headers, cache: 'no-store' } + ); + if (tRes.ok) { + const tenants = (await tRes.json()) as { + id: string; + name: string; + slug: string; + }[]; + const folders = await listDriveFolders(); + const matches = await matchFoldersToTenants(tenants, folders); + const applied = await applyMatches(matches); + linked = applied.linked; + ambiguous = matches.filter((m) => m.status === 'ambiguous').length; + } } + } catch { + // match can fail without undoing OAuth } const res = NextResponse.redirect( diff --git a/src/components/DriveConnectPanel.tsx b/src/components/DriveConnectPanel.tsx index 93496f8..679a918 100644 --- a/src/components/DriveConnectPanel.tsx +++ b/src/components/DriveConnectPanel.tsx @@ -38,14 +38,17 @@ export default function DriveConnectPanel() { const params = new URLSearchParams(window.location.search); if (params.get('drive') === 'ok') { setMsg( - `Drive conectado. Enlazadas ${params.get('linked') || 0} carpetas` + + `Google conectado. Enlazadas ${params.get('linked') || 0} carpetas Drive` + (params.get('ambiguous') && params.get('ambiguous') !== '0' ? ` · ${params.get('ambiguous')} ambiguas (revisa abajo)` : '') ); } if (params.get('drive') === 'error') { - setErr(params.get('msg') || 'Error OAuth Drive'); + setErr(params.get('msg') || 'Error OAuth Google'); + } + if (params.get('drive')) { + window.history.replaceState({}, '', '/dashboard/agencia'); } void loadStatus(); }, []); @@ -133,13 +136,21 @@ export default function DriveConnectPanel() { - {connected && ( -

+ {connected ? ( +

Conectado{email ? ` · ${email}` : ''}

+ ) : ( +

+ Aún no conectado — pulsa el botón naranja. +

)} {msg &&

{msg}

} - {err &&

{err}

} + {err && ( +

+ {err} +

+ )} {matches && matches.length > 0 && (