diff --git a/apps/web/src/app/api/arcade/invitations/pending/route.ts b/apps/web/src/app/api/arcade/invitations/pending/route.ts index b513b64c..f8b402dc 100644 --- a/apps/web/src/app/api/arcade/invitations/pending/route.ts +++ b/apps/web/src/app/api/arcade/invitations/pending/route.ts @@ -1,11 +1,12 @@ +import { and, eq, isNull } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' import { db, schema } from '@/db' -import { eq } from 'drizzle-orm' import { getViewerId } from '@/lib/viewer' /** * GET /api/arcade/invitations/pending * Get all pending invitations for the current user with room details + * Excludes invitations for rooms where the user is currently banned */ export async function GET(req: NextRequest) { try { @@ -33,8 +34,18 @@ export async function GET(req: NextRequest) { .where(eq(schema.roomInvitations.userId, viewerId)) .orderBy(schema.roomInvitations.createdAt) - // Filter to only pending invitations - const pendingInvitations = invitations.filter((inv) => inv.status === 'pending') + // Get all active bans for this user + const activeBans = await db + .select({ roomId: schema.roomBans.roomId }) + .from(schema.roomBans) + .where(and(eq(schema.roomBans.userId, viewerId), isNull(schema.roomBans.unbannedAt))) + + const bannedRoomIds = new Set(activeBans.map((ban) => ban.roomId)) + + // Filter to only pending invitations, excluding banned rooms + const pendingInvitations = invitations.filter( + (inv) => inv.status === 'pending' && !bannedRoomIds.has(inv.roomId) + ) return NextResponse.json({ invitations: pendingInvitations }, { status: 200 }) } catch (error: any) { diff --git a/apps/web/src/app/arcade/page.tsx b/apps/web/src/app/arcade/page.tsx index 4f5768d8..f8c42df8 100644 --- a/apps/web/src/app/arcade/page.tsx +++ b/apps/web/src/app/arcade/page.tsx @@ -5,13 +5,10 @@ import { PageWithNav } from '@/components/PageWithNav' import { css } from '../../../styled-system/css' import { EnhancedChampionArena } from '../../components/EnhancedChampionArena' import { FullscreenProvider, useFullscreen } from '../../contexts/FullscreenContext' -import { PendingInvitations } from '@/components/nav/PendingInvitations' -import { useRoomData } from '@/hooks/useRoomData' function ArcadeContent() { const { setFullscreenElement } = useFullscreen() const arcadeRef = useRef(null) - const { refetch: refetchRoomData } = useRoomData() useEffect(() => { // Register this component's main div as the fullscreen element @@ -50,17 +47,6 @@ function ArcadeContent() { })} /> - {/* Pending Invitations */} -
- refetchRoomData()} /> -
- {/* Main Champion Arena - takes remaining space */}
m.userId === currentUserId) @@ -169,171 +170,178 @@ export function GameContextNav({ const showPlayers = activePlayers.length > 0 || (shouldEmphasize && inactivePlayers.length > 0) return ( -
- {/* Game Title Section - Always mounted, hidden when in room */} + <> + {/* Pending Invitations Banner - Shows above nav when user has invitations */} + refetchRoomData()} + /> +
- -
-
+ + {/* Room Info Section - Always mounted, hidden when not in room */} +
+ + + {/* Network Players - inside same pane as room info */} + {networkPlayers.length > 0 && ( + <> +
+ {networkPlayers.map((player) => ( + + ))} + + )} +
+ + {/* Player Section - Always mounted, hidden when no players */} +
+ + +
-
- {/* Room Info Section - Always mounted, hidden when not in room */} -
- - - {/* Network Players - inside same pane as room info */} - {networkPlayers.length > 0 && ( - <> -
- {networkPlayers.map((player) => ( - - ))} - - )} -
- - {/* Player Section - Always mounted, hidden when no players */} -
- - - -
- -