diff --git a/apps/admin/app/layout.tsx b/apps/admin/app/layout.tsx index 7a807d4..8521291 100644 --- a/apps/admin/app/layout.tsx +++ b/apps/admin/app/layout.tsx @@ -1,16 +1,107 @@ -import { Geist, Geist_Mono } from "next/font/google" +import localFont from "next/font/local" import "@workspace/ui/globals.css" import { Providers } from "@/components/providers" -const fontSans = Geist({ - subsets: ["latin"], +const firaSans = localFont({ + src: [ + { + path: "../fonts/Fira-sans/FiraSans-Thin.ttf", + weight: "100", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-ThinItalic.ttf", + weight: "100", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-ExtraLight.ttf", + weight: "200", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-ExtraLightItalic.ttf", + weight: "200", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-Light.ttf", + weight: "300", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-LightItalic.ttf", + weight: "300", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-Regular.ttf", + weight: "400", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-Italic.ttf", + weight: "400", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-Medium.ttf", + weight: "500", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-MediumItalic.ttf", + weight: "500", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-SemiBold.ttf", + weight: "600", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-SemiBoldItalic.ttf", + weight: "600", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-Bold.ttf", + weight: "700", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-BoldItalic.ttf", + weight: "700", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-ExtraBold.ttf", + weight: "800", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-ExtraBoldItalic.ttf", + weight: "800", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-Black.ttf", + weight: "900", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-BlackItalic.ttf", + weight: "900", + style: "italic", + }, + ], variable: "--font-sans", }) -const fontMono = Geist_Mono({ - subsets: ["latin"], - variable: "--font-mono", +const marcellus = localFont({ + src: "../fonts/Marcellus/Marcellus-Regular.ttf", + variable: "--font-marcellus", }) export default function RootLayout({ @@ -21,7 +112,7 @@ export default function RootLayout({ return ( {children} diff --git a/apps/admin/app/page.tsx b/apps/admin/app/page.tsx index d338f0c..65031f5 100644 --- a/apps/admin/app/page.tsx +++ b/apps/admin/app/page.tsx @@ -1,11 +1,11 @@ import Login from "@/components/login"; import Studs from "@/components/studs"; -import { db, students } from "@workspace/db"; -import { signIn, signOut } from "@workspace/auth"; +import { db, admins } from "@workspace/db"; +import { auth, signIn, signOut } from "@workspace/auth"; async function getStudents() { "use server"; - const s = await db.select().from(students); + const s = await db.select().from(admins); console.log(s); } @@ -20,11 +20,12 @@ async function logOut() { } export default async function Page() { + const session = await auth() return (

Hello admins

- + {!session?.user && }
diff --git a/apps/admin/fonts/Fira-sans/FiraSans-Black.ttf b/apps/admin/fonts/Fira-sans/FiraSans-Black.ttf new file mode 100644 index 0000000..3087a31 Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-Black.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-BlackItalic.ttf b/apps/admin/fonts/Fira-sans/FiraSans-BlackItalic.ttf new file mode 100644 index 0000000..9a9ef5e Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-BlackItalic.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-Bold.ttf b/apps/admin/fonts/Fira-sans/FiraSans-Bold.ttf new file mode 100644 index 0000000..0fb896a Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-Bold.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-BoldItalic.ttf b/apps/admin/fonts/Fira-sans/FiraSans-BoldItalic.ttf new file mode 100644 index 0000000..e7e936f Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-BoldItalic.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-ExtraBold.ttf b/apps/admin/fonts/Fira-sans/FiraSans-ExtraBold.ttf new file mode 100644 index 0000000..4b29d6f Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-ExtraBold.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-ExtraBoldItalic.ttf b/apps/admin/fonts/Fira-sans/FiraSans-ExtraBoldItalic.ttf new file mode 100644 index 0000000..de3b83b Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-ExtraBoldItalic.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-ExtraLight.ttf b/apps/admin/fonts/Fira-sans/FiraSans-ExtraLight.ttf new file mode 100644 index 0000000..e5755da Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-ExtraLight.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-ExtraLightItalic.ttf b/apps/admin/fonts/Fira-sans/FiraSans-ExtraLightItalic.ttf new file mode 100644 index 0000000..890524e Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-ExtraLightItalic.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-Italic.ttf b/apps/admin/fonts/Fira-sans/FiraSans-Italic.ttf new file mode 100644 index 0000000..36efca2 Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-Italic.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-Light.ttf b/apps/admin/fonts/Fira-sans/FiraSans-Light.ttf new file mode 100644 index 0000000..fac4edf Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-Light.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-LightItalic.ttf b/apps/admin/fonts/Fira-sans/FiraSans-LightItalic.ttf new file mode 100644 index 0000000..1daa0bc Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-LightItalic.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-Medium.ttf b/apps/admin/fonts/Fira-sans/FiraSans-Medium.ttf new file mode 100644 index 0000000..eeb8f8f Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-Medium.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-MediumItalic.ttf b/apps/admin/fonts/Fira-sans/FiraSans-MediumItalic.ttf new file mode 100644 index 0000000..328b53b Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-MediumItalic.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-Regular.ttf b/apps/admin/fonts/Fira-sans/FiraSans-Regular.ttf new file mode 100644 index 0000000..c4cfa59 Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-Regular.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-SemiBold.ttf b/apps/admin/fonts/Fira-sans/FiraSans-SemiBold.ttf new file mode 100644 index 0000000..954a2ca Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-SemiBold.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-SemiBoldItalic.ttf b/apps/admin/fonts/Fira-sans/FiraSans-SemiBoldItalic.ttf new file mode 100644 index 0000000..55e812c Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-SemiBoldItalic.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-Thin.ttf b/apps/admin/fonts/Fira-sans/FiraSans-Thin.ttf new file mode 100644 index 0000000..8cb4bad Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-Thin.ttf differ diff --git a/apps/admin/fonts/Fira-sans/FiraSans-ThinItalic.ttf b/apps/admin/fonts/Fira-sans/FiraSans-ThinItalic.ttf new file mode 100644 index 0000000..f2dbf59 Binary files /dev/null and b/apps/admin/fonts/Fira-sans/FiraSans-ThinItalic.ttf differ diff --git a/apps/admin/fonts/Marcellus/Marcellus-Regular.ttf b/apps/admin/fonts/Marcellus/Marcellus-Regular.ttf new file mode 100644 index 0000000..1be0d9d Binary files /dev/null and b/apps/admin/fonts/Marcellus/Marcellus-Regular.ttf differ diff --git a/apps/admin/middleware.ts b/apps/admin/middleware.ts index b876a27..d084074 100644 --- a/apps/admin/middleware.ts +++ b/apps/admin/middleware.ts @@ -1 +1,18 @@ -export { auth as middleware } from "@workspace/auth"; +import { auth } from "@workspace/auth"; +import { NextResponse } from 'next/server'; + +export default auth((req: any) => { + // If the user is unauthenticated or an admin, allow the request. + if (!req.auth || req.auth.user?.role === "ADMIN") { + return NextResponse.next(); + } + + // Otherwise, redirect to the student app. + const studentUrl = process.env.STUDENT_URL ?? "http://localhost:3000" + + return NextResponse.redirect(new URL(studentUrl, req.url)); +}) as any; + +export const config = { + matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"], +} \ No newline at end of file diff --git a/apps/admin/next-auth.d.ts b/apps/admin/next-auth.d.ts new file mode 100644 index 0000000..0eeed9b --- /dev/null +++ b/apps/admin/next-auth.d.ts @@ -0,0 +1,19 @@ +import "next-auth"; + +declare module "next-auth" { + interface Session { + user: { + role?: "ADMIN" | "USER"; + adminId?: number; + studentId?: number; + [key: string]: any; + }; + } +} +declare module "next-auth/jwt" { + interface JWT { + role?: "ADMIN" | "USER"; + adminId?: number; + studentId?: number; + } +} \ No newline at end of file diff --git a/apps/student/app/api/auth/[...nextauth]/route.ts b/apps/student/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 0000000..ad9858b --- /dev/null +++ b/apps/student/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,2 @@ +import { handlers } from "@workspace/auth"; +export const { GET, POST } = handlers; diff --git a/apps/student/app/layout.tsx b/apps/student/app/layout.tsx index 7a807d4..8521291 100644 --- a/apps/student/app/layout.tsx +++ b/apps/student/app/layout.tsx @@ -1,16 +1,107 @@ -import { Geist, Geist_Mono } from "next/font/google" +import localFont from "next/font/local" import "@workspace/ui/globals.css" import { Providers } from "@/components/providers" -const fontSans = Geist({ - subsets: ["latin"], +const firaSans = localFont({ + src: [ + { + path: "../fonts/Fira-sans/FiraSans-Thin.ttf", + weight: "100", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-ThinItalic.ttf", + weight: "100", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-ExtraLight.ttf", + weight: "200", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-ExtraLightItalic.ttf", + weight: "200", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-Light.ttf", + weight: "300", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-LightItalic.ttf", + weight: "300", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-Regular.ttf", + weight: "400", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-Italic.ttf", + weight: "400", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-Medium.ttf", + weight: "500", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-MediumItalic.ttf", + weight: "500", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-SemiBold.ttf", + weight: "600", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-SemiBoldItalic.ttf", + weight: "600", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-Bold.ttf", + weight: "700", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-BoldItalic.ttf", + weight: "700", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-ExtraBold.ttf", + weight: "800", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-ExtraBoldItalic.ttf", + weight: "800", + style: "italic", + }, + { + path: "../fonts/Fira-sans/FiraSans-Black.ttf", + weight: "900", + style: "normal", + }, + { + path: "../fonts/Fira-sans/FiraSans-BlackItalic.ttf", + weight: "900", + style: "italic", + }, + ], variable: "--font-sans", }) -const fontMono = Geist_Mono({ - subsets: ["latin"], - variable: "--font-mono", +const marcellus = localFont({ + src: "../fonts/Marcellus/Marcellus-Regular.ttf", + variable: "--font-marcellus", }) export default function RootLayout({ @@ -21,7 +112,7 @@ export default function RootLayout({ return ( {children} diff --git a/apps/student/app/page.tsx b/apps/student/app/page.tsx index 1018ac5..e09ba3f 100644 --- a/apps/student/app/page.tsx +++ b/apps/student/app/page.tsx @@ -1,11 +1,32 @@ -import { Button } from "@workspace/ui/components/button"; +import Login from "@/components/login"; +import Studs from "@/components/studs"; +import { db, admins } from "@workspace/db"; +import { auth, signIn, signOut } from "@workspace/auth"; -export default function Page() { +async function getStudents() { + "use server"; + const s = await db.select().from(admins); + console.log(s); +} + +async function logIn() { + "use server"; + await signIn("google"); +} + +async function logOut() { + "use server"; + await signOut(); +} + +export default async function Page() { + const session = await auth() return (

Hello students

- + {!session?.user && } +
); diff --git a/apps/student/components/login.tsx b/apps/student/components/login.tsx new file mode 100644 index 0000000..7b42ac7 --- /dev/null +++ b/apps/student/components/login.tsx @@ -0,0 +1,25 @@ +"use client"; +import { signIn } from "@workspace/auth"; +import { Button } from "@workspace/ui/components/button"; + +export default function Login({logIn}: {logIn: () => Promise}) { + return ( +
+ +
+ ); +} diff --git a/apps/student/components/studs.tsx b/apps/student/components/studs.tsx new file mode 100644 index 0000000..7e49d2a --- /dev/null +++ b/apps/student/components/studs.tsx @@ -0,0 +1,19 @@ +import { Button } from "@workspace/ui/components/button"; +import { auth } from "@workspace/auth"; + +export default async function Studs({ + action, + logOut, +}: { + action: () => void; + logOut: () => void; +}) { + const session = await auth(); + if (!session?.user) return null; + return ( +
+ + +
+ ); +} diff --git a/apps/student/fonts/Fira-sans/FiraSans-Black.ttf b/apps/student/fonts/Fira-sans/FiraSans-Black.ttf new file mode 100644 index 0000000..3087a31 Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-Black.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-BlackItalic.ttf b/apps/student/fonts/Fira-sans/FiraSans-BlackItalic.ttf new file mode 100644 index 0000000..9a9ef5e Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-BlackItalic.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-Bold.ttf b/apps/student/fonts/Fira-sans/FiraSans-Bold.ttf new file mode 100644 index 0000000..0fb896a Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-Bold.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-BoldItalic.ttf b/apps/student/fonts/Fira-sans/FiraSans-BoldItalic.ttf new file mode 100644 index 0000000..e7e936f Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-BoldItalic.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-ExtraBold.ttf b/apps/student/fonts/Fira-sans/FiraSans-ExtraBold.ttf new file mode 100644 index 0000000..4b29d6f Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-ExtraBold.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-ExtraBoldItalic.ttf b/apps/student/fonts/Fira-sans/FiraSans-ExtraBoldItalic.ttf new file mode 100644 index 0000000..de3b83b Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-ExtraBoldItalic.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-ExtraLight.ttf b/apps/student/fonts/Fira-sans/FiraSans-ExtraLight.ttf new file mode 100644 index 0000000..e5755da Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-ExtraLight.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-ExtraLightItalic.ttf b/apps/student/fonts/Fira-sans/FiraSans-ExtraLightItalic.ttf new file mode 100644 index 0000000..890524e Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-ExtraLightItalic.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-Italic.ttf b/apps/student/fonts/Fira-sans/FiraSans-Italic.ttf new file mode 100644 index 0000000..36efca2 Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-Italic.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-Light.ttf b/apps/student/fonts/Fira-sans/FiraSans-Light.ttf new file mode 100644 index 0000000..fac4edf Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-Light.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-LightItalic.ttf b/apps/student/fonts/Fira-sans/FiraSans-LightItalic.ttf new file mode 100644 index 0000000..1daa0bc Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-LightItalic.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-Medium.ttf b/apps/student/fonts/Fira-sans/FiraSans-Medium.ttf new file mode 100644 index 0000000..eeb8f8f Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-Medium.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-MediumItalic.ttf b/apps/student/fonts/Fira-sans/FiraSans-MediumItalic.ttf new file mode 100644 index 0000000..328b53b Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-MediumItalic.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-Regular.ttf b/apps/student/fonts/Fira-sans/FiraSans-Regular.ttf new file mode 100644 index 0000000..c4cfa59 Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-Regular.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-SemiBold.ttf b/apps/student/fonts/Fira-sans/FiraSans-SemiBold.ttf new file mode 100644 index 0000000..954a2ca Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-SemiBold.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-SemiBoldItalic.ttf b/apps/student/fonts/Fira-sans/FiraSans-SemiBoldItalic.ttf new file mode 100644 index 0000000..55e812c Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-SemiBoldItalic.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-Thin.ttf b/apps/student/fonts/Fira-sans/FiraSans-Thin.ttf new file mode 100644 index 0000000..8cb4bad Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-Thin.ttf differ diff --git a/apps/student/fonts/Fira-sans/FiraSans-ThinItalic.ttf b/apps/student/fonts/Fira-sans/FiraSans-ThinItalic.ttf new file mode 100644 index 0000000..f2dbf59 Binary files /dev/null and b/apps/student/fonts/Fira-sans/FiraSans-ThinItalic.ttf differ diff --git a/apps/student/fonts/Marcellus/Marcellus-Regular.ttf b/apps/student/fonts/Marcellus/Marcellus-Regular.ttf new file mode 100644 index 0000000..1be0d9d Binary files /dev/null and b/apps/student/fonts/Marcellus/Marcellus-Regular.ttf differ diff --git a/apps/student/middleware.ts b/apps/student/middleware.ts new file mode 100644 index 0000000..09044e7 --- /dev/null +++ b/apps/student/middleware.ts @@ -0,0 +1,18 @@ +import { auth } from "@workspace/auth"; +import { NextResponse } from 'next/server'; + +export default auth((req: any) => { + // If the user is unauthenticated or a student, allow the request. + if (!req.auth || req.auth.user?.role === "USER") { + return NextResponse.next(); + } + + // Otherwise, redirect to the admin app. + const adminURL = process.env.ADMIN_URL ?? "http://localhost:3001" + + return NextResponse.redirect(new URL(adminURL, req.url)); +}) as any; + +export const config = { + matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"], +} \ No newline at end of file diff --git a/apps/student/next-auth.d.ts b/apps/student/next-auth.d.ts new file mode 100644 index 0000000..8ac7c89 --- /dev/null +++ b/apps/student/next-auth.d.ts @@ -0,0 +1,20 @@ +import "next-auth"; + +declare module "next-auth" { + interface Session { + user: { + role?: "ADMIN" | "USER"; + adminId?: number; + studentId?: number; + [key: string]: any; + }; + } +} + +declare module "next-auth/jwt" { + interface JWT { + role?: "ADMIN" | "USER"; + adminId?: number; + studentId?: number; + } +} \ No newline at end of file diff --git a/packages/auth/index.ts b/packages/auth/index.ts index 8ab8f2c..b4546e6 100644 --- a/packages/auth/index.ts +++ b/packages/auth/index.ts @@ -1,9 +1,65 @@ import NextAuth, { type NextAuthConfig } from "next-auth"; import Google from "next-auth/providers/google"; +import { db, admins, students } from "@workspace/db"; +import { eq } from "drizzle-orm"; const authConfig: NextAuthConfig = { providers: [Google], - callbacks: {}, + callbacks: { + async jwt({ token, account, user, profile }) { + // Only check DB on first sign in + if (account && user && user.email) { + const admin = await db + .select() + .from(admins) + .where(eq(admins.email, user.email)) + .limit(1); + if (admin.length > 0 && admin[0]) { + token.role = "ADMIN"; + token.adminId = admin[0].id; + } else { + token.role = "USER"; + const student = await db + .select() + .from(students) + .where(eq(students.email, user.email)) + .limit(1); + if (student.length > 0 && student[0]) { + token.studentId = student[0].id; + } else { + const nameParts = user.name?.split(" ") ?? []; + const firstName = nameParts[0] || ""; + const lastName = nameParts.slice(1).join(" ") || ""; + const newStudent = await db + .insert(students) + .values({ + email: user.email, + firstName: firstName, + lastName: lastName, + profilePicture: user.image, + }) + .returning({ id: students.id }); + if (newStudent[0]) { + token.studentId = newStudent[0].id; + } + } + } + } + return token; + }, + async session({ session, token }) { + if (token?.role) { + session.user.role = token.role as "ADMIN" | "USER"; + } + if (token?.adminId) { + session.user.adminId = token.adminId as number; + } + if (token?.studentId) { + session.user.studentId = token.studentId as number; + } + return session; + }, + }, }; const nextAuth = NextAuth(authConfig); diff --git a/packages/auth/package.json b/packages/auth/package.json index 4f2056e..62740d0 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -12,7 +12,9 @@ "license": "ISC", "packageManager": "pnpm@10.4.1", "dependencies": { - "next-auth": "5.0.0-beta.28" + "next-auth": "5.0.0-beta.28", + "@workspace/db": "workspace:*", + "drizzle-orm": "^0.44.2" }, "devDependencies": { "dotenv": "^16.5.0" diff --git a/packages/auth/types.d.ts b/packages/auth/types.d.ts new file mode 100644 index 0000000..b4ceb09 --- /dev/null +++ b/packages/auth/types.d.ts @@ -0,0 +1,20 @@ +import "next-auth"; +import "next-auth/jwt"; + +declare module "next-auth" { + interface Session { + user: { + role?: "ADMIN" | "USER"; + adminId?: number; + studentId?: number; + [key: string]: any; + }; + } +} +declare module "next-auth/jwt" { + interface JWT { + role?: "ADMIN" | "USER"; + adminId?: number; + studentId?: number; + } +} \ No newline at end of file diff --git a/packages/ui/src/components/button.tsx b/packages/ui/src/components/button.tsx index e0e289d..0240342 100644 --- a/packages/ui/src/components/button.tsx +++ b/packages/ui/src/components/button.tsx @@ -10,11 +10,11 @@ const buttonVariants = cva( variants: { variant: { default: - "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", + "bg-primary text-primary-foreground shadow-xs shadow-foreground/20 hover:bg-primary/90", destructive: - "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40", + "bg-destructive text-destructive-foreground shadow-xs shadow-foreground/20 hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40", outline: - "bg-background border border-border text-foreground shadow transition-all duration-300 ease-out group relative overflow-hidden hover:bg-muted hover:border-muted-foreground hover:shadow-lg hover:shadow-primary/20 hover:scale-102 active:scale-98 active:shadow-md focus:ring-2 focus:ring-primary focus:ring-offset-2", + "bg-background border border-border text-foreground shadow shadow-foreground/20 transition-all duration-300 ease-out group relative overflow-hidden hover:bg-muted hover:border-muted-foreground hover:shadow-lg hover:shadow-primary/20 hover:scale-103 active:scale-98 active:shadow-md focus:ring-2 focus:ring-primary focus:ring-offset-2", secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", diff --git a/packages/ui/src/styles/globals.css b/packages/ui/src/styles/globals.css index a5c6ce3..7f56d18 100644 --- a/packages/ui/src/styles/globals.css +++ b/packages/ui/src/styles/globals.css @@ -5,77 +5,82 @@ @import "tw-animate-css"; +@theme { + --font-sans: "var(--font-sans)"; + --font-marcellus: "var(--font-marcellus)"; +} + @custom-variant dark (&:is(.dark *)); :root { - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); - --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); + --background: oklch(0.9889 0.004 286.33); + --foreground: oklch(0.2442 0.006 0.59); + --card: oklch(0.97 0.004 286.33); + --card-foreground: oklch(0.2442 0.006 0.59); --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.97 0 0); - --secondary-foreground: oklch(0.205 0 0); - --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); - --accent: oklch(0.97 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --destructive-foreground: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); - --input: oklch(0.922 0 0); - --ring: oklch(0.708 0 0); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); + --popover-foreground: oklch(0.2442 0.006 0.59); + --primary: oklch(0.5044 0.184 22.51); + --primary-foreground: oklch(0.9889 0.004 286.33); + --secondary: oklch(0.4605 0.005 271.31); + --secondary-foreground: oklch(0.9889 0.004 286.33); + --muted: oklch(0.92 0.003 286.33); + --muted-foreground: oklch(0.44 0.004 286.33); + --accent: oklch(0.6034 0.234 27.23); + --accent-foreground: oklch(0.9889 0.004 286.33); + --destructive: oklch(0.55 0.18 27.23); + --destructive-foreground: oklch(0.9889 0.004 286.33); + --border: oklch(0.88 0.003 286.33); + --input: oklch(0.97 0.004 286.33); + --ring: oklch(0.6034 0.234 27.23); + --chart-1: oklch(0.5044 0.184 22.51); + --chart-2: oklch(0.6034 0.234 27.23); + --chart-3: oklch(0.4605 0.005 271.31); + --chart-4: oklch(0.7 0.15 120); + --chart-5: oklch(0.7 0.15 300); --radius: 0.625rem; - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.97 0 0); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.708 0 0); + --sidebar: oklch(0.97 0.004 286.33); + --sidebar-foreground: oklch(0.2442 0.006 0.59); + --sidebar-primary: oklch(0.5044 0.184 22.51); + --sidebar-primary-foreground: oklch(0.9889 0.004 286.33); + --sidebar-accent: oklch(0.6034 0.234 27.23); + --sidebar-accent-foreground: oklch(0.9889 0.004 286.33); + --sidebar-border: oklch(0.88 0.003 286.33); + --sidebar-ring: oklch(0.6034 0.234 27.23); } .dark { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.145 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.145 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.985 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.269 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.396 0.141 25.723); - --destructive-foreground: oklch(0.637 0.237 25.331); - --border: oklch(0.269 0 0); - --input: oklch(0.269 0 0); - --ring: oklch(0.556 0 0); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(0.269 0 0); - --sidebar-ring: oklch(0.439 0 0); + --background: oklch(0.18 0.01 286.33); + --foreground: oklch(0.9889 0.004 286.33); + --card: oklch(0.22 0.01 286.33); + --card-foreground: oklch(0.9889 0.004 286.33); + --popover: oklch(0.22 0.01 286.33); + --popover-foreground: oklch(0.9889 0.004 286.33); + --primary: oklch(0.7044 0.184 22.51); + --primary-foreground: oklch(0.18 0.01 286.33); + --secondary: oklch(0.36 0.005 271.31); + --secondary-foreground: oklch(0.9889 0.004 286.33); + --muted: oklch(0.25 0.01 286.33); + --muted-foreground: oklch(0.7 0.01 286.33); + --accent: oklch(0.8034 0.234 27.23); + --accent-foreground: oklch(0.18 0.01 286.33); + --destructive: oklch(0.65 0.18 27.23); + --destructive-foreground: oklch(0.18 0.01 286.33); + --border: oklch(0.25 0.01 286.33); + --input: oklch(0.22 0.01 286.33); + --ring: oklch(0.8034 0.234 27.23); + --chart-1: oklch(0.7044 0.184 22.51); + --chart-2: oklch(0.8034 0.234 27.23); + --chart-3: oklch(0.36 0.005 271.31); + --chart-4: oklch(0.7 0.15 120); + --chart-5: oklch(0.7 0.15 300); + --sidebar: oklch(0.22 0.01 286.33); + --sidebar-foreground: oklch(0.9889 0.004 286.33); + --sidebar-primary: oklch(0.7044 0.184 22.51); + --sidebar-primary-foreground: oklch(0.18 0.01 286.33); + --sidebar-accent: oklch(0.8034 0.234 27.23); + --sidebar-accent-foreground: oklch(0.18 0.01 286.33); + --sidebar-border: oklch(0.25 0.01 286.33); + --sidebar-ring: oklch(0.8034 0.234 27.23); } @theme inline { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ff0cf5d..df903bd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -130,6 +130,12 @@ importers: packages/auth: dependencies: + '@workspace/db': + specifier: workspace:* + version: link:../db + drizzle-orm: + specifier: ^0.44.2 + version: 0.44.2(@neondatabase/serverless@1.0.1)(@types/pg@8.15.4) next-auth: specifier: 5.0.0-beta.28 version: 5.0.0-beta.28(next@15.3.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)