From 23cc61f8569a45e1ccc68c48b4e54794f9ea5760 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Wed, 16 Jul 2025 23:40:57 -0600 Subject: [PATCH 1/5] init with role changes --- apps/web/src/app/admin/layout.tsx | 7 ++++++- apps/web/src/app/onboarding/layout.tsx | 1 - apps/web/src/components/shared/navbar.tsx | 8 +++----- apps/web/src/lib/constants/index.ts | 2 ++ apps/web/src/lib/queries/users.ts | 5 ++++- apps/web/src/middleware.ts | 11 ++++++----- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/apps/web/src/app/admin/layout.tsx b/apps/web/src/app/admin/layout.tsx index 7f27b77d..1a2ee491 100644 --- a/apps/web/src/app/admin/layout.tsx +++ b/apps/web/src/app/admin/layout.tsx @@ -8,6 +8,7 @@ import Navbar from "@/components/shared/navbar"; import DashNavItem from "@/components/dash/shared/DashNavItem"; import ClientToast from "@/components/shared/client-toast"; import c from "config"; +import { ADMIN_ROLES } from "@/lib/constants"; export default async function AdminLayout({ children, @@ -24,7 +25,11 @@ export default async function AdminLayout({ where: eq(users.clerkID, userId), }); - if (!user || (user.role !== "admin" && user.role !== "super_admin")) { + if (!user){ + return redirect("/onboarding"); + } + + if (!ADMIN_ROLES.includes(user.role)) { console.log("Denying admin access to user", user); return ( - {(user.role === "admin" || - user.role === "super_admin") && ( + {ADMIN_ROLES.includes(user.role) && ( - {(user.role === "admin" || - user.role === "super_admin") && ( + {ADMIN_ROLES.includes(user.role) && ( diff --git a/apps/web/src/lib/constants/index.ts b/apps/web/src/lib/constants/index.ts index f13fe6f8..d9861576 100644 --- a/apps/web/src/lib/constants/index.ts +++ b/apps/web/src/lib/constants/index.ts @@ -3,3 +3,5 @@ export const TWENTY_FOUR_HOURS = 24; export const UNIQUE_KEY_CONSTRAINT_VIOLATION_CODE = "23505"; export const LOWER_ALPHANUM_CUSTOM_ALPHABET = "1234567890abcdefghijklmnopqrstuvwxyz"; + +export const ADMIN_ROLES:Array = ["admin", "super_admin"] as const; diff --git a/apps/web/src/lib/queries/users.ts b/apps/web/src/lib/queries/users.ts index 563141d2..358a8585 100644 --- a/apps/web/src/lib/queries/users.ts +++ b/apps/web/src/lib/queries/users.ts @@ -2,13 +2,16 @@ import c from "config"; import { count, db, eq, sum } from "db"; import { checkins, data, events, users } from "db/schema"; import { getCurrentSemester } from "./semesters"; +import { ADMIN_ROLES } from "../constants"; + +type UserRoles = typeof users.$inferSelect.role[] export const getAdminUser = async (clerkId: string) => { return db.query.users.findFirst({ where: (users, { eq, and, inArray }) => and( eq(users.clerkID, clerkId), - inArray(users.role, ["admin", "super_admin"]), + inArray(users.role, ADMIN_ROLES as UserRoles), ), }); }; diff --git a/apps/web/src/middleware.ts b/apps/web/src/middleware.ts index cc6ace05..1dd36797 100644 --- a/apps/web/src/middleware.ts +++ b/apps/web/src/middleware.ts @@ -1,6 +1,7 @@ import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server"; import { getAdminUser } from "./lib/queries/users"; import { NextResponse } from "next/server"; + const isProtectedRoute = createRouteMatcher([ "/dash(.*)", "/admin(.*)", @@ -8,12 +9,12 @@ const isProtectedRoute = createRouteMatcher([ ]); const isAdminAPIRoute = createRouteMatcher(["/api/admin(.*)"]); -// come back and check if this is valid export default clerkMiddleware(async (auth, req) => { - const { userId } = await auth(); - - if (isProtectedRoute(req)) { - await auth.protect(); + const { userId, redirectToSignIn } = await auth(); + if (isProtectedRoute(req) && !userId) { + redirectToSignIn({ + returnBackUrl: req.nextUrl.toString(), + }); } // protect admin api routes From 4b5e704de336dbead9354e205ff4d6ec93eafaf5 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Wed, 16 Jul 2025 23:41:16 -0600 Subject: [PATCH 2/5] formatter --- apps/web/src/app/admin/layout.tsx | 2 +- apps/web/src/app/onboarding/layout.tsx | 1 - apps/web/src/lib/constants/index.ts | 2 +- apps/web/src/lib/queries/users.ts | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/web/src/app/admin/layout.tsx b/apps/web/src/app/admin/layout.tsx index 1a2ee491..eb215a1c 100644 --- a/apps/web/src/app/admin/layout.tsx +++ b/apps/web/src/app/admin/layout.tsx @@ -25,7 +25,7 @@ export default async function AdminLayout({ where: eq(users.clerkID, userId), }); - if (!user){ + if (!user) { return redirect("/onboarding"); } diff --git a/apps/web/src/app/onboarding/layout.tsx b/apps/web/src/app/onboarding/layout.tsx index 2a91d9b2..bf769ace 100644 --- a/apps/web/src/app/onboarding/layout.tsx +++ b/apps/web/src/app/onboarding/layout.tsx @@ -10,7 +10,6 @@ export default async function OnboardingLayout({ }: { children: React.ReactNode; }) { - const { userId } = await auth(); if (!userId) return redirect("/sign-up"); diff --git a/apps/web/src/lib/constants/index.ts b/apps/web/src/lib/constants/index.ts index d9861576..89207e10 100644 --- a/apps/web/src/lib/constants/index.ts +++ b/apps/web/src/lib/constants/index.ts @@ -4,4 +4,4 @@ export const UNIQUE_KEY_CONSTRAINT_VIOLATION_CODE = "23505"; export const LOWER_ALPHANUM_CUSTOM_ALPHABET = "1234567890abcdefghijklmnopqrstuvwxyz"; -export const ADMIN_ROLES:Array = ["admin", "super_admin"] as const; +export const ADMIN_ROLES: Array = ["admin", "super_admin"] as const; diff --git a/apps/web/src/lib/queries/users.ts b/apps/web/src/lib/queries/users.ts index 358a8585..6311dd89 100644 --- a/apps/web/src/lib/queries/users.ts +++ b/apps/web/src/lib/queries/users.ts @@ -4,7 +4,7 @@ import { checkins, data, events, users } from "db/schema"; import { getCurrentSemester } from "./semesters"; import { ADMIN_ROLES } from "../constants"; -type UserRoles = typeof users.$inferSelect.role[] +type UserRoles = (typeof users.$inferSelect.role)[]; export const getAdminUser = async (clerkId: string) => { return db.query.users.findFirst({ From 1782dd0d2f1091103889a0d552e0b8f43c495e2d Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Sun, 20 Jul 2025 18:17:37 -0600 Subject: [PATCH 3/5] allows users to switch accounts when onboarding --- apps/web/src/app/page.tsx | 6 +- apps/web/src/components/shared/navbar.tsx | 69 +++++++++++-------- .../src/components/shared/profile-button.tsx | 2 +- 3 files changed, 46 insertions(+), 31 deletions(-) diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index 347e349a..8e680f2d 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -1,4 +1,5 @@ import Navbar from "@/components/shared/navbar"; +import Link from "next/link"; export default function Home() { return ( // bg-[var(--my-var,var(--my-background,pink))] @@ -6,8 +7,11 @@ export default function Home() {
-
+

ClubKit

+ +

Find Events →

+
); diff --git a/apps/web/src/components/shared/navbar.tsx b/apps/web/src/components/shared/navbar.tsx index b131596e..e31fe6ca 100644 --- a/apps/web/src/components/shared/navbar.tsx +++ b/apps/web/src/components/shared/navbar.tsx @@ -17,6 +17,7 @@ import { import { ADMIN_ROLES } from "@/lib/constants"; import c from "config"; import { Menu } from "lucide-react"; +import { SignOutButton } from "@clerk/nextjs"; type NavbarProps = { siteRegion?: string; @@ -33,8 +34,8 @@ export default async function Navbar({ siteRegion, showBorder }: NavbarProps) { with: { data: true }, }) : null; - - const registrationComplete = user != null; + const hasSignedIn = userId != null; + const hasCompletedRegistration = user != null; return (
- {user ? ( + {hasSignedIn ? ( <> - - - - {ADMIN_ROLES.includes(user.role) && ( - - - + + { + hasCompletedRegistration && ( + ADMIN_ROLES.includes(user.role) && ( + + + + ) )} + + + + + + ) : ( <> @@ -122,9 +134,9 @@ export default async function Navbar({ siteRegion, showBorder }: NavbarProps) { - {user ? ( + {hasSignedIn ? ( <> - {registrationComplete && ( + {hasCompletedRegistration && ( - - - - {ADMIN_ROLES.includes(user.role) && ( + + { hasCompletedRegistration && ADMIN_ROLES.includes(user.role) && ( diff --git a/apps/web/src/components/shared/profile-button.tsx b/apps/web/src/components/shared/profile-button.tsx index 36b49318..c409e87e 100644 --- a/apps/web/src/components/shared/profile-button.tsx +++ b/apps/web/src/components/shared/profile-button.tsx @@ -56,7 +56,7 @@ export default async function ProfileButton({ - Complete Registration + Complete Registration / Connect Account Date: Sun, 20 Jul 2025 18:17:48 -0600 Subject: [PATCH 4/5] formatter --- apps/web/src/components/shared/navbar.tsx | 52 +++++++++++------------ 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/apps/web/src/components/shared/navbar.tsx b/apps/web/src/components/shared/navbar.tsx index e31fe6ca..300a8099 100644 --- a/apps/web/src/components/shared/navbar.tsx +++ b/apps/web/src/components/shared/navbar.tsx @@ -69,7 +69,9 @@ export default async function Navbar({ siteRegion, showBorder }: NavbarProps) { <> - - ) - )} + + {hasCompletedRegistration && + ADMIN_ROLES.includes(user.role) && ( + + + + )} - - - - - ) : ( <> @@ -156,19 +151,22 @@ export default async function Navbar({ siteRegion, showBorder }: NavbarProps) { ? "ghost" : "default" } - className="whitespace-normal p-4 h-12" + className="h-12 whitespace-normal p-4" > {hasCompletedRegistration ? "Dashboard" : "Complete Registration / Connect Account"} - - { hasCompletedRegistration && ADMIN_ROLES.includes(user.role) && ( - - - - )} + + {hasCompletedRegistration && + ADMIN_ROLES.includes(user.role) && ( + + + + )}
Date: Thu, 24 Jul 2025 21:21:19 -0600 Subject: [PATCH 5/5] removes '/complete registration' --- apps/web/src/components/shared/navbar.tsx | 4 ++-- apps/web/src/components/shared/profile-button.tsx | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/web/src/components/shared/navbar.tsx b/apps/web/src/components/shared/navbar.tsx index 300a8099..272fdeba 100644 --- a/apps/web/src/components/shared/navbar.tsx +++ b/apps/web/src/components/shared/navbar.tsx @@ -83,7 +83,7 @@ export default async function Navbar({ siteRegion, showBorder }: NavbarProps) { > {hasCompletedRegistration ? "Dashboard" - : "Complete Registration / Connect Account"} + : "Complete Registration"} @@ -155,7 +155,7 @@ export default async function Navbar({ siteRegion, showBorder }: NavbarProps) { > {hasCompletedRegistration ? "Dashboard" - : "Complete Registration / Connect Account"} + : "Complete Registration"} diff --git a/apps/web/src/components/shared/profile-button.tsx b/apps/web/src/components/shared/profile-button.tsx index c409e87e..491a6eda 100644 --- a/apps/web/src/components/shared/profile-button.tsx +++ b/apps/web/src/components/shared/profile-button.tsx @@ -5,7 +5,6 @@ import { DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, - DropdownMenuShortcut, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; @@ -56,7 +55,7 @@ export default async function ProfileButton({ - Complete Registration / Connect Account + Complete Registration - Report a Bug