Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 17 additions & 89 deletions src/app/api/whatsapp/config/route.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,14 @@
import { NextResponse } from 'next/server'
import { createClient } from '@/lib/supabase/server'
import { createClient as createAdminClient } from '@supabase/supabase-js'
import {
registerPhoneNumber,
subscribeWabaToApp,
verifyPhoneNumber,
} from '@/lib/whatsapp/meta-api'
import { encrypt, decrypt } from '@/lib/whatsapp/encryption'
import { getCurrentAccount, requireRole, toErrorResponse } from '@/lib/auth/account'


/**
* Resolve the caller's account_id from their profile. Inlined here
* (rather than going through `@/lib/auth/account.getCurrentAccount`)
* because the GET handler wants to return shaped 200s for every
* non-auth failure mode, not throw — keeping the helper minimal lets
* the existing response branches stay as-is.
*
* Returns null if the user has no profile or no account; callers
* should treat that the same as "not connected".
*/
async function resolveAccountId(
supabase: Awaited<ReturnType<typeof createClient>>,
userId: string,
): Promise<string | null> {
const { data, error } = await supabase
.from('profiles')
.select('account_id')
.eq('user_id', userId)
.maybeSingle()
if (error || !data?.account_id) return null
return data.account_id as string
}

// Lazy-initialised service-role client. We need it to detect a
// phone_number_id already claimed by a *different* user — under RLS,
Expand Down Expand Up @@ -60,30 +39,11 @@ function supabaseAdmin() {
* { connected: false, reason: 'token_corrupted', message: '...', needs_reset: true }
* { connected: false, reason: 'meta_api_error', message: '...' }
*/
export async function GET() {
export async function GET(request: Request) {
try {
const supabase = await createClient()

const {
data: { user },
error: authError,
} = await supabase.auth.getUser()

if (authError || !user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

const accountId = await resolveAccountId(supabase, user.id)
if (!accountId) {
return NextResponse.json(
{
connected: false,
reason: 'no_account',
message: 'Your profile is not linked to an account.',
},
{ status: 200 },
)
}
const { searchParams } = new URL(request.url)
const quick = searchParams.get('quick') === 'true'
const { supabase, accountId } = await getCurrentAccount()

const { data: config, error: configError } = await supabase
.from('whatsapp_config')
Expand Down Expand Up @@ -129,6 +89,11 @@ export async function GET() {
)
}

// If quick validation requested, return connected status early to save Meta API rate limits
if (quick) {
return NextResponse.json({ connected: config.status === 'connected', quick: true })
}

// Validate credentials against Meta
try {
const phoneInfo = await verifyPhoneNumber({
Expand All @@ -150,10 +115,7 @@ export async function GET() {
}
} catch (error) {
console.error('Error in WhatsApp config GET:', error)
return NextResponse.json(
{ connected: false, reason: 'unknown', message: 'Internal server error' },
{ status: 500 }
)
return toErrorResponse(error)
}
}

Expand All @@ -165,24 +127,7 @@ export async function GET() {
*/
export async function POST(request: Request) {
try {
const supabase = await createClient()

const {
data: { user },
error: authError,
} = await supabase.auth.getUser()

if (authError || !user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

const accountId = await resolveAccountId(supabase, user.id)
if (!accountId) {
return NextResponse.json(
{ error: 'Your profile is not linked to an account.' },
{ status: 403 },
)
}
const { supabase, accountId, userId } = await requireRole('admin')

const body = await request.json()
const { phone_number_id, waba_id, access_token, verify_token, pin } = body
Expand Down Expand Up @@ -388,7 +333,7 @@ export async function POST(request: Request) {
.from('whatsapp_config')
.insert({
account_id: accountId,
user_id: user.id,
user_id: userId,
...baseRow,
})

Expand Down Expand Up @@ -427,7 +372,7 @@ export async function POST(request: Request) {
})
} catch (error) {
console.error('Error in WhatsApp config POST:', error)
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
return toErrorResponse(error)
}
}

Expand All @@ -440,24 +385,7 @@ export async function POST(request: Request) {
*/
export async function DELETE() {
try {
const supabase = await createClient()

const {
data: { user },
error: authError,
} = await supabase.auth.getUser()

if (authError || !user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

const accountId = await resolveAccountId(supabase, user.id)
if (!accountId) {
return NextResponse.json(
{ error: 'Your profile is not linked to an account.' },
{ status: 403 },
)
}
const { supabase, accountId } = await requireRole('admin')

const { error: deleteError } = await supabase
.from('whatsapp_config')
Expand All @@ -475,6 +403,6 @@ export async function DELETE() {
return NextResponse.json({ success: true })
} catch (error) {
console.error('Error in WhatsApp config DELETE:', error)
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
return toErrorResponse(error)
}
}
Loading