From 9ee767b6cd407ed9e5d5b241b934cb58288b3a07 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 14 Feb 2026 13:30:55 +0100 Subject: [PATCH] Use session role for invite page, handle stale user sessions gracefully Switch invite page from DB query (user.me) to JWT session for role checks, avoiding failures when user ID is stale. Return friendly error from user.me instead of throwing on missing user. Co-Authored-By: Claude Opus 4.6 --- src/app/(admin)/admin/members/invite/page.tsx | 9 +++++---- src/server/routers/user.ts | 11 ++++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/app/(admin)/admin/members/invite/page.tsx b/src/app/(admin)/admin/members/invite/page.tsx index 5706a26..e19ed0e 100644 --- a/src/app/(admin)/admin/members/invite/page.tsx +++ b/src/app/(admin)/admin/members/invite/page.tsx @@ -69,6 +69,7 @@ import { Mail, MailX, } from 'lucide-react' +import { useSession } from 'next-auth/react' import { cn } from '@/lib/utils' type Step = 'input' | 'preview' | 'sending' | 'complete' @@ -274,10 +275,10 @@ export default function MemberInvitePage() { const utils = trpc.useUtils() - // Fetch current user to check role - const { data: currentUser } = trpc.user.me.useQuery() - const isSuperAdmin = currentUser?.role === 'SUPER_ADMIN' - const isAdmin = isSuperAdmin || currentUser?.role === 'PROGRAM_ADMIN' + // Use session role directly (from JWT) — no DB query needed, works even with stale user IDs + const { data: session } = useSession() + const isSuperAdmin = session?.user?.role === 'SUPER_ADMIN' + const isAdmin = isSuperAdmin || session?.user?.role === 'PROGRAM_ADMIN' // Compute available roles as a stable list — avoids Radix Select // not re-rendering conditional children when async data loads diff --git a/src/server/routers/user.ts b/src/server/routers/user.ts index c77d37b..2d7286e 100644 --- a/src/server/routers/user.ts +++ b/src/server/routers/user.ts @@ -19,7 +19,7 @@ export const userRouter = router({ * Get current user profile */ me: protectedProcedure.query(async ({ ctx }) => { - return ctx.prisma.user.findUniqueOrThrow({ + const user = await ctx.prisma.user.findUnique({ where: { id: ctx.user.id }, select: { id: true, @@ -41,6 +41,15 @@ export const userRouter = router({ lastLoginAt: true, }, }) + + if (!user) { + throw new TRPCError({ + code: 'UNAUTHORIZED', + message: 'User session is stale. Please log out and log back in.', + }) + } + + return user }), /**