diff --git a/src/app/page.tsx b/src/app/page.tsx
index bda4d65..20f354b 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -7,19 +7,31 @@ import { LandingFeatures } from "@/components/landing/LandingFeatures"
import { LandingFooter } from "@/components/landing/LandingFooter"
import { MobileHero } from "@/components/landing/mobile/MobileHero"
import { MobileFeatures } from "@/components/landing/mobile/MobileFeatures"
+import { useTheme } from "@/components/ThemeProvider"
+import { cn } from "@/lib/utils"
import dynamic from "next/dynamic"
-const LandingSolutions = dynamic(() => import("@/components/landing/LandingSolutions").then(mod => mod.LandingSolutions), {
- ssr: true,
- loading: () =>
-})
+const LandingSolutions = dynamic(
+ () => import("@/components/landing/LandingSolutions").then((mod) => mod.LandingSolutions),
+ {
+ ssr: true,
+ loading: () =>
,
+ }
+)
export default function HomePage() {
const isMobile = useMediaQuery("(max-width: 768px)")
+ const { theme } = useTheme()
+ const isLight = theme === "light"
return (
-
+
{isMobile ? (
diff --git a/src/app/supplier/layout.tsx b/src/app/supplier/layout.tsx
index b6b21e1..865ea36 100644
--- a/src/app/supplier/layout.tsx
+++ b/src/app/supplier/layout.tsx
@@ -20,7 +20,10 @@ export default async function SupplierLayout({
// Only allow SUPPLIER role to access supplier dashboard
if (session.user.role !== "SUPPLIER") {
- redirect("/dashboard")
+ if (session.user.role === "VENDOR") {
+ redirect("/login?error=WrongPortal&role=VENDOR")
+ }
+ redirect("/login?error=WrongRole")
}
// Ensure supplier profile exists, create if not
diff --git a/src/auth.ts b/src/auth.ts
index 422e607..338b269 100644
--- a/src/auth.ts
+++ b/src/auth.ts
@@ -3,6 +3,7 @@ import { PrismaAdapter } from "@auth/prisma-adapter"
import { prisma } from "@/lib/prisma"
import authConfig from "./auth.config"
import bcrypt from "bcryptjs"
+import { cookies } from "next/headers"
const ADMIN_EMAIL = process.env.ADMIN_EMAIL
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD
@@ -13,6 +14,45 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
trustHost: true, // Trust all hosts (needed for ngrok/proxies)
...authConfig,
callbacks: {
+ async signIn({ user, account }) {
+ // Allow non-email-based sign-in flows to proceed as usual
+ if (!user?.email) return true
+
+ // Never constrain the admin account via role toggle
+ if (user.email === ADMIN_EMAIL || user.role === "ADMIN") {
+ return true
+ }
+
+ // Read the desired role from the role toggle cookie set on the client
+ const cookieStore = await cookies()
+ const cookieRole = cookieStore.get("juno_login_role")?.value
+ const desiredRole =
+ cookieRole === "SUPPLIER" || cookieRole === "VENDOR" ? cookieRole : null
+
+ // If no role was explicitly chosen (e.g. legacy flows), fall back to existing behaviour
+ if (!desiredRole) {
+ return true
+ }
+
+ const existingUser = await prisma.user.findUnique({
+ where: { email: user.email },
+ select: { id: true, role: true },
+ })
+
+ // New user via OAuth: align their role with the chosen role on first sign-in
+ if (existingUser && existingUser.role !== desiredRole) {
+ // If the role already exists and differs, block sign-in with a clear error code
+ const url = new URL("/login", process.env.NEXTAUTH_URL || "http://localhost:3000")
+ url.searchParams.set("error", "SigninRoleMismatch")
+ url.searchParams.set("existingRole", existingUser.role || "VENDOR")
+ url.searchParams.set("desiredRole", desiredRole)
+ return url.toString()
+ }
+
+ // If the user record exists but has the default role and this is effectively a first login
+ // we keep the current behaviour and let onboarding/layouts route correctly.
+ return true
+ },
async jwt({ token, user }) {
if (user) {
token.id = user.id
@@ -89,6 +129,6 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
return user
},
- } as unknown as import("@auth/core/providers").Provider
- ]
+ } as unknown as import("@auth/core/providers").Provider,
+ ],
})