import { NextRequest, NextResponse } from 'next/server'; import { createClient } from '@/lib/supabase/server'; // GET /api/admin/users — list all users + pending invitations export async function GET(req: NextRequest) { const supabase = await createClient(); const { data: { user } } = await supabase.auth.getUser(); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const { searchParams } = new URL(req.url); const tab = searchParams.get('tab') || 'users'; if (tab === 'invitations') { const { data, error } = await supabase .from('contributor_invitations') .select('*') .order('created_at', { ascending: false }); if (error) return NextResponse.json({ error: error.message }, { status: 500 }); return NextResponse.json({ invitations: data || [] }); } // Users tab const { data, error } = await supabase .from('user_profiles') .select('id, email, full_name, avatar_url, role, is_active, created_at') .order('created_at', { ascending: false }); if (error) return NextResponse.json({ error: error.message }, { status: 500 }); return NextResponse.json({ users: data || [] }); } // PATCH /api/admin/users — update user role or status export async function PATCH(req: NextRequest) { const supabase = await createClient(); const { data: { user } } = await supabase.auth.getUser(); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const body = await req.json(); const { id, updates } = body; if (!id || !updates) { return NextResponse.json({ error: 'Missing id or updates' }, { status: 400 }); } const { data, error } = await supabase .from('user_profiles') .update(updates) .eq('id', id) .select() .single(); if (error) return NextResponse.json({ error: error.message }, { status: 500 }); return NextResponse.json({ user: data }); } // POST /api/admin/users — send contributor invitation export async function POST(req: NextRequest) { const supabase = await createClient(); const { data: { user } } = await supabase.auth.getUser(); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const body = await req.json(); const { email, role, message } = body; if (!email) { return NextResponse.json({ error: 'Email is required' }, { status: 400 }); } // Get inviter profile const { data: inviterProfile } = await supabase .from('user_profiles') .select('full_name, email') .eq('id', user.id) .single(); // Generate unique token const token = crypto.randomUUID().replace(/-/g, '') + crypto.randomUUID().replace(/-/g, ''); // Check for existing pending invitation const { data: existing } = await supabase .from('contributor_invitations') .select('id, status') .eq('email', email) .eq('status', 'pending') .single(); if (existing) { return NextResponse.json({ error: 'A pending invitation already exists for this email' }, { status: 409 }); } // Insert invitation record const { data: invitation, error: insertError } = await supabase .from('contributor_invitations') .insert({ email, invited_by: user.id, role: role || 'contributor', token, message: message || null, status: 'pending', }) .select() .single(); if (insertError) return NextResponse.json({ error: insertError.message }, { status: 500 }); // Send email via Supabase Edge Function const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY; const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://broadcastbeat.com'; try { const emailRes = await fetch(`${supabaseUrl}/functions/v1/send-contributor-invite`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${supabaseAnonKey}`, }, body: JSON.stringify({ email, inviterName: inviterProfile?.full_name || inviterProfile?.email || 'Broadcast Beat Admin', role: role || 'contributor', token, message, siteUrl, }), }); if (!emailRes.ok) { // Mark invitation as failed but still return the record await supabase .from('contributor_invitations') .update({ status: 'email_failed' }) .eq('id', invitation.id); return NextResponse.json({ invitation, emailSent: false, warning: 'Invitation created but email failed to send' }); } } catch { return NextResponse.json({ invitation, emailSent: false, warning: 'Invitation created but email failed to send' }); } return NextResponse.json({ invitation, emailSent: true }); } // DELETE /api/admin/users — revoke invitation export async function DELETE(req: NextRequest) { const supabase = await createClient(); const { data: { user } } = await supabase.auth.getUser(); if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const body = await req.json(); const { invitationId } = body; if (!invitationId) { return NextResponse.json({ error: 'invitationId is required' }, { status: 400 }); } const { error } = await supabase .from('contributor_invitations') .update({ status: 'revoked' }) .eq('id', invitationId); if (error) return NextResponse.json({ error: error.message }, { status: 500 }); return NextResponse.json({ success: true }); }