diff --git a/src/app/api/collections/[id]/join/route.ts b/src/app/api/collections/[id]/join/route.ts index de00c3b..1645dbd 100644 --- a/src/app/api/collections/[id]/join/route.ts +++ b/src/app/api/collections/[id]/join/route.ts @@ -12,6 +12,7 @@ export async function POST( const session = await getServerSession(authOptions); if (!session?.user) { + console.log('[collections/:id/join] unauthorized: no session'); return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } @@ -109,6 +110,7 @@ export async function POST( } } if (!collection.isPublic && !inviteOk) { + console.log('[collections/:id/join] private and no valid invite'); return NextResponse.json( { error: 'This collection is private and requires an invitation' }, { status: 403 } @@ -143,6 +145,7 @@ export async function POST( } } else { // Create new membership + console.log('[collections/:id/join] creating membership'); await db.collectionMember.create({ data: { userId, @@ -214,7 +217,7 @@ export async function POST( res.cookies.set('invite_library', '', { path: '/', maxAge: 0 }); return res; } catch (error) { - console.error('Error joining collection:', error); + console.error('[collections/:id/join] error', error); return NextResponse.json( { error: 'Failed to join collection' }, { status: 500 } diff --git a/src/app/api/invite/consume/route.ts b/src/app/api/invite/consume/route.ts index dc5c0e4..f40c1c8 100644 --- a/src/app/api/invite/consume/route.ts +++ b/src/app/api/invite/consume/route.ts @@ -7,18 +7,27 @@ import { db } from '@/lib/db'; export async function POST(request: NextRequest) { try { const session = await getServerSession(authOptions); + console.log('[invite/consume] start', { + url: request.url, + hasSessionUser: !!session?.user, + hasCookieInviteToken: !!request.cookies.get('invite_token')?.value, + inviteLibrary: request.cookies.get('invite_library')?.value, + }); if (!session?.user) { + console.log('[invite/consume] no session user'); return NextResponse.json({ redirect: null }, { status: 200 }); } const inviteToken = request.cookies.get('invite_token')?.value; const inviteLibrary = request.cookies.get('invite_library')?.value; if (!inviteToken || !inviteLibrary) { + console.log('[invite/consume] missing cookies'); return NextResponse.json({ redirect: null }, { status: 200 }); } const userId = (session.user as { id?: string } | undefined)?.id; if (!userId) { + console.log('[invite/consume] missing userId from session'); return NextResponse.json({ redirect: null }, { status: 200 }); } @@ -32,6 +41,11 @@ export async function POST(request: NextRequest) { }, select: { id: true, expiresAt: true }, }); + console.log('[invite/consume] invitation lookup', { + found: !!invitation, + expired: invitation ? new Date() > invitation.expiresAt : undefined, + }); + // Build base response now so we can always clear cookies const res = NextResponse.json({ redirect: `/collection/${inviteLibrary}` }); @@ -39,6 +53,7 @@ export async function POST(request: NextRequest) { res.cookies.set('invite_library', '', { path: '/', maxAge: 0 }); if (!invitation || new Date() > invitation.expiresAt) { + console.log('[invite/consume] invalid or expired invite; returning'); return res; } @@ -48,6 +63,10 @@ export async function POST(request: NextRequest) { select: { id: true, isActive: true }, }); if (!existing) { + console.log('[invite/consume] creating membership', { + userId, + inviteLibrary, + }); await db.collectionMember.create({ data: { userId, @@ -57,20 +76,32 @@ export async function POST(request: NextRequest) { }, }); } else if (!existing.isActive) { + console.log('[invite/consume] reactivating membership', { + id: existing.id, + }); + await db.collectionMember.update({ where: { id: existing.id }, data: { isActive: true }, }); + } else { + console.log('[invite/consume] membership already active'); } // Mark invite accepted + console.log('[invite/consume] marking invite accepted'); + await db.invitation.updateMany({ where: { token: inviteToken, libraryId: inviteLibrary }, data: { status: 'ACCEPTED', acceptedAt: new Date(), receiverId: userId }, }); + console.log('[invite/consume] returning redirect', { + to: `/collection/${inviteLibrary}`, + }); return res; - } catch { + } catch (e) { + console.error('[invite/consume] error', e); return NextResponse.json({ redirect: null }, { status: 200 }); } } diff --git a/src/app/collection/[id]/page.tsx b/src/app/collection/[id]/page.tsx index b25a0f7..9499a1f 100644 --- a/src/app/collection/[id]/page.tsx +++ b/src/app/collection/[id]/page.tsx @@ -23,6 +23,14 @@ export default async function CollectionPage({ const inviteLibrary = cookieStore.get('invite_library')?.value; const { id: collectionIdForCheck } = await params; const allowGuest = inviteToken && inviteLibrary === collectionIdForCheck; + console.log('[collection page] auth gate', { + hasSessionUser: !!session?.user, + guestParam: guest, + hasInviteToken: !!inviteToken, + inviteLibrary, + collectionIdForCheck, + allowGuest, + }); if (!allowGuest) { redirect('/auth/signin'); }